4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * platform independent module to manage nodes under frutree
34 * This file has the frutree initialization code:
35 * 1) parse the config file to create all locations in the chassis
36 * 2) probe each location to find fru and probe the fru recursively to
37 * create locations, port nodes
38 * 3) handle hotswap picl events (dr_ap_state_change, dr_req)
39 * - update the frutree
40 * - send out picl-state-change, picl-condition-events
41 * 4) Monitor the port nodes state and condition
45 #include <sys/param.h>
53 #include <sys/systeminfo.h>
54 #include <sys/types.h>
63 #include <libnvpair.h>
66 #include <config_admin.h>
67 #include <libdevinfo.h>
73 #include <picld_pluginutil.h>
75 #include <sys/sysevent/dr.h>
76 #include <ptree_impl.h>
77 #include "piclfrutree.h"
79 #pragma init(piclfrutree_register)
82 * following values are tunables that can be changed using
83 * environment variables
85 int frutree_debug
= NONE
; /* debug switch */
86 static int frutree_poll_timeout
= 5; /* polling time to monitor ports */
87 static int frutree_drwait_time
= 10; /* wait time for dr operation */
89 #define PICL_PROP_CONF_FILE "conf_name"
90 #define PICL_ADMINLOCK_DISABLED "disabled"
91 #define PICL_ADMINLOCK_ENABLED "enabled"
92 #define HASH_TABLE_SIZE (64)
94 #define HASH_INDEX(s, x) ((int)((x) & ((s) - 1)))
95 #define FRUDATA_PTR(_X) ((frutree_frunode_t *)(((hashdata_t *)(_X))->data))
96 #define LOCDATA_PTR(_X) ((frutree_locnode_t *)(((hashdata_t *)(_X))->data))
97 #define PORTDATA_PTR(_X) ((frutree_portnode_t *)(((hashdata_t *)(_X))->data))
99 /* Hash table structure */
100 typedef struct frutree_hash_elm
{
103 struct frutree_hash_elm
*nextp
;
108 frutree_hashelm_t
**tbl
;
112 frutree_datatype_t type
;
116 typedef int (*callback_t
)(picl_nodehdl_t
, void *);
119 CREATE_DEVICES_ENTRIES
,
128 HANDLE_LOCSTATE_CHANGE
,
138 typedef struct event_queue
{
139 frutree_dr_arg_t arg
;
140 struct event_queue
*next
;
144 char node_name
[PICL_PROPNAMELEN_MAX
];
145 picl_nodehdl_t retnodeh
;
146 } frutree_callback_data_t
;
148 typedef struct remove_list
{
149 picl_nodehdl_t nodeh
;
150 struct remove_list
*next
;
154 frutree_frunode_t
*frup
;
155 delete_list_t
*first
;
156 } frutree_init_callback_arg_t
;
158 boolean_t frutree_connects_initiated
= B_FALSE
;
159 static ev_queue_t
*queue_head
= NULL
;
160 static ev_queue_t
*queue_tail
= NULL
;
161 static pthread_mutex_t ev_mutex
;
162 static pthread_cond_t ev_cond
;
164 static frutree_hash_t node_hash_table
= {0, NULL
};
165 static picl_nodehdl_t chassish
= 0;
166 static picl_nodehdl_t frutreeh
= 0;
167 static picl_nodehdl_t rooth
= 0;
168 static picl_nodehdl_t platformh
= 0;
169 static boolean_t post_picl_events
= B_FALSE
;
170 static int piclevent_pending
= 0;
171 static char conf_file
[MAXPATHLEN
];
172 static char sys_name
[SYS_NMLN
];
174 static mutex_t piclevent_mutex
= DEFAULTMUTEX
;
175 static cond_t piclevent_completed_cv
= DEFAULTCV
;
176 static rwlock_t hash_lock
;
178 static pthread_t tid
;
179 static void *dr_thread(void *);
181 static pthread_t init_threadID
;
182 static pthread_t monitor_tid
;
183 static pthread_mutex_t monitor_mutex
= PTHREAD_MUTEX_INITIALIZER
;
184 static pthread_cond_t monitor_cv
= PTHREAD_COND_INITIALIZER
;
185 static int fini_called
= 0;
186 static void *monitor_node_status(void *);
187 static ev_queue_t
*remove_from_queue(void);
188 static picl_errno_t
handle_chassis_configure(frutree_frunode_t
*frup
);
193 static char *loc_state
[] = {
194 PICLEVENTARGVAL_UNKNOWN
,
195 PICLEVENTARGVAL_EMPTY
,
196 PICLEVENTARGVAL_CONNECTED
,
197 PICLEVENTARGVAL_DISCONNECTED
,
198 PICLEVENTARGVAL_CONNECTING
,
199 PICLEVENTARGVAL_DISCONNECTING
,
206 static char *fru_state
[] = {
207 PICLEVENTARGVAL_UNKNOWN
,
208 PICLEVENTARGVAL_CONFIGURED
,
209 PICLEVENTARGVAL_UNCONFIGURED
,
210 PICLEVENTARGVAL_CONFIGURING
,
211 PICLEVENTARGVAL_UNCONFIGURING
,
218 static char *fru_cond
[] = {
219 PICLEVENTARGVAL_UNKNOWN
,
220 PICLEVENTARGVAL_FAILED
,
221 PICLEVENTARGVAL_FAILING
,
223 PICLEVENTARGVAL_TESTING
,
230 static char *port_state
[] = {
231 PICLEVENTARGVAL_DOWN
,
233 PICLEVENTARGVAL_UNKNOWN
,
240 static char *port_cond
[] = {
242 PICLEVENTARGVAL_FAILING
,
243 PICLEVENTARGVAL_FAILED
,
244 PICLEVENTARGVAL_TESTING
,
245 PICLEVENTARGVAL_UNKNOWN
,
249 /* mapping between libcfgadm error codes to picl error codes */
250 static const int cfg2picl_errmap
[][2] = {
251 {CFGA_OK
, PICL_SUCCESS
},
252 {CFGA_NACK
, PICL_NORESPONSE
},
253 {CFGA_NOTSUPP
, PICL_NOTSUPPORTED
},
254 {CFGA_OPNOTSUPP
, PICL_NOTSUPPORTED
},
255 {CFGA_PRIV
, PICL_FAILURE
},
256 {CFGA_BUSY
, PICL_TREEBUSY
},
257 {CFGA_SYSTEM_BUSY
, PICL_TREEBUSY
},
258 {CFGA_DATA_ERROR
, PICL_FAILURE
},
259 {CFGA_LIB_ERROR
, PICL_FAILURE
},
260 {CFGA_NO_LIB
, PICL_FAILURE
},
261 {CFGA_INSUFFICENT_CONDITION
, PICL_FAILURE
},
262 {CFGA_INVAL
, PICL_INVALIDARG
},
263 {CFGA_ERROR
, PICL_FAILURE
},
264 {CFGA_APID_NOEXIST
, PICL_NODENOTFOUND
},
265 {CFGA_ATTR_INVAL
, PICL_INVALIDARG
}
268 /* local functions */
269 static void piclfrutree_register(void);
270 static void piclfrutree_init(void);
271 static void piclfrutree_fini(void);
272 static void * init_thread(void *);
273 static void frutree_wd_evhandler(const char *, const void *, size_t, void *);
274 static void frutree_dr_apstate_change_evhandler(const char *, const void *,
276 static void frutree_dr_req_evhandler(const char *, const void *,
278 static void frutree_cpu_state_change_evhandler(const char *, const void *,
280 static void init_queue(void);
281 static void frutree_get_env();
282 static picl_errno_t
hash_init(void);
283 static picl_errno_t
hash_remove_entry(picl_nodehdl_t
);
284 static picl_errno_t
hash_lookup_entry(picl_nodehdl_t
, void **);
285 static void hash_destroy();
286 static picl_errno_t
initialize_frutree();
287 static picl_errno_t
update_loc_state(frutree_locnode_t
*, boolean_t
*);
288 static int is_autoconfig_enabled(char *);
289 static picl_errno_t
do_action(picl_nodehdl_t
, int action
, void *);
290 static picl_errno_t
probe_fru(frutree_frunode_t
*, boolean_t
);
291 static picl_errno_t
handle_fru_unconfigure(frutree_frunode_t
*);
292 static picl_errno_t
update_loc_state(frutree_locnode_t
*, boolean_t
*);
293 static picl_errno_t
update_fru_state(frutree_frunode_t
*, boolean_t
*);
294 static picl_errno_t
update_port_state(frutree_portnode_t
*, boolean_t
);
295 static picl_errno_t
configure_fru(frutree_frunode_t
*, cfga_flags_t
);
296 static picl_errno_t
post_piclevent(const char *, char *, char *,
297 picl_nodehdl_t
, frutree_wait_t
);
298 static picl_errno_t
fru_init(frutree_frunode_t
*);
300 /* External functions */
301 extern boolean_t
is_fru_present_under_location(frutree_locnode_t
*);
302 extern int kstat_port_state(frutree_port_type_t
, char *, int);
303 extern int kstat_port_cond(frutree_port_type_t
, char *, int);
304 extern picl_errno_t
probe_libdevinfo(frutree_frunode_t
*,
305 frutree_device_args_t
**, boolean_t
);
306 extern picl_errno_t
get_scsislot_name(char *, char *, char *);
307 extern picl_errno_t
probe_for_scsi_frus(frutree_frunode_t
*);
308 extern picl_errno_t
get_fru_path(char *, frutree_frunode_t
*);
309 extern picl_errno_t
scsi_info_init();
310 extern void scsi_info_fini();
311 extern picl_errno_t
get_port_info(frutree_portnode_t
*);
312 extern char *strtok_r(char *s1
, const char *s2
, char **lasts
);
314 /* Plugin initialization */
315 static picld_plugin_reg_t frutree_reg_info
= {
316 PICLD_PLUGIN_VERSION_1
,
317 PICLD_PLUGIN_CRITICAL
,
323 /* ptree entry points */
325 piclfrutree_register(void)
327 FRUTREE_DEBUG0(FRUTREE_INIT
, "piclfrutree register");
328 (void) picld_plugin_register(&frutree_reg_info
);
332 piclfrutree_init(void)
334 FRUTREE_DEBUG0(FRUTREE_INIT
, "piclfrutree_init begin");
335 (void) rwlock_init(&hash_lock
, USYNC_THREAD
, NULL
);
338 /* read the environment variables */
341 if (sysinfo(SI_PLATFORM
, sys_name
, sizeof (sys_name
)) == -1) {
345 if (hash_init() != PICL_SUCCESS
) {
348 if (initialize_frutree() != PICL_SUCCESS
) {
352 /* initialize the event queue */
355 (void) pthread_cond_init(&ev_cond
, NULL
);
356 (void) pthread_mutex_init(&ev_mutex
, NULL
);
357 if (pthread_create(&tid
, NULL
, &dr_thread
, NULL
) != 0) {
360 /* register for picl events */
361 if (ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE
,
362 frutree_dr_apstate_change_evhandler
, NULL
) !=
367 if (ptree_register_handler(PICLEVENT_DR_REQ
,
368 frutree_dr_req_evhandler
, NULL
) != PICL_SUCCESS
) {
372 if (ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE
,
373 frutree_cpu_state_change_evhandler
, NULL
) !=
378 if (ptree_register_handler(PICLEVENT_STATE_CHANGE
,
379 frutree_wd_evhandler
, NULL
) != PICL_SUCCESS
) {
382 FRUTREE_DEBUG0(FRUTREE_INIT
, "piclfrutree_init end");
386 piclfrutree_fini(void)
388 ev_queue_t
*event
= NULL
;
391 FRUTREE_DEBUG0(EVENTS
, "piclfrutree_fini begin");
394 /* unregister event handlers */
395 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE
,
396 frutree_dr_apstate_change_evhandler
, NULL
);
397 (void) ptree_unregister_handler(PICLEVENT_DR_REQ
,
398 frutree_dr_req_evhandler
, NULL
);
399 (void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE
,
400 frutree_cpu_state_change_evhandler
, NULL
);
401 (void) ptree_unregister_handler(PICLEVENT_STATE_CHANGE
,
402 frutree_wd_evhandler
, NULL
);
404 /* flush the event queue */
405 (void) pthread_mutex_lock(&ev_mutex
);
406 event
= remove_from_queue();
409 event
= remove_from_queue();
411 queue_head
= queue_tail
= NULL
;
413 (void) pthread_cond_broadcast(&ev_cond
);
414 (void) pthread_mutex_unlock(&ev_mutex
);
415 (void) pthread_cancel(tid
);
416 (void) pthread_join(tid
, &exitval
);
417 (void) pthread_cancel(monitor_tid
);
418 (void) pthread_join(monitor_tid
, &exitval
);
419 (void) pthread_cancel(init_threadID
);
420 (void) pthread_join(init_threadID
, &exitval
);
423 (void) ptree_delete_node(frutreeh
);
424 (void) ptree_destroy_node(frutreeh
);
426 frutree_connects_initiated
= B_FALSE
;
427 chassish
= frutreeh
= rooth
= platformh
= 0;
428 post_picl_events
= B_FALSE
;
429 piclevent_pending
= 0;
430 FRUTREE_DEBUG0(EVENTS
, "piclfrutree_fini end");
433 /* read the ENVIRONMENT variables and initialize tunables */
440 /* read frutree debug flag value */
441 if (val
= getenv(FRUTREE_DEBUG
)) {
443 intval
= strtol(val
, (char **)NULL
, 0);
445 frutree_debug
= intval
;
446 FRUTREE_DEBUG1(PRINT_ALL
, "SUNW_frutree:debug = %x",
451 /* read poll timeout value */
452 if (val
= getenv(FRUTREE_POLL_TIMEOUT
)) {
454 intval
= strtol(val
, (char **)NULL
, 0);
456 frutree_poll_timeout
= intval
;
460 /* read drwait time value */
461 if (val
= getenv(FRUTREE_DRWAIT
)) {
463 intval
= strtol(val
, (char **)NULL
, 0);
465 frutree_drwait_time
= intval
;
471 * callback function for ptree_walk_tree_class to get the
472 * node handle of node
473 * matches a node with same class and name
476 frutree_get_nodehdl(picl_nodehdl_t nodeh
, void *c_args
)
479 char name
[PICL_PROPNAMELEN_MAX
];
480 frutree_callback_data_t
*fru_arg
;
483 return (PICL_INVALIDARG
);
484 fru_arg
= (frutree_callback_data_t
*)c_args
;
486 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_NAME
, name
,
487 sizeof (name
))) != PICL_SUCCESS
) {
491 if (strcmp(fru_arg
->node_name
, name
) == 0) {
492 fru_arg
->retnodeh
= nodeh
;
493 return (PICL_WALK_TERMINATE
);
495 return (PICL_WALK_CONTINUE
);
498 /* queue implementation (used to queue hotswap events) */
506 /* add an event to the queue */
508 add_to_queue(frutree_dr_arg_t dr_data
)
510 ev_queue_t
*new_event
;
512 new_event
= (ev_queue_t
*)malloc(sizeof (ev_queue_t
));
513 if (new_event
== NULL
)
514 return (PICL_NOSPACE
);
516 new_event
->arg
.action
= dr_data
.action
;
517 new_event
->arg
.data
= dr_data
.data
;
518 new_event
->next
= NULL
;
520 if (queue_head
== NULL
) {
521 queue_head
= new_event
;
523 queue_tail
->next
= new_event
;
525 queue_tail
= new_event
;
527 return (PICL_SUCCESS
);
531 remove_from_queue(void)
533 ev_queue_t
*event
= NULL
;
535 if (queue_head
== NULL
)
539 queue_head
= queue_head
->next
;
541 if (queue_head
== NULL
)
547 * event handler for watchdog expiry event (picl-state-change) event on
548 * watchdog-timer node
552 frutree_wd_evhandler(const char *ename
, const void *earg
, size_t size
,
556 char *wd_state
= NULL
;
558 picl_nodehdl_t wd_nodehdl
;
559 char value
[PICL_PROPNAMELEN_MAX
];
560 frutree_callback_data_t fru_arg
;
565 if (strncmp(ename
, PICLEVENT_STATE_CHANGE
,
566 strlen(PICLEVENT_STATE_CHANGE
))) {
570 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
)) {
574 if (nvlist_lookup_uint64(nvlp
, PICLEVENTARG_NODEHANDLE
,
575 &wd_nodehdl
) == -1) {
580 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_STATE
,
586 if ((rc
= ptree_get_propval_by_name(wd_nodehdl
,
587 PICL_PROP_CLASSNAME
, value
, sizeof (value
))) != PICL_SUCCESS
) {
592 /* if the event is not of watchdog-timer, return */
593 if (strcmp(value
, PICL_CLASS_WATCHDOG_TIMER
) != 0) {
598 FRUTREE_DEBUG1(EVENTS
, "frutree:Received WD event(%s)", wd_state
);
599 /* frutree plugin handles only watchdog expiry events */
600 if (strcmp(wd_state
, PICL_PROPVAL_WD_STATE_EXPIRED
) != 0) {
605 if ((rc
= ptree_get_propval_by_name(wd_nodehdl
,
606 PICL_PROP_WATCHDOG_ACTION
, value
, sizeof (value
))) !=
612 /* if action is none, dont do anything */
613 if (strcmp(value
, PICL_PROPVAL_WD_ACTION_NONE
) == 0) {
618 /* find the CPU nodehdl */
619 (void) strncpy(fru_arg
.node_name
, SANIBEL_PICLNODE_CPU
,
620 sizeof (fru_arg
.node_name
));
621 fru_arg
.retnodeh
= 0;
622 if ((rc
= ptree_walk_tree_by_class(chassish
, PICL_CLASS_FRU
,
623 &fru_arg
, frutree_get_nodehdl
)) != PICL_SUCCESS
) {
628 if (fru_arg
.retnodeh
== NULL
) {
633 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
634 PICLEVENTARGVAL_FAILED
, NULL
, fru_arg
.retnodeh
,
635 NO_WAIT
)) != PICL_SUCCESS
) {
636 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
637 SANIBEL_PICLNODE_CPU
, PICLEVENT_CONDITION_CHANGE
, rc
);
643 * event handler for dr_ap_state_change event
644 * - determine the event type and queue it in dr_queue to handle it
648 frutree_dr_apstate_change_evhandler(const char *ename
, const void *earg
,
649 size_t size
, void *cookie
)
655 picl_nodehdl_t nodeh
, childh
;
656 hashdata_t
*hashptr
= NULL
;
657 frutree_dr_arg_t dr_arg
;
658 frutree_frunode_t
*frup
= NULL
;
659 frutree_locnode_t
*locp
= NULL
;
660 frutree_callback_data_t fru_arg
;
661 boolean_t state_changed
= B_FALSE
;
666 if (strncmp(ename
, PICLEVENT_DR_AP_STATE_CHANGE
,
667 strlen(PICLEVENT_DR_AP_STATE_CHANGE
)) != 0) {
671 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
)) {
675 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_AP_ID
, &ap_id
) == -1) {
680 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_HINT
, &hint
) == -1) {
685 /* check for empty strings */
686 if (!ap_id
|| !hint
) {
687 FRUTREE_DEBUG0(EVENTS
, "Empty hint/ap_id");
692 /* get the location name */
693 name
= strrchr(ap_id
, ':');
700 /* find the loc object */
701 (void) strncpy(fru_arg
.node_name
, name
, sizeof (fru_arg
.node_name
));
702 fru_arg
.retnodeh
= 0;
703 if (ptree_walk_tree_by_class(chassish
, PICL_CLASS_LOCATION
,
704 &fru_arg
, frutree_get_nodehdl
) != PICL_SUCCESS
) {
709 if (fru_arg
.retnodeh
== NULL
) {
713 nodeh
= fru_arg
.retnodeh
;
715 if (hash_lookup_entry(nodeh
, (void **)&hashptr
) != PICL_SUCCESS
) {
719 locp
= LOCDATA_PTR(hashptr
);
725 if (strcmp(hint
, DR_HINT_INSERT
) == 0) {
726 dr_arg
.action
= HANDLE_INSERT
;
728 (void) pthread_mutex_lock(&ev_mutex
);
729 if (add_to_queue(dr_arg
) != PICL_SUCCESS
) {
730 (void) pthread_mutex_unlock(&ev_mutex
);
734 (void) pthread_cond_signal(&ev_cond
);
735 (void) pthread_mutex_unlock(&ev_mutex
);
740 if (strcmp(hint
, DR_HINT_REMOVE
) == 0) {
741 dr_arg
.action
= HANDLE_REMOVE
;
743 (void) pthread_mutex_lock(&ev_mutex
);
744 if (add_to_queue(dr_arg
) != PICL_SUCCESS
) {
745 (void) pthread_mutex_unlock(&ev_mutex
);
749 (void) pthread_cond_signal(&ev_cond
);
750 (void) pthread_mutex_unlock(&ev_mutex
);
755 if (strcmp(hint
, DR_RESERVED_ATTR
) != 0) { /* unknown event */
760 /* handle DR_RESERVED_ATTR HINT */
761 /* check if this is a fru event */
762 if (ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_CHILD
,
763 &childh
, sizeof (childh
)) == PICL_SUCCESS
) {
764 /* get the child fru information */
765 if (hash_lookup_entry(childh
, (void **)&hashptr
) ==
767 frup
= FRUDATA_PTR(hashptr
);
775 (void) pthread_mutex_lock(&frup
->mutex
);
776 if (frup
->dr_in_progress
) {
777 /* dr in progress, neglect the event */
778 (void) pthread_mutex_unlock(&frup
->mutex
);
782 (void) pthread_mutex_unlock(&frup
->mutex
);
784 if (update_fru_state(frup
, &state_changed
) != PICL_SUCCESS
) {
790 (void) pthread_mutex_lock(&frup
->mutex
);
791 /* figure out if this is config/unconfig operation */
792 if (frup
->state
== FRU_STATE_CONFIGURED
) {
793 dr_arg
.action
= HANDLE_CONFIGURE
;
795 } else if (frup
->state
== FRU_STATE_UNCONFIGURED
) {
796 dr_arg
.action
= HANDLE_UNCONFIGURE
;
799 (void) pthread_mutex_unlock(&frup
->mutex
);
801 (void) pthread_mutex_lock(&ev_mutex
);
802 if (add_to_queue(dr_arg
) != PICL_SUCCESS
) {
803 (void) pthread_mutex_unlock(&ev_mutex
);
807 (void) pthread_cond_signal(&ev_cond
);
808 (void) pthread_mutex_unlock(&ev_mutex
);
813 /* check if this event is related to location */
814 (void) pthread_mutex_lock(&locp
->mutex
);
815 if (locp
->dr_in_progress
) {
816 /* dr in progress, neglect the event */
817 (void) pthread_mutex_unlock(&locp
->mutex
);
821 (void) pthread_mutex_unlock(&locp
->mutex
);
822 if (update_loc_state(locp
, &state_changed
) != PICL_SUCCESS
) {
827 if (state_changed
) { /* location state has changed */
828 dr_arg
.action
= HANDLE_LOCSTATE_CHANGE
;
831 (void) pthread_mutex_lock(&ev_mutex
);
832 if (add_to_queue(dr_arg
) != PICL_SUCCESS
) {
833 (void) pthread_mutex_unlock(&ev_mutex
);
837 (void) pthread_cond_signal(&ev_cond
);
838 (void) pthread_mutex_unlock(&ev_mutex
);
842 /* duplicate event */
847 * Event handler for dr_req event
851 frutree_dr_req_evhandler(const char *ename
, const void *earg
, size_t size
,
858 picl_nodehdl_t nodeh
;
859 frutree_dr_arg_t dr_arg
;
860 hashdata_t
*hashptr
= NULL
;
861 frutree_frunode_t
*frup
= NULL
;
862 frutree_callback_data_t fru_arg
;
867 if (strncmp(ename
, PICLEVENT_DR_REQ
, strlen(PICLEVENT_DR_REQ
)) != 0) {
870 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
)) {
873 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_AP_ID
, &ap_id
) == -1) {
877 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_DR_REQ_TYPE
,
883 if (!ap_id
|| !dr_req
) {
884 FRUTREE_DEBUG0(EVENTS
, "Empty dr_req/ap_id");
889 /* get the location name */
890 name
= strrchr(ap_id
, ':');
902 FRUTREE_DEBUG2(EVENTS
, "DR_REQ:%s on %s", dr_req
, name
);
903 (void) strncpy(fru_arg
.node_name
, name
, sizeof (fru_arg
.node_name
));
904 fru_arg
.retnodeh
= 0;
905 if (ptree_walk_tree_by_class(frutreeh
, PICL_CLASS_FRU
,
906 &fru_arg
, frutree_get_nodehdl
) != PICL_SUCCESS
) {
911 if (fru_arg
.retnodeh
== NULL
) {
915 nodeh
= fru_arg
.retnodeh
;
917 /* find the fru object */
918 if (hash_lookup_entry(nodeh
, (void **)&hashptr
) != PICL_SUCCESS
) {
922 frup
= FRUDATA_PTR(hashptr
);
928 if (strcmp(dr_req
, DR_REQ_INCOMING_RES
) == 0) {
929 dr_arg
.action
= CONFIGURE_FRU
;
932 } else if (strcmp(dr_req
, DR_REQ_OUTGOING_RES
) == 0) {
933 dr_arg
.action
= UNCONFIGURE_FRU
;
941 (void) pthread_mutex_lock(&ev_mutex
);
942 if (add_to_queue(dr_arg
) != PICL_SUCCESS
) {
943 (void) pthread_mutex_unlock(&ev_mutex
);
947 (void) pthread_cond_signal(&ev_cond
);
948 (void) pthread_mutex_unlock(&ev_mutex
);
953 * Event handler for cpu_state_change event
957 frutree_cpu_state_change_evhandler(const char *ename
, const void *earg
,
958 size_t size
, void *cookie
)
962 frutree_frunode_t
*frup
= NULL
;
963 hashdata_t
*hashptr
= NULL
;
964 picl_nodehdl_t nodeh
;
965 frutree_dr_arg_t dr_arg
;
970 if (strncmp(ename
, PICLEVENT_CPU_STATE_CHANGE
,
971 strlen(PICLEVENT_CPU_STATE_CHANGE
)) != 0) {
975 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
)) {
978 if (nvlist_lookup_uint64(nvlp
, PICLEVENTARG_NODEHANDLE
, &nodeh
) == -1) {
982 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_CPU_EV_TYPE
, &hint
) == -1) {
987 if (hash_lookup_entry(nodeh
, (void **)&hashptr
) != PICL_SUCCESS
) {
991 frup
= FRUDATA_PTR(hashptr
);
997 if (strcmp(hint
, PICLEVENTARGVAL_OFFLINE
) == 0) {
998 dr_arg
.action
= CPU_OFFLINE
;
1000 } else if (strcmp(hint
, PICLEVENTARGVAL_ONLINE
) == 0) {
1001 dr_arg
.action
= CPU_ONLINE
;
1008 (void) pthread_mutex_lock(&ev_mutex
);
1009 if (add_to_queue(dr_arg
) != PICL_SUCCESS
) {
1010 (void) pthread_mutex_unlock(&ev_mutex
);
1014 (void) pthread_cond_signal(&ev_cond
);
1015 (void) pthread_mutex_unlock(&ev_mutex
);
1020 attach_driver(char *driver
)
1024 (void) snprintf(cmd
, sizeof (cmd
), "%s %s",
1025 DEVFSADM_CMD
, driver
);
1026 (void) pclose(popen(cmd
, "r"));
1030 * Find the node in platform tree with given devfs-path.
1031 * ptree_find_node is getting a node with devfs-path /pci@1f,0/pci@1,1
1032 * when we want to find node with /pci@1f,0/pci@1. The fix
1033 * is required in libpicltree. For now use ptree_walk_tree_by_class
1037 find_ref_parent(picl_nodehdl_t nodeh
, void *c_args
)
1039 picl_prophdl_t proph
;
1040 ptree_propinfo_t propinfo
;
1042 frutree_callback_data_t
*fru_arg
;
1045 return (PICL_INVALIDARG
);
1046 fru_arg
= (frutree_callback_data_t
*)c_args
;
1048 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_DEVFS_PATH
,
1049 &proph
) != PICL_SUCCESS
) {
1050 return (PICL_WALK_CONTINUE
);
1053 if (ptree_get_propinfo(proph
, &propinfo
) != PICL_SUCCESS
) {
1054 return (PICL_WALK_CONTINUE
);
1057 vbuf
= alloca(propinfo
.piclinfo
.size
);
1059 return (PICL_WALK_CONTINUE
);
1061 if (ptree_get_propval(proph
, vbuf
,
1062 propinfo
.piclinfo
.size
) != PICL_SUCCESS
) {
1063 return (PICL_WALK_CONTINUE
);
1066 /* compare the devfs_path */
1067 if (strcmp(fru_arg
->node_name
, (char *)vbuf
) == 0) {
1068 fru_arg
->retnodeh
= nodeh
;
1069 return (PICL_WALK_TERMINATE
);
1071 return (PICL_WALK_CONTINUE
);
1074 * Find the reference node in /platform tree
1075 * return : 0 - if node is not found
1077 static picl_nodehdl_t
1078 get_reference_handle(picl_nodehdl_t nodeh
)
1080 picl_prophdl_t proph
;
1081 ptree_propinfo_t propinfo
;
1083 picl_errno_t rc
= PICL_SUCCESS
;
1084 char devfs_path
[PICL_PROPNAMELEN_MAX
];
1085 char value
[PICL_PROPNAMELEN_MAX
];
1086 char class[PICL_PROPNAMELEN_MAX
];
1087 frutree_callback_data_t fru_arg
;
1088 picl_nodehdl_t refhdl
= 0, ref_parent
= 0, nodehdl
= 0;
1091 * for fru node, get the devfspath and bus-addr of
1094 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_CLASSNAME
,
1095 class, sizeof (class)) != PICL_SUCCESS
) {
1099 if (strcmp(class, PICL_CLASS_FRU
) == 0) {
1100 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_PARENT
,
1101 &nodehdl
, sizeof (nodehdl
)) != PICL_SUCCESS
) {
1104 } else if (strcmp(class, PICL_CLASS_PORT
) == 0) {
1110 if (ptree_get_propval_by_name(nodehdl
, PICL_PROP_DEVFS_PATH
,
1111 devfs_path
, sizeof (devfs_path
)) != PICL_SUCCESS
) {
1114 if (ptree_get_propval_by_name(nodehdl
, PICL_PROP_BUS_ADDR
,
1115 value
, sizeof (value
)) != PICL_SUCCESS
) {
1119 /* find the node with same devfs-path */
1120 (void) strncpy(fru_arg
.node_name
, devfs_path
,
1121 sizeof (fru_arg
.node_name
));
1122 fru_arg
.retnodeh
= 0;
1123 if (ptree_walk_tree_by_class(platformh
, NULL
,
1124 (void *)&fru_arg
, find_ref_parent
) != PICL_SUCCESS
) {
1128 if (fru_arg
.retnodeh
== NULL
)
1131 ref_parent
= fru_arg
.retnodeh
;
1132 /* traverse thru childeren and find the reference node */
1133 rc
= ptree_get_propval_by_name(ref_parent
, PICL_PROP_CHILD
,
1134 &refhdl
, sizeof (picl_nodehdl_t
));
1135 while (rc
== PICL_SUCCESS
) {
1137 rc
= ptree_get_propval_by_name(refhdl
, PICL_PROP_PEER
,
1138 &refhdl
, sizeof (picl_nodehdl_t
));
1140 * compare the bus_addr or Unit address
1141 * format of bus_addr can be either (1,3 or 0x6)
1143 if (ptree_get_prop_by_name(nodehdl
, PICL_PROP_BUS_ADDR
,
1144 &proph
) != PICL_SUCCESS
) {
1145 if (ptree_get_prop_by_name(nodehdl
,
1146 PICL_PROP_UNIT_ADDRESS
, &proph
) !=
1152 if (ptree_get_propinfo(proph
, &propinfo
) != PICL_SUCCESS
) {
1156 vbuf
= alloca(propinfo
.piclinfo
.size
);
1160 if (ptree_get_propval(proph
, vbuf
,
1161 propinfo
.piclinfo
.size
) != PICL_SUCCESS
) {
1165 if (strchr((char *)vbuf
, ',') != NULL
) {
1166 if (strcmp(value
, (char *)vbuf
) == 0) {
1170 if (strtoul((char *)vbuf
, NULL
, 16) ==
1171 strtoul(value
, NULL
, 16)) {
1179 /* Hash Table Management */
1181 free_data(frutree_datatype_t type
, hashdata_t
*datap
)
1183 frutree_frunode_t
*frup
= NULL
;
1184 frutree_locnode_t
*locp
= NULL
;
1185 frutree_portnode_t
*portp
= NULL
;
1187 if (datap
== NULL
) {
1193 frup
= (frutree_frunode_t
*)datap
->data
;
1195 (void) pthread_mutex_destroy(&frup
->mutex
);
1196 (void) pthread_cond_destroy(&frup
->cond_cv
);
1197 (void) pthread_cond_destroy(&frup
->busy_cond_cv
);
1201 locp
= (frutree_locnode_t
*)datap
->data
;
1203 (void) pthread_mutex_destroy(&locp
->mutex
);
1204 (void) pthread_cond_destroy(&locp
->cond_cv
);
1208 portp
= (frutree_portnode_t
*)datap
->data
;
1217 * Initialize the hash table
1224 FRUTREE_DEBUG0(HASHTABLE
, "hash_init begin");
1225 node_hash_table
.tbl
= (frutree_hashelm_t
**)malloc(
1226 sizeof (frutree_hashelm_t
*) * HASH_TABLE_SIZE
);
1228 if (node_hash_table
.tbl
== NULL
) {
1229 return (PICL_NOSPACE
);
1232 /* initialize each entry in hashtable */
1233 node_hash_table
.hash_size
= HASH_TABLE_SIZE
;
1234 for (i
= 0; i
< node_hash_table
.hash_size
; ++i
) {
1235 node_hash_table
.tbl
[i
] = NULL
;
1237 return (PICL_SUCCESS
);
1241 * Destroy the hash table
1247 frutree_hashelm_t
*el
;
1248 hashdata_t
*datap
= NULL
;
1250 (void) rw_wrlock(&hash_lock
);
1251 if (node_hash_table
.tbl
== NULL
) {
1252 (void) rw_unlock(&hash_lock
);
1256 /* loop thru each linked list in the table and free */
1257 for (i
= 0; i
< node_hash_table
.hash_size
; ++i
) {
1258 while (node_hash_table
.tbl
[i
] != NULL
) {
1259 el
= node_hash_table
.tbl
[i
];
1260 node_hash_table
.tbl
[i
] = el
->nextp
;
1261 datap
= (hashdata_t
*)el
->nodep
;
1262 free_data(datap
->type
, datap
);
1268 free(node_hash_table
.tbl
);
1269 (void) rw_unlock(&hash_lock
);
1273 * Add an entry to the hash table
1276 hash_add_entry(picl_nodehdl_t hdl
, void *nodep
)
1279 frutree_hashelm_t
*el
;
1281 FRUTREE_DEBUG0(HASHTABLE
, "hash_add_entry : begin");
1282 (void) rw_wrlock(&hash_lock
);
1284 if (node_hash_table
.tbl
== NULL
) {
1285 (void) rw_unlock(&hash_lock
);
1286 return (PICL_NOTINITIALIZED
);
1289 el
= (frutree_hashelm_t
*)malloc(sizeof (frutree_hashelm_t
));
1291 (void) rw_unlock(&hash_lock
);
1292 return (PICL_NOSPACE
);
1299 if (frutree_debug
& HASHTABLE
) {
1300 picl_nodehdl_t nodeid
;
1302 cvt_ptree2picl(&nodeid
);
1303 FRUTREE_DEBUG1(HASHTABLE
, "added node: %llx", nodeid
);
1306 indx
= HASH_INDEX(node_hash_table
.hash_size
, hdl
);
1307 if (node_hash_table
.tbl
[indx
] == NULL
) {
1308 /* first element for this index */
1309 node_hash_table
.tbl
[indx
] = el
;
1310 (void) rw_unlock(&hash_lock
);
1311 return (PICL_SUCCESS
);
1314 el
->nextp
= node_hash_table
.tbl
[indx
];
1315 node_hash_table
.tbl
[indx
] = el
;
1316 (void) rw_unlock(&hash_lock
);
1317 return (PICL_SUCCESS
);
1321 * Remove a hash entry from the table
1324 hash_remove_entry(picl_nodehdl_t hdl
)
1327 hashdata_t
*datap
= NULL
;
1328 frutree_hashelm_t
*prev
, *cur
;
1330 (void) rw_wrlock(&hash_lock
);
1332 if (node_hash_table
.tbl
== NULL
) {
1333 (void) rw_unlock(&hash_lock
);
1334 return (PICL_NOTINITIALIZED
);
1337 i
= HASH_INDEX(node_hash_table
.hash_size
, hdl
);
1339 /* check that the hash chain is not empty */
1340 if (node_hash_table
.tbl
[i
] == NULL
) {
1341 (void) rw_wrlock(&hash_lock
);
1342 return (PICL_NODENOTFOUND
);
1345 /* search hash chain for entry to be removed */
1347 cur
= node_hash_table
.tbl
[i
];
1349 if (cur
->hdl
== hdl
) {
1350 if (prev
== NULL
) { /* 1st elem in hash chain */
1351 node_hash_table
.tbl
[i
] = cur
->nextp
;
1353 prev
->nextp
= cur
->nextp
;
1355 datap
= (hashdata_t
*)cur
->nodep
;
1356 free_data(datap
->type
, datap
);
1361 if (frutree_debug
& HASHTABLE
) {
1362 picl_nodehdl_t nodeid
;
1364 cvt_ptree2picl(&nodeid
);
1365 FRUTREE_DEBUG1(HASHTABLE
, "removed node: %llx",
1369 (void) rw_unlock(&hash_lock
);
1370 return (PICL_SUCCESS
);
1376 /* entry was not found */
1377 (void) rw_unlock(&hash_lock
);
1378 return (PICL_NODENOTFOUND
);
1382 * Lookup a handle in the table
1385 hash_lookup_entry(picl_nodehdl_t hdl
, void **nodepp
)
1388 frutree_hashelm_t
*el
;
1390 FRUTREE_DEBUG1(HASHTABLE
, "hash_lookup begin: %llx", hdl
);
1391 (void) rw_rdlock(&hash_lock
);
1393 if (node_hash_table
.tbl
== NULL
) {
1394 (void) rw_unlock(&hash_lock
);
1395 return (PICL_NOTINITIALIZED
);
1397 if (nodepp
== NULL
) {
1398 (void) rw_unlock(&hash_lock
);
1399 return (PICL_INVALIDHANDLE
);
1402 i
= HASH_INDEX(node_hash_table
.hash_size
, hdl
);
1404 if (node_hash_table
.tbl
[i
] == NULL
) {
1405 (void) rw_unlock(&hash_lock
);
1406 return (PICL_NODENOTFOUND
);
1409 el
= node_hash_table
.tbl
[i
];
1411 if (el
->hdl
== hdl
) {
1412 *nodepp
= el
->nodep
;
1413 (void) rw_unlock(&hash_lock
);
1414 return (PICL_SUCCESS
);
1418 (void) rw_unlock(&hash_lock
);
1419 return (PICL_NODENOTFOUND
);
1422 /* create and initialize data structure for a loc node */
1424 make_loc_data(char *full_name
, hashdata_t
**hashptr
)
1427 frutree_locnode_t
*locp
;
1428 hashdata_t
*datap
= NULL
;
1430 datap
= (hashdata_t
*)malloc(sizeof (hashdata_t
));
1431 if (datap
== NULL
) {
1432 return (PICL_NOSPACE
);
1434 datap
->type
= LOC_TYPE
;
1436 /* allocate the data */
1437 locp
= (frutree_locnode_t
*)malloc(sizeof (frutree_locnode_t
));
1440 return (PICL_NOSPACE
);
1443 /* make a copy of the name */
1444 name_copy
= strdup(full_name
);
1445 if (name_copy
== NULL
) {
1448 return (PICL_NOSPACE
);
1451 /* initialize the data */
1452 locp
->name
= name_copy
;
1454 locp
->state
= LOC_STATE_UNKNOWN
;
1455 locp
->prev_state
= LOC_STATE_UNKNOWN
;
1456 locp
->cpu_node
= B_FALSE
;
1457 locp
->autoconfig_enabled
= B_FALSE
;
1458 locp
->state_mgr
= UNKNOWN
;
1459 locp
->dr_in_progress
= B_FALSE
;
1460 (void) pthread_mutex_init(&locp
->mutex
, NULL
);
1461 (void) pthread_cond_init(&locp
->cond_cv
, NULL
);
1465 return (PICL_SUCCESS
);
1468 /* create and initialize data structure for a fru node */
1470 make_fru_data(char *full_name
, hashdata_t
**hashptr
)
1473 frutree_frunode_t
*frup
;
1474 hashdata_t
*datap
= NULL
;
1476 datap
= (hashdata_t
*)malloc(sizeof (hashdata_t
));
1477 if (datap
== NULL
) {
1478 return (PICL_NOSPACE
);
1480 datap
->type
= FRU_TYPE
;
1482 /* allocate the data */
1483 frup
= (frutree_frunode_t
*)malloc(sizeof (frutree_frunode_t
));
1486 return (PICL_NOSPACE
);
1489 /* make a copy of the name */
1490 name_copy
= strdup(full_name
);
1491 if (name_copy
== NULL
) {
1494 return (PICL_NOSPACE
);
1497 /* initialize the data */
1498 frup
->name
= name_copy
;
1500 frup
->state
= FRU_STATE_UNCONFIGURED
;
1501 frup
->prev_state
= FRU_STATE_UNKNOWN
;
1502 frup
->cond
= FRU_COND_UNKNOWN
;
1503 frup
->prev_cond
= FRU_COND_UNKNOWN
;
1504 frup
->cpu_node
= B_FALSE
;
1505 frup
->autoconfig_enabled
= B_FALSE
;
1506 frup
->dr_in_progress
= B_FALSE
;
1507 frup
->busy
= B_FALSE
;
1508 frup
->state_mgr
= UNKNOWN
;
1509 frup
->fru_path
[0] = '\0';
1510 (void) pthread_mutex_init(&frup
->mutex
, NULL
);
1511 (void) pthread_cond_init(&frup
->cond_cv
, NULL
);
1512 (void) pthread_cond_init(&frup
->busy_cond_cv
, NULL
);
1516 return (PICL_SUCCESS
);
1519 /* create and initialize data structure for a port node */
1521 make_port_data(char *full_name
, hashdata_t
**hashptr
)
1524 frutree_portnode_t
*portp
;
1525 hashdata_t
*datap
= NULL
;
1527 datap
= (hashdata_t
*)malloc(sizeof (hashdata_t
));
1528 if (datap
== NULL
) {
1529 return (PICL_NOSPACE
);
1531 datap
->type
= PORT_TYPE
;
1533 /* allocate the data */
1534 portp
= (frutree_portnode_t
*)malloc(sizeof (frutree_portnode_t
));
1535 if (portp
== NULL
) {
1537 return (PICL_NOSPACE
);
1539 /* make a copy of the name */
1540 name_copy
= strdup(full_name
);
1541 if (name_copy
== NULL
) {
1544 return (PICL_NOSPACE
);
1547 /* initialize the data */
1548 portp
->name
= name_copy
;
1549 portp
->portnodeh
= 0;
1550 portp
->state
= PORT_STATE_UNKNOWN
;
1551 portp
->cond
= PORT_COND_UNKNOWN
;
1552 datap
->data
= portp
;
1554 return (PICL_SUCCESS
);
1558 * utility routine to create table entries
1561 create_table_entry(picl_prophdl_t tblhdl
, picl_nodehdl_t refhdl
, char *class)
1564 ptree_propinfo_t propinfo
;
1565 picl_prophdl_t prophdl
[2];
1566 char buf
[PICL_CLASSNAMELEN_MAX
];
1568 /* first column is class */
1569 if ((rc
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1570 PICL_PTYPE_CHARSTRING
, PICL_READ
, PICL_CLASSNAMELEN_MAX
,
1571 PICL_PROP_CLASS
, NULLREAD
,
1572 NULLWRITE
)) != PICL_SUCCESS
) {
1576 if ((rc
= ptree_create_prop(&propinfo
, class,
1577 &prophdl
[0])) != PICL_SUCCESS
) {
1581 /* second column is reference property */
1582 (void) snprintf(buf
, sizeof (buf
), "_%s_", class);
1583 if ((rc
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1584 PICL_PTYPE_REFERENCE
, PICL_READ
,
1585 sizeof (picl_nodehdl_t
), buf
, NULLREAD
,
1586 NULLWRITE
)) != PICL_SUCCESS
) {
1590 if ((rc
= ptree_create_prop(&propinfo
, &refhdl
,
1591 &prophdl
[1])) != PICL_SUCCESS
) {
1595 /* add row to table */
1596 if ((rc
= ptree_add_row_to_table(tblhdl
, 2, prophdl
)) != PICL_SUCCESS
) {
1599 return (PICL_SUCCESS
);
1603 * Utility routine to create picl property
1606 create_property(int ptype
, int pmode
, size_t psize
, char *pname
,
1607 int (*readfn
)(ptree_rarg_t
*, void *),
1608 int (*writefn
)(ptree_warg_t
*, const void *),
1609 picl_nodehdl_t nodeh
, picl_prophdl_t
*prophp
, void *vbuf
)
1612 ptree_propinfo_t propinfo
;
1613 picl_prophdl_t proph
;
1615 if (pname
== NULL
|| vbuf
== NULL
) {
1616 return (PICL_FAILURE
);
1619 if (ptype
== PICL_PTYPE_TABLE
) {
1620 if ((rc
= ptree_create_table((picl_prophdl_t
*)vbuf
))
1626 if ((rc
= ptree_get_prop_by_name(nodeh
, pname
, &proph
)) ==
1627 PICL_SUCCESS
) { /* property already exists */
1631 rc
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
1632 ptype
, pmode
, psize
, pname
, readfn
, writefn
);
1633 if (rc
!= PICL_SUCCESS
) {
1637 rc
= ptree_create_and_add_prop(nodeh
, &propinfo
, vbuf
, prophp
);
1638 if (rc
!= PICL_SUCCESS
) {
1641 return (PICL_SUCCESS
);
1645 * create frutree node, chassis node
1648 initialize_frutree()
1650 int rc
= PICL_SUCCESS
;
1651 hashdata_t
*datap
= NULL
;
1652 frutree_frunode_t
*frup
= NULL
;
1653 uint64_t ap_status_time
;
1655 FRUTREE_DEBUG0(FRUTREE_INIT
, "initialize_frutree begin");
1656 /* Get the root of the PICL tree */
1657 if ((rc
= ptree_get_root(&rooth
)) != PICL_SUCCESS
) {
1660 FRUTREE_DEBUG1(FRUTREE_INIT
, "roothdl = %llx", rooth
);
1662 /* create /frutree node */
1663 if ((rc
= ptree_create_and_add_node(rooth
, PICL_NODE_FRUTREE
,
1664 PICL_CLASS_PICL
, &frutreeh
)) != PICL_SUCCESS
) {
1667 FRUTREE_DEBUG1(FRUTREE_INIT
, "frutreeh = %llx", frutreeh
);
1669 /* create chassis node */
1670 if ((rc
= ptree_create_node(PICL_NODE_CHASSIS
, PICL_CLASS_FRU
,
1671 &chassish
)) != PICL_SUCCESS
) {
1674 FRUTREE_DEBUG1(FRUTREE_INIT
, "chassish = %llx", chassish
);
1676 /* Allocate fru data */
1677 if ((rc
= make_fru_data(PICL_NODE_CHASSIS
, &datap
)) !=
1679 (void) ptree_destroy_node(chassish
);
1682 /* initialise chassis handle and parent handle */
1683 frup
= FRUDATA_PTR(datap
);
1684 frup
->frunodeh
= chassish
;
1686 /* Add the chassis node to the tree */
1687 if ((rc
= ptree_add_node(frutreeh
, chassish
)) != PICL_SUCCESS
) {
1688 free_data(datap
->type
, datap
);
1689 (void) ptree_destroy_node(chassish
);
1693 /* create chassis state property */
1694 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
1695 PICL_READ
, PICL_PROPNAMELEN_MAX
, PICL_PROP_STATE
,
1696 NULLREAD
, NULLWRITE
, chassish
, (picl_prophdl_t
*)NULL
,
1697 PICLEVENTARGVAL_UNCONFIGURED
)) != PICL_SUCCESS
) {
1698 free_data(datap
->type
, datap
);
1699 (void) ptree_delete_node(chassish
);
1700 (void) ptree_destroy_node(chassish
);
1703 ap_status_time
= (uint64_t)(time(NULL
));
1704 if ((rc
= create_property(PICL_PTYPE_TIMESTAMP
, PICL_READ
,
1705 sizeof (ap_status_time
), PICL_PROP_STATUS_TIME
,
1706 NULLREAD
, NULLWRITE
, chassish
,
1707 NULL
, &ap_status_time
)) != PICL_SUCCESS
) {
1708 free_data(datap
->type
, datap
);
1709 (void) ptree_delete_node(chassish
);
1710 (void) ptree_destroy_node(chassish
);
1714 /* save chassis info in hashtable */
1715 if ((rc
= hash_add_entry(chassish
,
1716 (void *)datap
)) != PICL_SUCCESS
) {
1717 free_data(datap
->type
, datap
);
1718 (void) ptree_delete_node(chassish
);
1719 (void) ptree_destroy_node(chassish
);
1722 return (PICL_SUCCESS
);
1726 * Read the temporary property created by platform specific
1727 * plugin to get the config file name.
1730 get_configuration_file()
1733 picl_prophdl_t proph
;
1734 char file_name
[PICL_PROPNAMELEN_MAX
];
1736 if ((rc
= ptree_get_prop_by_name(chassish
,
1737 PICL_PROP_CONF_FILE
, &proph
)) != PICL_SUCCESS
) {
1741 if ((rc
= ptree_get_propval(proph
, file_name
,
1742 sizeof (file_name
))) != PICL_SUCCESS
) {
1746 (void) snprintf(conf_file
, sizeof (conf_file
),
1747 PICLD_PLAT_PLUGIN_DIRF
"%s", sys_name
, file_name
);
1748 /* delete the tmp prop created by platform specific plugin */
1749 (void) ptree_delete_prop(proph
);
1750 (void) ptree_destroy_prop(proph
);
1751 FRUTREE_DEBUG1(EVENTS
, "Using %s conf file", conf_file
);
1752 return (PICL_SUCCESS
);
1756 * Read the cfgadm data and get the latest information
1759 get_cfgadm_state(cfga_list_data_t
*data
, char *ap_id
)
1762 cfga_err_t ap_list_err
;
1763 cfga_list_data_t
*list
= NULL
;
1764 char * const *p
= &ap_id
;
1766 if (data
== NULL
|| ap_id
== NULL
) {
1767 return (PICL_INVALIDARG
);
1770 ap_list_err
= config_list_ext(1, p
, &list
, &nlist
, NULL
,
1772 if (ap_list_err
!= CFGA_OK
) {
1774 return (cfg2picl_errmap
[ap_list_err
][1]);
1777 (void) memcpy(data
, list
, sizeof (cfga_list_data_t
));
1779 return (PICL_SUCCESS
);
1783 * syncup with cfgadm data and read latest location state information
1786 update_loc_state(frutree_locnode_t
*locp
, boolean_t
*updated
)
1789 cfga_list_data_t
*list
= NULL
;
1790 picl_errno_t rc
, rc1
;
1791 char valbuf
[PICL_PROPNAMELEN_MAX
];
1792 char slot_type
[PICL_PROPNAMELEN_MAX
];
1793 uint64_t ap_status_time
;
1796 if (locp
->state_mgr
== PLUGIN_PVT
) {
1797 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
1798 PICL_PROP_STATE
, (void *)valbuf
,
1799 PICL_PROPNAMELEN_MAX
)) != PICL_SUCCESS
) {
1803 /* if there is a change in state, update the internal value */
1804 if (strcmp(loc_state
[locp
->state
], valbuf
) != 0) {
1805 ap_status_time
= (uint64_t)(time(NULL
));
1806 if ((rc
= ptree_update_propval_by_name(locp
->locnodeh
,
1807 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
1808 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
1809 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
1810 PICL_PROP_STATUS_TIME
, locp
->name
, rc
);
1813 locp
->prev_state
= locp
->state
;
1814 for (i
= 0; (loc_state
[i
] != NULL
); i
++) {
1815 if (strcmp(loc_state
[i
], valbuf
) == 0) {
1817 return (PICL_SUCCESS
);
1821 return (PICL_SUCCESS
);
1822 } else if (locp
->state_mgr
== STATIC_LOC
) {
1823 return (PICL_SUCCESS
);
1826 /* get the info from the libcfgadm interface */
1827 list
= (cfga_list_data_t
*)malloc(sizeof (cfga_list_data_t
));
1829 return (PICL_NOSPACE
);
1832 if ((rc
= get_cfgadm_state(list
, locp
->name
)) != PICL_SUCCESS
) {
1833 if ((rc1
= ptree_get_propval_by_name(locp
->locnodeh
,
1834 PICL_PROP_SLOT_TYPE
, slot_type
,
1835 sizeof (slot_type
))) != PICL_SUCCESS
) {
1839 if (strcmp(slot_type
, SANIBEL_SCSI_SLOT
) != 0 &&
1840 strcmp(slot_type
, SANIBEL_IDE_SLOT
) != 0) {
1844 /* this is a scsi location */
1845 if (rc
!= PICL_NODENOTFOUND
) {
1851 * for scsi locations, if node is not found,
1852 * consider location state as empty
1854 (void) pthread_mutex_lock(&locp
->mutex
);
1855 if (locp
->state
!= LOC_STATE_EMPTY
) {
1857 locp
->prev_state
= locp
->state
;
1858 locp
->state
= LOC_STATE_EMPTY
;
1859 ap_status_time
= (uint64_t)(time(NULL
));
1860 if ((rc
= ptree_update_propval_by_name(locp
->locnodeh
,
1861 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
1862 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
1863 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
1864 PICL_PROP_STATUS_TIME
, locp
->name
, rc
);
1867 (void) pthread_mutex_unlock(&locp
->mutex
);
1869 return (PICL_SUCCESS
);
1872 (void) pthread_mutex_lock(&locp
->mutex
);
1873 switch (list
->ap_r_state
) {
1874 case CFGA_STAT_CONNECTED
:
1875 if (locp
->state
!= LOC_STATE_CONNECTED
) {
1877 locp
->prev_state
= locp
->state
;
1878 locp
->state
= LOC_STATE_CONNECTED
;
1881 case CFGA_STAT_DISCONNECTED
:
1882 if (locp
->state
!= LOC_STATE_DISCONNECTED
) {
1884 locp
->prev_state
= locp
->state
;
1885 locp
->state
= LOC_STATE_DISCONNECTED
;
1888 case CFGA_STAT_EMPTY
:
1889 if (locp
->state
!= LOC_STATE_EMPTY
) {
1891 locp
->prev_state
= locp
->state
;
1892 locp
->state
= LOC_STATE_EMPTY
;
1896 if (locp
->state
!= LOC_STATE_UNKNOWN
) {
1898 locp
->prev_state
= locp
->state
;
1899 locp
->state
= LOC_STATE_UNKNOWN
;
1903 if (*updated
== B_TRUE
) {
1904 ap_status_time
= (uint64_t)(time(NULL
));
1905 if ((rc
= ptree_update_propval_by_name(locp
->locnodeh
,
1906 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
1907 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
1908 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
1909 PICL_PROP_STATUS_TIME
, locp
->name
, rc
);
1913 /* update the autoconfig flag */
1914 switch (is_autoconfig_enabled(locp
->name
)) {
1916 locp
->autoconfig_enabled
= B_TRUE
;
1920 locp
->autoconfig_enabled
= B_FALSE
;
1923 (void) pthread_mutex_unlock(&locp
->mutex
);
1926 return (PICL_SUCCESS
);
1930 * volatile callback function to return the state value for a location
1933 get_loc_state(ptree_rarg_t
*rarg
, void *buf
)
1936 frutree_dr_arg_t dr_arg
;
1937 hashdata_t
*hashptr
= NULL
;
1938 frutree_locnode_t
*locp
= NULL
;
1939 boolean_t state_change
= B_FALSE
;
1942 return (PICL_INVALIDARG
);
1945 if ((rc
= hash_lookup_entry(rarg
->nodeh
, (void **)&hashptr
)) !=
1950 locp
= LOCDATA_PTR(hashptr
);
1952 return (PICL_FAILURE
);
1955 (void) pthread_mutex_lock(&locp
->mutex
);
1956 if (locp
->dr_in_progress
== B_TRUE
) {
1957 /* return the cached value */
1958 (void) strncpy((char *)buf
, loc_state
[locp
->state
],
1959 PICL_PROPNAMELEN_MAX
);
1960 (void) pthread_mutex_unlock(&locp
->mutex
);
1961 return (PICL_SUCCESS
);
1963 (void) pthread_mutex_unlock(&locp
->mutex
);
1965 if ((rc
= update_loc_state(locp
, &state_change
)) != PICL_SUCCESS
) {
1966 FRUTREE_DEBUG2(EVENTS
, GET_LOC_STATE_ERR
, locp
->name
, rc
);
1967 /* return the cached value */
1968 (void) strncpy((char *)buf
, loc_state
[locp
->state
],
1969 PICL_PROPNAMELEN_MAX
);
1973 /* if there is a state change, handle the event */
1975 (void) pthread_mutex_lock(&locp
->mutex
);
1976 if (locp
->state
== LOC_STATE_EMPTY
) { /* card removed */
1977 dr_arg
.action
= HANDLE_REMOVE
;
1978 } else if (locp
->prev_state
== LOC_STATE_EMPTY
) {
1979 dr_arg
.action
= HANDLE_INSERT
; /* card inserted */
1981 /* loc state changed */
1982 dr_arg
.action
= HANDLE_LOCSTATE_CHANGE
;
1984 (void) pthread_mutex_unlock(&locp
->mutex
);
1986 (void) pthread_mutex_lock(&ev_mutex
);
1987 if ((rc
= add_to_queue(dr_arg
)) != PICL_SUCCESS
) {
1988 (void) pthread_mutex_unlock(&ev_mutex
);
1989 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
,
1990 "dr_ap_state_change", locp
->name
, rc
);
1992 (void) pthread_cond_signal(&ev_cond
);
1993 (void) pthread_mutex_unlock(&ev_mutex
);
1997 (void) strncpy((char *)buf
, loc_state
[locp
->state
],
1998 PICL_PROPNAMELEN_MAX
);
1999 return (PICL_SUCCESS
);
2003 * syncup with cfgadm data and read latest fru state information
2006 update_fru_state(frutree_frunode_t
*frup
, boolean_t
*updated
)
2010 picl_nodehdl_t loch
;
2011 uint64_t ap_status_time
;
2012 hashdata_t
*hashptr
= NULL
;
2013 cfga_list_data_t
*list
= NULL
;
2014 frutree_locnode_t
*locp
= NULL
;
2015 char valbuf
[PICL_PROPNAMELEN_MAX
];
2018 if (frup
->state_mgr
== PLUGIN_PVT
) {
2019 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
,
2020 PICL_PROP_STATE
, (void *)valbuf
,
2021 PICL_PROPNAMELEN_MAX
)) != PICL_SUCCESS
) {
2025 /* if there is a change in state, update the internal value */
2026 if (strcmp(fru_state
[frup
->state
], valbuf
) != 0) {
2028 frup
->prev_state
= frup
->state
;
2029 ap_status_time
= (uint64_t)(time(NULL
));
2030 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
2031 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
2032 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
2033 if (rc
== PICL_PROPNOTFOUND
) {
2034 (void) create_property(
2035 PICL_PTYPE_TIMESTAMP
, PICL_READ
,
2036 sizeof (ap_status_time
),
2037 PICL_PROP_STATUS_TIME
,
2038 NULLREAD
, NULLWRITE
,
2040 NULL
, &ap_status_time
);
2042 FRUTREE_DEBUG3(EVENTS
,
2043 PTREE_UPDATE_PROP_ERR
,
2044 PICL_PROP_STATUS_TIME
,
2048 for (i
= 0; (fru_state
[i
] != NULL
); i
++) {
2049 if (strcmp(fru_state
[i
], valbuf
) == 0) {
2051 return (PICL_SUCCESS
);
2055 return (PICL_SUCCESS
);
2056 } else if (frup
->state_mgr
== STATIC_LOC
) {
2057 frup
->state
= FRU_STATE_CONFIGURED
;
2058 return (PICL_SUCCESS
);
2061 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
2062 &loch
, sizeof (loch
))) != PICL_SUCCESS
) {
2066 if ((rc
= hash_lookup_entry(loch
, (void **)&hashptr
)) !=
2070 locp
= LOCDATA_PTR(hashptr
);
2072 return (PICL_FAILURE
);
2075 list
= (cfga_list_data_t
*)malloc(sizeof (cfga_list_data_t
));
2077 return (PICL_NOSPACE
);
2080 if ((rc
= get_cfgadm_state(list
, locp
->name
)) != PICL_SUCCESS
) {
2085 (void) pthread_mutex_lock(&frup
->mutex
);
2086 switch (list
->ap_o_state
) {
2087 case CFGA_STAT_CONFIGURED
:
2088 if (frup
->state
!= FRU_STATE_CONFIGURED
) {
2090 frup
->prev_state
= frup
->state
;
2091 frup
->state
= FRU_STATE_CONFIGURED
;
2094 case CFGA_STAT_UNCONFIGURED
:
2095 if (frup
->state
!= FRU_STATE_UNCONFIGURED
) {
2097 frup
->prev_state
= frup
->state
;
2098 frup
->state
= FRU_STATE_UNCONFIGURED
;
2102 if (frup
->state
!= FRU_STATE_UNKNOWN
) {
2104 frup
->prev_state
= frup
->state
;
2105 frup
->state
= FRU_STATE_UNKNOWN
;
2110 /* update the fru_type property */
2111 if (list
->ap_type
) {
2112 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
2113 PICL_PROP_FRU_TYPE
, list
->ap_type
,
2114 sizeof (list
->ap_type
))) != PICL_SUCCESS
) {
2115 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
2116 PICL_PROP_FRU_TYPE
, frup
->name
, rc
);
2120 if (*updated
== B_TRUE
) {
2121 ap_status_time
= (uint64_t)(time(NULL
));
2122 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
2123 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
2124 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
2125 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
2126 PICL_PROP_STATUS_TIME
, frup
->name
, rc
);
2129 (void) pthread_mutex_unlock(&frup
->mutex
);
2132 return (PICL_SUCCESS
);
2136 * syncup with cfgadm data and read latest fru condition information
2139 update_fru_condition(frutree_frunode_t
*frup
, boolean_t
*updated
)
2143 picl_nodehdl_t loch
;
2144 uint64_t ap_cond_time
;
2145 hashdata_t
*hashptr
= NULL
;
2146 cfga_list_data_t
*list
= NULL
;
2147 frutree_locnode_t
*locp
= NULL
;
2148 char valbuf
[PICL_PROPNAMELEN_MAX
];
2151 if (frup
->state_mgr
== PLUGIN_PVT
) {
2152 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
,
2153 PICL_PROP_CONDITION
, (void *)valbuf
,
2154 PICL_PROPNAMELEN_MAX
)) != PICL_SUCCESS
) {
2159 * if there is a change in condition, update the
2162 if (strcmp(fru_cond
[frup
->cond
], valbuf
) != 0) {
2164 ap_cond_time
= (uint64_t)(time(NULL
));
2165 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
2166 PICL_PROP_CONDITION_TIME
, (void *)&ap_cond_time
,
2167 sizeof (ap_cond_time
))) != PICL_SUCCESS
) {
2168 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
2169 PICL_PROP_CONDITION_TIME
, frup
->name
,
2172 frup
->prev_cond
= frup
->cond
;
2174 for (i
= 0; (fru_cond
[i
] != NULL
); i
++) {
2175 if (strcmp(fru_cond
[i
], valbuf
) == 0) {
2177 return (PICL_SUCCESS
);
2181 return (PICL_SUCCESS
);
2182 } else if (frup
->state_mgr
== STATIC_LOC
) {
2183 frup
->cond
= FRU_COND_OK
;
2184 return (PICL_SUCCESS
);
2187 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
2188 &loch
, sizeof (loch
))) != PICL_SUCCESS
) {
2192 if ((rc
= hash_lookup_entry(loch
, (void **)&hashptr
)) !=
2197 locp
= LOCDATA_PTR(hashptr
);
2199 return (PICL_FAILURE
);
2201 list
= (cfga_list_data_t
*)malloc(sizeof (cfga_list_data_t
));
2203 return (PICL_NOSPACE
);
2206 if ((rc
= get_cfgadm_state(list
, locp
->name
)) != PICL_SUCCESS
) {
2211 switch (list
->ap_cond
) {
2213 if (frup
->cond
!= FRU_COND_OK
) {
2215 frup
->prev_cond
= frup
->cond
;
2216 frup
->cond
= FRU_COND_OK
;
2219 case CFGA_COND_FAILING
:
2220 if (frup
->cond
!= FRU_COND_FAILING
) {
2222 frup
->prev_cond
= frup
->cond
;
2223 frup
->cond
= FRU_COND_FAILING
;
2226 case CFGA_COND_FAILED
:
2227 case CFGA_COND_UNUSABLE
:
2228 if (frup
->cond
!= FRU_COND_FAILED
) {
2230 frup
->prev_cond
= frup
->cond
;
2231 frup
->cond
= FRU_COND_FAILED
;
2235 if (frup
->cond
!= FRU_COND_UNKNOWN
) {
2237 frup
->prev_cond
= frup
->cond
;
2238 frup
->cond
= FRU_COND_UNKNOWN
;
2242 if (*updated
== B_TRUE
) {
2243 ap_cond_time
= (uint64_t)(time(NULL
));
2244 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
2245 PICL_PROP_CONDITION_TIME
, (void *)&ap_cond_time
,
2246 sizeof (ap_cond_time
))) != PICL_SUCCESS
) {
2247 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
2248 PICL_PROP_CONDITION_TIME
, frup
->name
, rc
);
2252 return (PICL_SUCCESS
);
2256 * Volatile callback function to read fru state
2259 get_fru_state(ptree_rarg_t
*rarg
, void *buf
)
2262 hashdata_t
*hashptr
= NULL
;
2263 frutree_frunode_t
*frup
= NULL
;
2264 boolean_t state_change
= B_FALSE
;
2265 frutree_dr_arg_t dr_arg
;
2268 return (PICL_INVALIDARG
);
2271 if ((rc
= hash_lookup_entry(rarg
->nodeh
, (void **)&hashptr
)) !=
2276 frup
= FRUDATA_PTR(hashptr
);
2278 return (PICL_FAILURE
);
2281 /* return the cached value, if dr is in progress */
2282 (void) pthread_mutex_lock(&frup
->mutex
);
2283 if (frup
->dr_in_progress
) {
2284 (void) pthread_mutex_unlock(&frup
->mutex
);
2285 (void) strncpy((char *)buf
, fru_state
[frup
->state
],
2286 PICL_PROPNAMELEN_MAX
);
2287 return (PICL_SUCCESS
);
2289 (void) pthread_mutex_unlock(&frup
->mutex
);
2291 if ((rc
= update_fru_state(frup
, &state_change
)) != PICL_SUCCESS
) {
2292 FRUTREE_DEBUG2(EVENTS
, GET_FRU_STATE_ERR
, frup
->name
, rc
);
2293 /* return the cached value */
2294 (void) strncpy((char *)buf
, fru_state
[frup
->state
],
2295 PICL_PROPNAMELEN_MAX
);
2299 /* if there is a state change, handle the event */
2301 (void) pthread_mutex_lock(&frup
->mutex
);
2302 /* figure out if this is config/unconfig operation */
2303 if (frup
->state
== FRU_STATE_CONFIGURED
) {
2304 dr_arg
.action
= HANDLE_CONFIGURE
;
2306 } else if (frup
->state
== FRU_STATE_UNCONFIGURED
) {
2307 dr_arg
.action
= HANDLE_UNCONFIGURE
;
2310 (void) pthread_mutex_unlock(&frup
->mutex
);
2312 (void) pthread_mutex_lock(&ev_mutex
);
2313 if ((rc
= add_to_queue(dr_arg
)) != PICL_SUCCESS
) {
2314 (void) pthread_mutex_unlock(&ev_mutex
);
2315 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
,
2316 "dr_ap_state_chage", frup
->name
, rc
);
2318 (void) pthread_cond_signal(&ev_cond
);
2319 (void) pthread_mutex_unlock(&ev_mutex
);
2323 (void) strncpy((char *)buf
, fru_state
[frup
->state
],
2324 PICL_PROPNAMELEN_MAX
);
2326 return (PICL_SUCCESS
);
2330 * Volatile callback function to read fru condition
2333 get_fru_condition(ptree_rarg_t
*rarg
, void *buf
)
2336 frutree_dr_arg_t dr_arg
;
2337 hashdata_t
*hashptr
= NULL
;
2338 frutree_frunode_t
*frup
= NULL
;
2339 boolean_t cond_changed
= B_FALSE
;
2342 return (PICL_INVALIDARG
);
2345 if ((rc
= hash_lookup_entry(rarg
->nodeh
, (void **)&hashptr
)) !=
2350 frup
= FRUDATA_PTR(hashptr
);
2352 return (PICL_FAILURE
);
2355 /* return the cached value, if dr is in progress */
2356 (void) pthread_mutex_lock(&frup
->mutex
);
2357 if (frup
->dr_in_progress
) {
2358 (void) pthread_mutex_unlock(&frup
->mutex
);
2359 (void) strncpy((char *)buf
, fru_cond
[frup
->cond
],
2360 PICL_PROPNAMELEN_MAX
);
2361 return (PICL_SUCCESS
);
2364 (void) pthread_mutex_unlock(&frup
->mutex
);
2366 if ((rc
= update_fru_condition(frup
, &cond_changed
)) != PICL_SUCCESS
) {
2367 FRUTREE_DEBUG2(EVENTS
, GET_FRU_COND_ERR
, frup
->name
, rc
);
2368 /* return the cached value */
2369 (void) strncpy((char *)buf
, fru_cond
[frup
->cond
],
2370 PICL_PROPNAMELEN_MAX
);
2374 dr_arg
.action
= POST_COND_EVENT
;
2376 (void) pthread_mutex_lock(&ev_mutex
);
2377 if ((rc
= add_to_queue(dr_arg
)) != PICL_SUCCESS
) {
2378 (void) pthread_mutex_unlock(&ev_mutex
);
2379 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
,
2380 "condition event", frup
->name
, rc
);
2382 (void) pthread_cond_signal(&ev_cond
);
2383 (void) pthread_mutex_unlock(&ev_mutex
);
2387 /* if there is a condition change, post picl event */
2388 (void) strncpy((char *)buf
, fru_cond
[frup
->cond
],
2389 PICL_PROPNAMELEN_MAX
);
2391 return (PICL_SUCCESS
);
2395 free_cache(frutree_cache_t
*cachep
)
2397 frutree_cache_t
*tmp
= NULL
;
2401 while (cachep
!= NULL
) {
2403 cachep
= cachep
->next
;
2409 * traverse the /platform tree in PICL tree to create logical devices table
2412 probe_platform_tree(frutree_frunode_t
*frup
, frutree_device_args_t
**devp
)
2415 picl_nodehdl_t refhdl
= 0;
2416 char class[PICL_CLASSNAMELEN_MAX
];
2417 frutree_device_args_t
*device
= NULL
;
2418 picl_prophdl_t tblprophdl
;
2419 picl_prophdl_t dev_tblhdl
, env_tblhdl
= 0;
2422 return (PICL_FAILURE
);
2424 device
= *(frutree_device_args_t
**)devp
;
2425 if (device
== NULL
) {
2426 return (PICL_FAILURE
);
2429 /* traverse thru platform tree and add entries to Devices table */
2430 if ((refhdl
= get_reference_handle(frup
->frunodeh
)) == 0) {
2431 return (PICL_NODENOTFOUND
);
2434 /* create Devices table property */
2435 if ((rc
= create_property(PICL_PTYPE_TABLE
, PICL_READ
,
2436 sizeof (picl_prophdl_t
), PICL_PROP_DEVICES
, NULLREAD
,
2437 NULLWRITE
, frup
->frunodeh
, &tblprophdl
, &dev_tblhdl
)) !=
2442 if ((rc
= ptree_get_propval_by_name(refhdl
, PICL_PROP_CLASSNAME
,
2443 class, sizeof (class))) != PICL_SUCCESS
) {
2447 if ((rc
= create_table_entry(dev_tblhdl
, refhdl
, class)) !=
2452 /* create Environment devices table property */
2453 if ((rc
= create_property(PICL_PTYPE_TABLE
, PICL_READ
,
2454 sizeof (picl_prophdl_t
), PICL_PROP_ENV
, NULLREAD
,
2455 NULLWRITE
, frup
->frunodeh
, &tblprophdl
, &env_tblhdl
)) !=
2460 device
->nodeh
= refhdl
;
2461 device
->device_tblhdl
= dev_tblhdl
;
2462 device
->env_tblhdl
= env_tblhdl
;
2463 device
->first
= NULL
;
2464 device
->last
= NULL
;
2465 device
->create_cache
= B_FALSE
;
2467 /* probe using platform tree info */
2468 if ((rc
= do_action(refhdl
, CREATE_DEVICES_ENTRIES
,
2469 device
)) != PICL_SUCCESS
) {
2470 free_cache(device
->first
);
2473 return (PICL_SUCCESS
);
2477 * create temp conf file to pass it to picld util lib to create
2478 * nodes under the fru
2481 create_fru_children(frutree_frunode_t
*frup
, frutree_device_args_t device
)
2485 char conffile
[MAXPATHLEN
];
2486 char dir
[MAXPATHLEN
];
2487 struct stat file_stat
;
2488 char version
[BUF_SIZE
];
2489 frutree_cache_t
*cachep
= NULL
;
2491 cachep
= device
.first
;
2492 if (cachep
== NULL
) {
2493 return (PICL_SUCCESS
);
2496 /* create the configuration file for the fru */
2497 (void) snprintf(dir
, MAXPATHLEN
, "%s%s", TEMP_DIR
, frup
->name
);
2498 bzero(&file_stat
, sizeof (file_stat
));
2499 if (stat(conffile
, &file_stat
) == -1) {
2500 if (mkdir(conffile
, 0755) == -1) {
2501 return (PICL_FAILURE
);
2505 (void) snprintf(conffile
, MAXPATHLEN
, "%s/%s", dir
, PROBE_FILE
);
2506 if ((fd
= open(conffile
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644)) == -1) {
2508 return (PICL_FAILURE
);
2511 (void) snprintf(version
, sizeof (version
), "VERSION %d.0",
2512 PTREE_PROPINFO_VERSION
);
2513 if (write(fd
, version
, strlen(version
)) != strlen(version
)) {
2514 (void) remove(conffile
);
2517 return (PICL_FAILURE
);
2520 /* traverse thru each cache entry and append to conf file */
2521 while (cachep
!= NULL
) {
2522 if (write(fd
, cachep
->buf
, strlen(cachep
->buf
))
2523 != strlen(cachep
->buf
)) {
2525 (void) remove(conffile
);
2527 return (PICL_FAILURE
);
2529 cachep
= cachep
->next
;
2533 /* create child nodes for fru using the conffile created */
2534 if ((rc
= picld_pluginutil_parse_config_file(frup
->frunodeh
,
2535 conffile
)) != PICL_SUCCESS
) {
2536 (void) remove(conffile
);
2540 (void) remove(conffile
);
2543 if ((rc
= fru_init(frup
)) != PICL_SUCCESS
) {
2546 return (PICL_SUCCESS
);
2550 * probes libdevinfo and create the port nodes under a fru
2551 * probes for any scsi devices under a fru
2554 probe_fru(frutree_frunode_t
*frup
, boolean_t load_drivers
)
2557 picl_nodehdl_t child
, loch
;
2558 char slot_type
[PICL_PROPNAMELEN_MAX
];
2559 char devfs_path
[PICL_PROPNAMELEN_MAX
];
2560 char probe_path
[PICL_PROPNAMELEN_MAX
];
2561 frutree_device_args_t
*device
= NULL
;
2564 return (PICL_FAILURE
);
2566 FRUTREE_DEBUG1(EVENTS
, "probing :%s", frup
->name
);
2568 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
2569 &loch
, sizeof (loch
))) != PICL_SUCCESS
) {
2573 bzero(devfs_path
, PICL_PROPNAMELEN_MAX
);
2574 bzero(probe_path
, PICL_PROPNAMELEN_MAX
);
2575 if ((rc
= ptree_get_propval_by_name(loch
, PICL_PROP_DEVFS_PATH
,
2576 devfs_path
, sizeof (devfs_path
))) == PICL_SUCCESS
) {
2577 device
= (frutree_device_args_t
*)malloc(
2578 sizeof (frutree_device_args_t
));
2579 if (device
== NULL
) {
2580 return (PICL_NOSPACE
);
2582 device
->first
= NULL
;
2583 device
->last
= NULL
;
2584 (void) probe_platform_tree(frup
, &device
);
2585 free_cache(device
->first
);
2590 * if parent has NULL probe-path, skip probing this fru
2591 * probe only child locations (if present).
2592 * if probe-path is not present use devfs-path as path for
2595 rc
= ptree_get_propval_by_name(loch
, PICL_PROP_PROBE_PATH
,
2596 probe_path
, sizeof (probe_path
));
2597 if (rc
!= PICL_SUCCESS
) {
2598 if (!devfs_path
[0]) { /* devfspath is also not present */
2599 return (PICL_SUCCESS
); /* nothing to probe */
2601 /* use devfs-path as path for probing */
2602 if ((rc
= get_fru_path(devfs_path
, frup
)) !=
2608 /* NULL path, skip probing this fru */
2609 if (strlen(probe_path
) == 0) {
2610 rc
= fru_init(frup
); /* probe its children */
2613 /* valid probe-path */
2614 if ((rc
= get_fru_path(probe_path
, frup
)) !=
2621 /* children present already, no need to probe libdevinfo */
2622 rc
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_CHILD
,
2623 &child
, sizeof (picl_nodehdl_t
));
2624 if (rc
== PICL_SUCCESS
) { /* child present */
2625 if ((rc
= fru_init(frup
)) != PICL_SUCCESS
) {
2628 /* now create the scsi nodes for this fru */
2629 if ((rc
= probe_for_scsi_frus(frup
)) != PICL_SUCCESS
) {
2632 return (PICL_SUCCESS
);
2635 if (ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
2636 &loch
, sizeof (loch
)) != PICL_SUCCESS
) {
2639 if ((rc
= ptree_get_propval_by_name(loch
, PICL_PROP_SLOT_TYPE
,
2640 slot_type
, sizeof (slot_type
))) != PICL_SUCCESS
) {
2643 /* no need to probe further for scsi frus */
2644 if (strcmp(slot_type
, SANIBEL_SCSI_SLOT
) == 0 ||
2645 strcmp(slot_type
, SANIBEL_IDE_SLOT
) == 0) {
2646 return (PICL_SUCCESS
);
2649 device
= (frutree_device_args_t
*)malloc(
2650 sizeof (frutree_device_args_t
));
2651 if (device
== NULL
) {
2652 return (PICL_NOSPACE
);
2654 device
->first
= NULL
;
2655 device
->last
= NULL
;
2657 if ((rc
= probe_libdevinfo(frup
, &device
, load_drivers
)) !=
2659 free_cache(device
->first
);
2664 if (device
->first
!= NULL
) {
2665 if ((rc
= create_fru_children(frup
, *device
)) != PICL_SUCCESS
) {
2666 free_cache(device
->first
);
2671 free_cache(device
->first
);
2674 /* now create the scsi nodes for this fru */
2675 if ((rc
= probe_for_scsi_frus(frup
)) != PICL_SUCCESS
) {
2678 return (PICL_SUCCESS
);
2682 * callback function for ptree_walk_tree_by_class,
2683 * used to update hashtable during DR_HINT_REMOVE event
2687 frutree_update_hash(picl_nodehdl_t nodeh
, void *c_args
)
2689 picl_errno_t rc
= 0;
2690 if ((rc
= hash_remove_entry(nodeh
)) != PICL_SUCCESS
) {
2693 return (PICL_WALK_CONTINUE
);
2697 * routine to handle DR_HINT_REMOVE
2700 handle_fru_remove(frutree_frunode_t
*frup
)
2702 picl_errno_t rc
= PICL_SUCCESS
;
2705 return (PICL_FAILURE
);
2708 if ((rc
= ptree_walk_tree_by_class(frup
->frunodeh
,
2709 NULL
, NULL
, frutree_update_hash
)) != PICL_SUCCESS
) {
2712 (void) ptree_delete_node(frup
->frunodeh
);
2713 (void) ptree_destroy_node(frup
->frunodeh
);
2714 if ((rc
= hash_remove_entry(frup
->frunodeh
)) !=
2718 return (PICL_SUCCESS
);
2721 /* remove State and Condition props for all the nodes under fru */
2724 frutree_handle_unconfigure(picl_nodehdl_t nodeh
, void *c_args
)
2726 picl_errno_t rc
= 0;
2727 picl_prophdl_t proph
;
2728 char class[PICL_PROPNAMELEN_MAX
];
2730 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_STATE
,
2731 &proph
) == PICL_SUCCESS
) {
2732 (void) ptree_delete_prop(proph
);
2733 (void) ptree_destroy_prop(proph
);
2735 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_STATUS_TIME
,
2736 &proph
) == PICL_SUCCESS
) {
2737 (void) ptree_delete_prop(proph
);
2738 (void) ptree_destroy_prop(proph
);
2741 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_CLASSNAME
,
2742 class, sizeof (class))) != PICL_SUCCESS
) {
2746 if (strcmp(class, PICL_CLASS_PORT
) == 0) {
2747 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_CONDITION
,
2748 &proph
) == PICL_SUCCESS
) {
2749 (void) ptree_delete_prop(proph
);
2750 (void) ptree_destroy_prop(proph
);
2752 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_CONDITION_TIME
,
2753 &proph
) == PICL_SUCCESS
) {
2754 (void) ptree_delete_prop(proph
);
2755 (void) ptree_destroy_prop(proph
);
2757 /* delete devices table */
2758 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_DEVICES
,
2759 &proph
) == PICL_SUCCESS
) {
2760 (void) ptree_delete_prop(proph
);
2761 (void) ptree_destroy_prop(proph
);
2764 return (PICL_WALK_CONTINUE
);
2768 * traverse thru each node fru node and do cleanup
2771 handle_fru_unconfigure(frutree_frunode_t
*frup
)
2773 picl_errno_t rc
= 0, retval
= 0;
2774 picl_prophdl_t proph
;
2775 picl_nodehdl_t childh
, peerh
, nodeh
;
2776 hashdata_t
*hashptr
= NULL
;
2777 frutree_frunode_t
*child_frup
= NULL
;
2778 char class[PICL_PROPNAMELEN_MAX
];
2781 return (PICL_FAILURE
);
2784 /* delete devices table */
2785 if (ptree_get_prop_by_name(frup
->frunodeh
, PICL_PROP_DEVICES
,
2786 &proph
) == PICL_SUCCESS
) {
2787 (void) ptree_delete_prop(proph
);
2788 (void) ptree_destroy_prop(proph
);
2791 /* delete Environment devices table */
2792 if (ptree_get_prop_by_name(frup
->frunodeh
, PICL_PROP_ENV
,
2793 &proph
) == PICL_SUCCESS
) {
2794 (void) ptree_delete_prop(proph
);
2795 (void) ptree_destroy_prop(proph
);
2798 if ((rc
= ptree_walk_tree_by_class(frup
->frunodeh
,
2799 NULL
, NULL
, frutree_handle_unconfigure
)) != PICL_SUCCESS
) {
2803 /* remove all the fru nodes under the child locations */
2804 retval
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_CHILD
,
2805 &peerh
, sizeof (peerh
));
2806 while (retval
== PICL_SUCCESS
) {
2808 retval
= ptree_get_propval_by_name(nodeh
, PICL_PROP_PEER
,
2809 &peerh
, sizeof (peerh
));
2810 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_CLASSNAME
,
2811 class, sizeof (class))) != PICL_SUCCESS
) {
2815 if (strcmp(class, PICL_CLASS_PORT
) == 0) {
2819 /* if the child location has fru, delete the fru */
2820 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_CHILD
,
2821 &childh
, sizeof (childh
)) != PICL_SUCCESS
) {
2825 /* child is present under the location */
2826 if ((rc
= hash_lookup_entry(childh
, (void **)&hashptr
)) !=
2830 child_frup
= FRUDATA_PTR(hashptr
);
2831 (void) handle_fru_remove(child_frup
);
2833 return (PICL_SUCCESS
);
2837 * create the properties under the fru
2840 create_fru_props(frutree_frunode_t
*frup
)
2843 uint64_t ap_status_time
= 0;
2844 boolean_t state_change
;
2846 /* create state props */
2847 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
2848 PICL_READ
+ PICL_VOLATILE
, PICL_PROPNAMELEN_MAX
,
2849 PICL_PROP_STATE
, get_fru_state
, NULLWRITE
,
2850 frup
->frunodeh
, NULL
, fru_state
[frup
->state
])) !=
2852 FRUTREE_DEBUG3(EVENTS
, PTREE_CREATE_PROP_FAILED
,
2853 PICL_PROP_STATE
, frup
->name
, rc
);
2856 ap_status_time
= (uint64_t)(time(NULL
));
2857 if ((rc
= create_property(PICL_PTYPE_TIMESTAMP
, PICL_READ
,
2858 sizeof (ap_status_time
), PICL_PROP_STATUS_TIME
,
2859 NULLREAD
, NULLWRITE
, frup
->frunodeh
,
2860 NULL
, &ap_status_time
)) != PICL_SUCCESS
) {
2861 FRUTREE_DEBUG3(EVENTS
, PTREE_CREATE_PROP_FAILED
,
2862 PICL_PROP_STATUS_TIME
, frup
->name
, rc
);
2865 if ((rc
= update_fru_state(frup
, &state_change
)) != PICL_SUCCESS
) {
2866 FRUTREE_DEBUG2(EVENTS
, GET_FRU_STATE_ERR
, frup
->name
, rc
);
2870 /* create condition props */
2871 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
2872 PICL_READ
+ PICL_VOLATILE
, PICL_PROPNAMELEN_MAX
,
2873 PICL_PROP_CONDITION
, get_fru_condition
, NULLWRITE
,
2874 frup
->frunodeh
, NULL
, fru_cond
[frup
->cond
])) !=
2876 FRUTREE_DEBUG3(EVENTS
, PTREE_CREATE_PROP_FAILED
,
2877 PICL_PROP_CONDITION
, frup
->name
, rc
);
2879 if ((rc
= create_property(PICL_PTYPE_TIMESTAMP
, PICL_READ
,
2880 sizeof (ap_status_time
), PICL_PROP_CONDITION_TIME
,
2881 NULLREAD
, NULLWRITE
, frup
->frunodeh
, NULL
,
2882 &ap_status_time
)) != PICL_SUCCESS
) {
2883 FRUTREE_DEBUG3(EVENTS
, PTREE_CREATE_PROP_FAILED
,
2884 PICL_PROP_CONDITION_TIME
, frup
->name
, rc
);
2887 if ((rc
= update_fru_condition(frup
, &state_change
)) != PICL_SUCCESS
) {
2888 FRUTREE_DEBUG2(EVENTS
, GET_FRU_COND_ERR
, frup
->name
, rc
);
2892 /* create admin lock prop */
2893 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
2894 PICL_READ
+ PICL_WRITE
, PICL_PROPNAMELEN_MAX
,
2895 PICL_PROP_ADMIN_LOCK
, NULLREAD
, NULLWRITE
,
2896 frup
->frunodeh
, NULL
, PICL_ADMINLOCK_DISABLED
)) !=
2898 FRUTREE_DEBUG3(EVENTS
, PTREE_CREATE_PROP_FAILED
,
2899 PICL_PROP_ADMIN_LOCK
, frup
->name
, rc
);
2905 * calls libcfgadm API to do a connect on a location
2908 connect_fru(frutree_locnode_t
*locp
)
2911 cfga_err_t ap_list_err
;
2912 cfga_flags_t flags
= 0;
2913 boolean_t state_change
;
2914 uint64_t ap_status_time
;
2919 return (PICL_FAILURE
);
2921 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
2922 PICLEVENTARGVAL_CONNECTING
, loc_state
[locp
->state
],
2923 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
2924 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
2925 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
2928 (void) pthread_mutex_lock(&locp
->mutex
);
2929 locp
->dr_in_progress
= B_TRUE
;
2930 (void) pthread_mutex_unlock(&locp
->mutex
);
2932 if (frutree_debug
& PERF_DATA
) {
2933 start
= gethrtime();
2935 ap_list_err
= config_change_state(CFGA_CMD_CONNECT
, 1, &(locp
->name
),
2936 NULL
, NULL
, NULL
, NULL
, flags
);
2938 if (frutree_debug
& PERF_DATA
) {
2940 FRUTREE_DEBUG2(PERF_DATA
, "time for connect on %s: %lld nsec",
2941 locp
->name
, (end
- start
));
2943 if (ap_list_err
!= CFGA_OK
) {
2944 (void) pthread_mutex_lock(&locp
->mutex
);
2945 locp
->dr_in_progress
= B_FALSE
;
2946 (void) pthread_mutex_unlock(&locp
->mutex
);
2948 /* release mutex before updating state */
2949 (void) update_loc_state(locp
, &state_change
);
2950 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
2951 loc_state
[locp
->state
], PICLEVENTARGVAL_CONNECTING
,
2952 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
2953 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
2954 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
2956 if (locp
->state
== LOC_STATE_CONNECTED
) {
2957 /* wakeup threads sleeping on this condition */
2958 (void) pthread_mutex_lock(&locp
->mutex
);
2959 (void) pthread_cond_broadcast(&locp
->cond_cv
);
2960 (void) pthread_mutex_unlock(&locp
->mutex
);
2961 return (PICL_SUCCESS
);
2963 return (cfg2picl_errmap
[ap_list_err
][1]);
2965 (void) pthread_mutex_lock(&locp
->mutex
);
2967 locp
->dr_in_progress
= B_FALSE
;
2968 locp
->prev_state
= LOC_STATE_DISCONNECTED
;
2969 locp
->state
= LOC_STATE_CONNECTED
;
2970 ap_status_time
= (uint64_t)(time(NULL
));
2971 if ((rc
= ptree_update_propval_by_name(locp
->locnodeh
,
2972 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
2973 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
2974 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
2975 PICL_PROP_STATUS_TIME
, locp
->name
, rc
);
2978 /* wakeup threads sleeping on this condition */
2979 (void) pthread_cond_broadcast(&locp
->cond_cv
);
2980 (void) pthread_mutex_unlock(&locp
->mutex
);
2982 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
2983 PICLEVENTARGVAL_CONNECTED
, PICLEVENTARGVAL_CONNECTING
,
2984 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
2985 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
2986 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
2988 return (PICL_SUCCESS
);
2992 * calls libcfgadm API to do a disconnect on a location
2995 disconnect_fru(frutree_locnode_t
*locp
)
2998 picl_nodehdl_t childh
;
2999 hashdata_t
*hashptr
= NULL
;
3002 hrtime_t start
, end
;
3003 cfga_err_t ap_list_err
;
3004 cfga_flags_t flags
= 0;
3005 boolean_t state_change
;
3006 uint64_t ap_status_time
;
3007 frutree_frunode_t
*frup
= NULL
;
3010 return (PICL_FAILURE
);
3013 (void) pthread_mutex_lock(&locp
->mutex
);
3014 if (locp
->state
== LOC_STATE_DISCONNECTED
) {
3015 (void) pthread_mutex_unlock(&locp
->mutex
);
3016 return (PICL_SUCCESS
);
3018 (void) pthread_mutex_unlock(&locp
->mutex
);
3020 /* get the child fru information */
3021 if (ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_CHILD
,
3022 &childh
, sizeof (childh
)) == PICL_SUCCESS
) {
3023 if (hash_lookup_entry(childh
, (void **)&hashptr
) ==
3025 frup
= FRUDATA_PTR(hashptr
);
3030 return (PICL_SUCCESS
);
3033 (void) pthread_mutex_lock(&frup
->mutex
);
3035 (void) gettimeofday(&tp
, NULL
);
3036 to
.tv_sec
= tp
.tv_sec
+ frutree_drwait_time
;
3037 to
.tv_nsec
= tp
.tv_usec
* 1000;
3039 if (frup
->state
!= FRU_STATE_UNCONFIGURED
) {
3040 (void) pthread_cond_timedwait(&frup
->cond_cv
,
3044 if (frup
->state
!= FRU_STATE_UNCONFIGURED
) {
3045 FRUTREE_DEBUG1(LOG_ERR
, "SUNW_frutree:Disconnect operation on"
3046 " %s failed", locp
->name
);
3047 (void) pthread_mutex_unlock(&frup
->mutex
);
3048 return (PICL_FAILURE
);
3050 (void) pthread_mutex_unlock(&frup
->mutex
);
3052 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3053 PICLEVENTARGVAL_DISCONNECTING
, loc_state
[locp
->state
],
3054 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
3055 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3056 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3059 (void) pthread_mutex_lock(&locp
->mutex
);
3060 locp
->dr_in_progress
= B_TRUE
;
3061 (void) pthread_mutex_unlock(&locp
->mutex
);
3063 if (frutree_debug
& PERF_DATA
) {
3064 start
= gethrtime();
3067 ap_list_err
= config_change_state(CFGA_CMD_DISCONNECT
, 1, &(locp
->name
),
3068 NULL
, NULL
, NULL
, NULL
, flags
);
3069 if (frutree_debug
& PERF_DATA
) {
3071 FRUTREE_DEBUG2(PERF_DATA
, "time for disconnect on %s: %lld ns",
3072 locp
->name
, (end
- start
));
3074 if (ap_list_err
!= CFGA_OK
) {
3075 (void) pthread_mutex_lock(&locp
->mutex
);
3076 locp
->dr_in_progress
= B_FALSE
;
3077 (void) pthread_mutex_unlock(&locp
->mutex
);
3079 /* release mutex before updating state */
3080 (void) update_loc_state(locp
, &state_change
);
3081 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3082 loc_state
[locp
->state
], PICLEVENTARGVAL_DISCONNECTING
,
3083 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
3084 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3085 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3087 (void) pthread_mutex_lock(&locp
->mutex
);
3088 if (locp
->state
== LOC_STATE_DISCONNECTED
) {
3089 (void) pthread_mutex_unlock(&locp
->mutex
);
3090 return (PICL_SUCCESS
);
3092 (void) pthread_mutex_unlock(&locp
->mutex
);
3093 return (cfg2picl_errmap
[ap_list_err
][1]);
3095 (void) pthread_mutex_lock(&locp
->mutex
);
3096 locp
->dr_in_progress
= B_FALSE
;
3097 locp
->prev_state
= LOC_STATE_CONNECTED
;
3098 locp
->state
= LOC_STATE_DISCONNECTED
;
3099 ap_status_time
= (uint64_t)(time(NULL
));
3100 if ((rc
= ptree_update_propval_by_name(locp
->locnodeh
,
3101 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
3102 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
3103 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
3104 PICL_PROP_STATUS_TIME
, locp
->name
, rc
);
3106 (void) pthread_mutex_unlock(&locp
->mutex
);
3108 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3109 PICLEVENTARGVAL_DISCONNECTED
, PICLEVENTARGVAL_DISCONNECTING
,
3110 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
3111 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3112 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3114 return (PICL_SUCCESS
);
3118 * Handle DR_INCOMING_RES event
3121 handle_fru_configure(frutree_frunode_t
*frup
)
3124 boolean_t cond_changed
;
3129 if ((rc
= probe_fru(frup
, B_FALSE
)) != PICL_SUCCESS
) {
3130 FRUTREE_DEBUG2(EVENTS
, PROBE_FRU_ERR
, frup
->name
, rc
);
3133 /* update the fru condition */
3134 (void) update_fru_condition(frup
, &cond_changed
);
3136 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
3137 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
3138 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3139 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3140 frup
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
3144 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3145 fru_state
[frup
->state
], fru_state
[frup
->prev_state
],
3146 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3147 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3148 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3153 * call libcfgadm API to configure a fru
3154 * (Handle DR_INCOMING_RES event)
3157 configure_fru(frutree_frunode_t
*frup
, cfga_flags_t flags
)
3160 picl_nodehdl_t parenth
;
3163 hrtime_t start
, end
;
3164 cfga_err_t ap_list_err
;
3165 uint64_t ap_status_time
;
3166 hashdata_t
*hashptr
= NULL
;
3167 frutree_locnode_t
*locp
= NULL
;
3168 boolean_t state_change
, cond_changed
;
3171 return (PICL_FAILURE
);
3174 (void) pthread_mutex_lock(&frup
->mutex
);
3175 if (frup
->state
== FRU_STATE_CONFIGURED
) {
3176 (void) pthread_mutex_unlock(&frup
->mutex
);
3177 ap_list_err
= config_change_state(CFGA_CMD_CONFIGURE
, 1,
3178 &(frup
->name
), NULL
, NULL
, NULL
, NULL
, flags
);
3179 return (PICL_SUCCESS
);
3181 (void) pthread_mutex_unlock(&frup
->mutex
);
3183 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
3184 &parenth
, sizeof (parenth
))) != PICL_SUCCESS
) {
3188 if ((rc
= hash_lookup_entry(parenth
, (void **)&hashptr
)) !=
3192 locp
= LOCDATA_PTR(hashptr
);
3194 return (PICL_FAILURE
);
3197 (void) pthread_mutex_lock(&locp
->mutex
);
3199 (void) gettimeofday(&tp
, NULL
);
3200 to
.tv_sec
= tp
.tv_sec
+ frutree_drwait_time
;
3201 to
.tv_nsec
= tp
.tv_usec
* 1000;
3203 /* wait for sometime for location to get connected */
3204 if (locp
->state
!= LOC_STATE_CONNECTED
) {
3205 (void) pthread_cond_timedwait(&locp
->cond_cv
,
3209 if (locp
->state
!= LOC_STATE_CONNECTED
) { /* give up */
3210 FRUTREE_DEBUG1(EVENTS
, "SUNW_frutree:Configure operation on"
3211 " %s failed as loc is not connected", locp
->name
);
3212 (void) pthread_mutex_unlock(&locp
->mutex
);
3213 return (PICL_FAILURE
);
3215 (void) pthread_mutex_unlock(&locp
->mutex
);
3217 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3218 PICLEVENTARGVAL_CONFIGURING
, fru_state
[frup
->state
],
3219 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3220 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3221 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3224 (void) pthread_mutex_lock(&frup
->mutex
);
3225 frup
->dr_in_progress
= B_TRUE
;
3226 (void) pthread_mutex_unlock(&frup
->mutex
);
3228 if (frutree_debug
& PERF_DATA
) {
3229 start
= gethrtime();
3231 ap_list_err
= config_change_state(CFGA_CMD_CONFIGURE
, 1,
3232 &(frup
->name
), NULL
, NULL
, NULL
, NULL
, flags
);
3234 if (frutree_debug
& PERF_DATA
) {
3236 FRUTREE_DEBUG2(PERF_DATA
, "time for configure on %s: %lld nsec",
3237 frup
->name
, (end
- start
));
3240 if (ap_list_err
!= CFGA_OK
) {
3241 (void) pthread_mutex_lock(&frup
->mutex
);
3242 frup
->dr_in_progress
= B_FALSE
;
3243 (void) pthread_mutex_unlock(&frup
->mutex
);
3244 /* release mutex before updating state */
3245 (void) update_fru_state(frup
, &state_change
);
3246 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3247 fru_state
[frup
->state
], PICLEVENTARGVAL_CONFIGURING
,
3248 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3249 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3250 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3252 /* update the fru condition */
3253 (void) update_fru_condition(frup
, &state_change
);
3255 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
3256 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
3257 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3258 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3259 frup
->name
, PICLEVENT_CONDITION_CHANGE
,
3263 return (cfg2picl_errmap
[ap_list_err
][1]);
3265 (void) pthread_mutex_lock(&frup
->mutex
);
3266 frup
->dr_in_progress
= B_FALSE
;
3267 frup
->prev_state
= FRU_STATE_UNCONFIGURED
;
3268 frup
->state
= FRU_STATE_CONFIGURED
;
3269 ap_status_time
= (uint64_t)(time(NULL
));
3270 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
3271 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
3272 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
3273 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
3274 PICL_PROP_STATUS_TIME
, frup
->name
, rc
);
3276 (void) pthread_mutex_unlock(&frup
->mutex
);
3278 if ((rc
= probe_fru(frup
, B_FALSE
)) != PICL_SUCCESS
) {
3279 FRUTREE_DEBUG2(FRUTREE_INIT
, PROBE_FRU_ERR
, frup
->name
, rc
);
3281 /* update the fru condition */
3282 (void) update_fru_condition(frup
, &cond_changed
);
3284 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
3285 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
3286 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3287 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3288 frup
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
3292 /* send the state change event */
3293 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3294 fru_state
[frup
->state
], PICLEVENTARGVAL_CONFIGURING
,
3295 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3296 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3297 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3299 return (PICL_SUCCESS
);
3303 * Handle DR_OUTGOING_RES event
3304 * (call libcfgadm API to unconfigure a fru)
3307 unconfigure_fru(frutree_frunode_t
*frup
, cfga_flags_t flags
)
3310 cfga_err_t ap_list_err
;
3311 boolean_t state_change
;
3312 uint64_t ap_status_time
;
3317 return (PICL_FAILURE
);
3320 (void) pthread_mutex_lock(&frup
->mutex
);
3321 if (frup
->state
== FRU_STATE_UNCONFIGURED
) {
3322 (void) pthread_mutex_unlock(&frup
->mutex
);
3323 return (PICL_SUCCESS
);
3325 (void) pthread_mutex_unlock(&frup
->mutex
);
3327 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3328 PICLEVENTARGVAL_UNCONFIGURING
, fru_state
[frup
->state
],
3329 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3330 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3331 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3334 (void) pthread_mutex_lock(&frup
->mutex
);
3335 while (frup
->busy
== B_TRUE
) {
3336 (void) pthread_cond_wait(&frup
->busy_cond_cv
,
3340 frup
->dr_in_progress
= B_TRUE
;
3341 (void) pthread_mutex_unlock(&frup
->mutex
);
3343 if (frutree_debug
& PERF_DATA
) {
3344 start
= gethrtime();
3346 ap_list_err
= config_change_state(CFGA_CMD_UNCONFIGURE
, 1,
3347 &(frup
->name
), NULL
, NULL
, NULL
, NULL
, flags
);
3348 if (frutree_debug
& PERF_DATA
) {
3350 FRUTREE_DEBUG2(PERF_DATA
, "time for unconfigure on %s: %lld ns",
3351 frup
->name
, (end
- start
));
3353 if (ap_list_err
!= CFGA_OK
) {
3355 * call configure again (workaround for
3356 * ENUM# to get generated for next attempt)
3358 config_change_state(CFGA_CMD_CONFIGURE
, 1,
3359 &(frup
->name
), NULL
, NULL
, NULL
, NULL
, flags
);
3361 (void) pthread_mutex_lock(&frup
->mutex
);
3362 frup
->dr_in_progress
= B_FALSE
;
3363 (void) pthread_mutex_unlock(&frup
->mutex
);
3365 /* release mutex before updating state */
3366 (void) update_fru_condition(frup
, &state_change
);
3368 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
3369 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
3370 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3371 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3372 frup
->name
, PICLEVENT_CONDITION_CHANGE
,
3376 (void) update_fru_state(frup
, &state_change
);
3377 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3378 fru_state
[frup
->state
], PICLEVENTARGVAL_UNCONFIGURING
,
3379 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3380 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3381 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3383 return (cfg2picl_errmap
[ap_list_err
][1]);
3386 (void) pthread_mutex_lock(&frup
->mutex
);
3388 frup
->dr_in_progress
= B_FALSE
;
3389 frup
->prev_state
= FRU_STATE_CONFIGURED
;
3390 frup
->state
= FRU_STATE_UNCONFIGURED
;
3391 ap_status_time
= (uint64_t)(time(NULL
));
3392 if ((rc
= ptree_update_propval_by_name(frup
->frunodeh
,
3393 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
3394 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
3395 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
3396 PICL_PROP_STATUS_TIME
, frup
->name
, rc
);
3398 /* wakeup threads sleeping on this condition */
3399 (void) pthread_cond_broadcast(&frup
->cond_cv
);
3400 (void) pthread_mutex_unlock(&frup
->mutex
);
3402 /* update the fru condition */
3403 if ((rc
= update_fru_condition(frup
, &state_change
)) != PICL_SUCCESS
) {
3404 FRUTREE_DEBUG2(EVENTS
, GET_FRU_STATE_ERR
,
3408 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
3409 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
3410 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3411 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3412 frup
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
3416 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
3417 PICLEVENTARGVAL_UNCONFIGURED
, PICLEVENTARGVAL_UNCONFIGURING
,
3418 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
3419 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
3420 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
3422 return (PICL_SUCCESS
);
3425 /* creates fru nodes with basic properties and sends out intializing events */
3427 create_fru_node(frutree_locnode_t
*locp
, frutree_frunode_t
**child_frupp
)
3430 hashdata_t
*fru_data
= NULL
;
3431 frutree_frunode_t
*frup
= NULL
;
3432 picl_nodehdl_t fruh
, child
;
3433 char slot_type
[PICL_PROPNAMELEN_MAX
];
3434 char fru_name
[PICL_PROPNAMELEN_MAX
];
3435 char apid_type
[PICL_PROPNAMELEN_MAX
];
3436 boolean_t fru_present
= B_FALSE
;
3437 boolean_t state_changed
= B_FALSE
;
3439 if (locp
->state
== LOC_STATE_EMPTY
) {
3440 return (PICL_SUCCESS
);
3443 /* check if fru is present or not */
3444 rc
= ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_CHILD
,
3445 &child
, sizeof (picl_nodehdl_t
));
3446 if (rc
== PICL_SUCCESS
) {
3447 fru_present
= B_TRUE
;
3449 (void) ptree_get_propval_by_name(child
, PICL_PROP_NAME
,
3450 fru_name
, sizeof (fru_name
));
3453 /* create fru node */
3454 if (fru_present
== B_FALSE
) {
3455 (void) strncpy(fru_name
, locp
->name
, sizeof (fru_name
));
3456 if ((rc
= ptree_create_node(fru_name
, PICL_CLASS_FRU
,
3457 &fruh
)) != PICL_SUCCESS
) {
3462 /* initialize internal data structures */
3463 if ((rc
= make_fru_data(fru_name
, &fru_data
)) != PICL_SUCCESS
) {
3466 frup
= FRUDATA_PTR(fru_data
);
3468 frup
->frunodeh
= fruh
;
3469 frup
->cpu_node
= locp
->cpu_node
;
3470 frup
->state_mgr
= locp
->state_mgr
;
3471 *child_frupp
= frup
;
3473 if ((rc
= hash_add_entry(fruh
, (void *)(fru_data
))) != PICL_SUCCESS
) {
3474 (void) ptree_destroy_node(fruh
);
3475 free_data(FRU_TYPE
, (fru_data
));
3479 if (locp
->state_mgr
== STATIC_LOC
) {
3480 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
3481 PICL_PROP_SLOT_TYPE
, slot_type
,
3482 sizeof (slot_type
))) == PICL_SUCCESS
) {
3483 (void) strncpy(apid_type
, slot_type
,
3484 sizeof (apid_type
));
3488 /* create fru type property */
3489 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
3490 PICL_PROPNAMELEN_MAX
, PICL_PROP_FRU_TYPE
, NULLREAD
,
3491 NULLWRITE
, fruh
, NULL
, apid_type
)) !=
3493 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
3494 PICL_PROP_FRU_TYPE
, frup
->name
, rc
);
3497 if (fru_present
== B_FALSE
) {
3498 if ((rc
= ptree_add_node(locp
->locnodeh
, fruh
)) !=
3500 (void) ptree_destroy_node(fruh
);
3501 (void) hash_remove_entry(fruh
);
3506 if (locp
->state_mgr
== PLUGIN_PVT
) {
3507 (void) update_fru_state(frup
, &state_changed
);
3508 return (PICL_SUCCESS
);
3511 if ((rc
= create_fru_props(frup
)) != PICL_SUCCESS
) {
3514 return (PICL_SUCCESS
);
3518 add_node2cache(picl_nodehdl_t nodeh
, char *class, frutree_cache_t
**cacheptr
)
3522 char driver
[PICL_PROPNAMELEN_MAX
];
3523 char bus_addr
[PICL_PROPNAMELEN_MAX
];
3524 char devfs_path
[PICL_PROPNAMELEN_MAX
];
3525 char node_name
[PICL_PROPNAMELEN_MAX
];
3526 char port_type
[PICL_PROPNAMELEN_MAX
];
3527 char label
[PICL_PROPNAMELEN_MAX
];
3528 frutree_cache_t
*cachep
= NULL
;
3530 if (strcmp(class, SANIBEL_NETWORK_PORT
) == 0) {
3531 (void) strncpy(label
, SANIBEL_NETWORK_LABEL
, sizeof (label
));
3532 (void) strncpy(node_name
, PICL_CLASS_PORT
, sizeof (node_name
));
3533 (void) strncpy(port_type
, SANIBEL_NETWORK_PORT
,
3534 sizeof (port_type
));
3536 } else if (strcmp(class, SANIBEL_SERIAL_PORT
) == 0) {
3537 (void) strncpy(label
, SANIBEL_SERIAL_PORT
, sizeof (label
));
3538 (void) strncpy(node_name
, PICL_CLASS_PORT
, sizeof (node_name
));
3539 (void) strncpy(port_type
, SANIBEL_SERIAL_PORT
,
3540 sizeof (port_type
));
3542 } else if (strcmp(class, SANIBEL_PARALLEL_PORT
) == 0) {
3543 (void) strncpy(label
, SANIBEL_PARALLEL_PORT
, sizeof (label
));
3544 (void) strncpy(node_name
, PICL_CLASS_PORT
, sizeof (node_name
));
3545 (void) strncpy(port_type
, SANIBEL_PARALLEL_PORT
,
3546 sizeof (port_type
));
3549 return (PICL_FAILURE
);
3552 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_INSTANCE
,
3553 &instance
, sizeof (instance
))) != PICL_SUCCESS
) {
3557 /* load the driver */
3559 attach_driver(driver
);
3562 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_DEVFS_PATH
,
3563 devfs_path
, sizeof (devfs_path
))) != PICL_SUCCESS
) {
3567 /* get either bus address or unit address */
3568 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_BUS_ADDR
, bus_addr
,
3569 sizeof (bus_addr
))) != PICL_SUCCESS
) {
3570 if ((rc
= ptree_get_propval_by_name(nodeh
,
3571 PICL_PROP_UNIT_ADDRESS
, bus_addr
,
3572 sizeof (bus_addr
))) != PICL_SUCCESS
) {
3577 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_DRIVER_NAME
,
3578 driver
, sizeof (driver
))) != PICL_SUCCESS
) {
3582 cachep
= (frutree_cache_t
*)malloc(sizeof (frutree_cache_t
));
3583 if (NULL
== cachep
) {
3584 return (PICL_NOSPACE
);
3586 cachep
->buf
[0] = '\0';
3588 /* update the cache buffer in PICL configuration format */
3589 (void) snprintf(cachep
->buf
, sizeof (cachep
->buf
),
3591 "\t%s %s %s %s 0 \"%s %d\"\n"
3592 "\t%s %s %s %s 0 \"%s\"\n"
3593 "\t%s %s %s %s 1 %d\n"
3594 "\t%s %s %s %s 0 \"%s\"\n"
3595 "\t%s %s %s %s 0 \"%s\"\n"
3597 "NODE", driver
, instance
, node_name
,
3598 "PROP", PICL_PROP_LABEL
, "string", "r", label
, instance
,
3599 "PROP", PICL_PROP_BUS_ADDR
, "string", "r", bus_addr
,
3600 "PROP", PICL_PROP_GEO_ADDR
, "uint", "r", instance
,
3601 "PROP", PICL_PROP_PORT_TYPE
, "string", "r", port_type
,
3602 "PROP", PICL_PROP_DEVFS_PATH
, "string", "r", devfs_path
,
3605 return (PICL_SUCCESS
);
3610 create_device_entries(picl_nodehdl_t nodeh
, void *c_args
)
3612 char class[PICL_CLASSNAMELEN_MAX
];
3613 char name
[PICL_PROPNAMELEN_MAX
];
3614 frutree_device_args_t
*device
= NULL
;
3615 frutree_cache_t
*cachep
= NULL
;
3617 if (c_args
== NULL
) { /* need not create cache */
3618 return (PICL_INVALIDARG
);
3620 device
= (frutree_device_args_t
*)c_args
;
3622 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_CLASSNAME
,
3623 class, sizeof (class)) != PICL_SUCCESS
) {
3624 return (PICL_WALK_CONTINUE
);
3627 /* add reference handle to Devices table */
3628 (void) create_table_entry(device
->device_tblhdl
, nodeh
, class);
3630 /* add to Environment Devices table */
3631 if (strcmp(class, PICL_CLASS_TEMPERATURE_SENSOR
) == 0) {
3632 if (device
->env_tblhdl
) {
3633 (void) create_table_entry(device
->env_tblhdl
, nodeh
,
3638 if (device
->create_cache
!= B_TRUE
) { /* dont create cache */
3639 return (PICL_WALK_CONTINUE
);
3642 /* compare the classname and create the cache entry for the child */
3643 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_NAME
, name
,
3644 sizeof (name
)) != PICL_SUCCESS
) {
3645 return (PICL_WALK_CONTINUE
);
3648 if (strcmp(name
, SANIBEL_PICLNODE_PARALLEL
) == 0) {
3649 (void) strncpy(class, SANIBEL_PARALLEL_PORT
, sizeof (class));
3652 if (add_node2cache(nodeh
, class, &cachep
) != PICL_SUCCESS
) {
3653 return (PICL_WALK_CONTINUE
);
3656 /* add cache to the linked list */
3657 if (cachep
!= NULL
) {
3658 cachep
->next
= NULL
;
3659 if (device
->first
== NULL
) { /* 1st node */
3660 device
->first
= cachep
;
3661 device
->last
= NULL
;
3663 } else if (device
->last
!= NULL
) { /* last node */
3664 device
->last
->next
= cachep
;
3665 device
->last
= cachep
;
3667 } else { /* 2nd node */
3668 device
->first
->next
= cachep
;
3669 device
->last
= cachep
;
3672 return (PICL_WALK_CONTINUE
);
3676 * determine the state manager for this node
3679 get_loc_type(frutree_locnode_t
*locp
)
3682 cfga_list_data_t
*list
= NULL
;
3683 char valbuf
[PICL_PROPNAMELEN_MAX
];
3684 char slot_type
[PICL_PROPNAMELEN_MAX
];
3686 if (locp
->state_mgr
!= UNKNOWN
)
3687 return (PICL_SUCCESS
);
3689 rc
= ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_STATE
,
3690 (void *)valbuf
, PICL_PROPNAMELEN_MAX
);
3691 if (rc
== PICL_SUCCESS
) { /* managed by platform specific plugin */
3692 locp
->state_mgr
= PLUGIN_PVT
;
3693 return (PICL_SUCCESS
);
3696 /* get the info from the libcfgadm interface */
3697 list
= (cfga_list_data_t
*)malloc(sizeof (cfga_list_data_t
));
3699 return (PICL_NOSPACE
);
3702 if ((rc
= get_cfgadm_state(list
, locp
->name
)) == PICL_SUCCESS
) {
3703 locp
->state_mgr
= CFGADM_AP
;
3705 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
3706 PICL_PROP_SLOT_TYPE
, slot_type
,
3707 sizeof (slot_type
))) != PICL_SUCCESS
) {
3711 if (strcmp(slot_type
, SANIBEL_SCSI_SLOT
) == 0 ||
3712 strcmp(slot_type
, SANIBEL_IDE_SLOT
) == 0) {
3714 * for scsi locations, if cfgadm ap is
3715 * not present, then consider it as device
3718 locp
->state_mgr
= CFGADM_AP
;
3721 * devices like PMC card doesnt showup in cfgadm
3723 locp
->state_mgr
= STATIC_LOC
;
3727 return (PICL_SUCCESS
);
3731 * Initialize the location node.(create all the props)
3734 location_init(frutree_locnode_t
*locp
)
3737 boolean_t state_change
;
3738 uint64_t ap_status_time
= 0;
3739 char valbuf
[PICL_PROPNAMELEN_MAX
];
3741 /* check if it is a CPU location node or not */
3742 if (ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_NAME
,
3743 (void *)valbuf
, PICL_PROPNAMELEN_MAX
) == PICL_SUCCESS
) {
3744 if (strncmp(valbuf
, SANIBEL_PICLNODE_CPU
,
3745 strlen(SANIBEL_PICLNODE_CPU
)) == 0) {
3746 locp
->cpu_node
= B_TRUE
;
3751 * if "State" prop is already created (node is managed by other plugin)
3753 * else if cfgadm ap is found
3754 * creates State prop and intializes it
3756 * find the nodes using libdevinfo under a given path
3759 * mark node state a connected
3761 * mark node state a empty
3763 (void) get_loc_type(locp
);
3764 if (locp
->state_mgr
== PLUGIN_PVT
) {
3765 (void) update_loc_state(locp
, &state_change
);
3766 return (PICL_SUCCESS
);
3769 if (locp
->state_mgr
== STATIC_LOC
) {
3771 * in case of scsi locations,, loc state will be connected
3772 * no need to check again if the fru is present using libdevinfo
3774 if (locp
->state
!= LOC_STATE_CONNECTED
) {
3775 if (is_fru_present_under_location(locp
) == B_TRUE
) {
3776 locp
->state
= LOC_STATE_CONNECTED
;
3778 locp
->state
= LOC_STATE_EMPTY
;
3782 /* create state property */
3783 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
3784 PICL_READ
+ PICL_VOLATILE
, PICL_PROPNAMELEN_MAX
,
3785 PICL_PROP_STATE
, get_loc_state
, NULLWRITE
, locp
->locnodeh
,
3786 NULL
, loc_state
[locp
->state
])) != PICL_SUCCESS
) {
3787 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
3788 PICL_PROP_STATE
, locp
->name
, rc
);
3791 ap_status_time
= (uint64_t)(time(NULL
));
3793 /* create location StatusTime prop. */
3794 if ((rc
= create_property(PICL_PTYPE_TIMESTAMP
, PICL_READ
,
3795 sizeof (uint64_t), PICL_PROP_STATUS_TIME
, NULLREAD
,
3796 NULLWRITE
, locp
->locnodeh
, NULL
, &ap_status_time
)) !=
3798 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
3799 PICL_PROP_STATUS_TIME
, locp
->name
, rc
);
3803 if ((rc
= update_loc_state(locp
, &state_change
)) != PICL_SUCCESS
) {
3804 FRUTREE_DEBUG2(FRUTREE_INIT
, GET_LOC_STATE_ERR
, locp
->name
, rc
);
3807 return (PICL_SUCCESS
);
3810 static frutree_port_type_t
3811 frutree_get_port_type(frutree_portnode_t
*portp
)
3813 char device_type
[PICL_PROPNAMELEN_MAX
];
3814 frutree_port_type_t port_type
= UNKNOWN_PORT
;
3816 if (portp
== NULL
) {
3820 if (ptree_get_propval_by_name(portp
->portnodeh
,
3821 PICL_PROP_PORT_TYPE
, device_type
,
3822 sizeof (device_type
)) == PICL_SUCCESS
) {
3823 if (strcmp(device_type
, SANIBEL_NETWORK_PORT
) == 0) {
3824 port_type
= NETWORK_PORT
;
3825 } else if (strcmp(device_type
,
3826 SANIBEL_SERIAL_PORT
) == 0) {
3827 port_type
= SERIAL_PORT
;
3828 } else if (strcmp(device_type
,
3829 SANIBEL_PARALLEL_PORT
) == 0) {
3830 port_type
= PARALLEL_PORT
;
3836 /* volatile callback function to get port condition */
3838 get_port_condition(ptree_rarg_t
*rarg
, void *buf
)
3841 hashdata_t
*hashptr
= NULL
;
3842 frutree_portnode_t
*portp
= NULL
;
3843 frutree_port_type_t port_type
;
3846 return (PICL_INVALIDARG
);
3849 if ((rc
= hash_lookup_entry(rarg
->nodeh
, (void **)&hashptr
)) !=
3854 portp
= PORTDATA_PTR(hashptr
);
3855 if (portp
== NULL
) {
3856 return (PICL_FAILURE
);
3858 port_type
= frutree_get_port_type(portp
);
3860 if (port_type
== UNKNOWN_PORT
) {
3861 portp
->cond
= PORT_COND_UNKNOWN
;
3862 (void) strncpy((char *)buf
, port_cond
[portp
->cond
],
3863 PICL_PROPNAMELEN_MAX
);
3864 return (PICL_SUCCESS
);
3867 if ((rc
= update_port_state(portp
, B_TRUE
)) != PICL_SUCCESS
) {
3871 (void) strncpy((char *)buf
, port_cond
[portp
->cond
],
3872 PICL_PROPNAMELEN_MAX
);
3873 return (PICL_SUCCESS
);
3876 /* volatile callback function to get port state */
3878 get_port_state(ptree_rarg_t
*rarg
, void *buf
)
3881 hashdata_t
*hashptr
= NULL
;
3882 frutree_portnode_t
*portp
= NULL
;
3883 frutree_port_type_t port_type
;
3886 return (PICL_INVALIDARG
);
3888 if ((rc
= hash_lookup_entry(rarg
->nodeh
, (void **)&hashptr
)) !=
3892 portp
= PORTDATA_PTR(hashptr
);
3893 if (portp
== NULL
) {
3894 return (PICL_FAILURE
);
3897 port_type
= frutree_get_port_type(portp
);
3898 if (port_type
== UNKNOWN_PORT
) {
3899 portp
->state
= PORT_STATE_UNKNOWN
;
3900 (void) strncpy((char *)buf
, port_state
[portp
->state
],
3901 PICL_PROPNAMELEN_MAX
);
3902 return (PICL_SUCCESS
);
3905 if ((rc
= update_port_state(portp
, B_TRUE
)) != PICL_SUCCESS
) {
3908 (void) strncpy((char *)buf
, port_state
[portp
->state
],
3909 PICL_PROPNAMELEN_MAX
);
3910 return (PICL_SUCCESS
);
3914 * Creates State and Condition property for a port node
3917 port_init(frutree_portnode_t
*portp
)
3919 picl_prophdl_t proph
;
3920 ptree_propinfo_t propinfo
;
3923 uint64_t status_time
;
3924 picl_nodehdl_t refhdl
;
3925 frutree_device_args_t device
;
3926 picl_prophdl_t tblprophdl
, tblhdl
;
3927 char class[PICL_PROPNAMELEN_MAX
];
3929 if (portp
== NULL
) {
3930 return (PICL_FAILURE
);
3932 refhdl
= get_reference_handle(portp
->portnodeh
);
3934 /* traverse thru platform tree and add entries to Devices table */
3936 /* create Devices table property */
3937 if ((rc
= create_property(PICL_PTYPE_TABLE
, PICL_READ
,
3938 sizeof (picl_prophdl_t
), PICL_PROP_DEVICES
,
3939 NULLREAD
, NULLWRITE
, portp
->portnodeh
, &tblprophdl
,
3940 &tblhdl
)) != PICL_SUCCESS
) {
3944 /* walk down the subtree and populate Devices */
3945 if ((rc
= ptree_get_propval_by_name(refhdl
,
3946 PICL_PROP_CLASSNAME
, class,
3947 sizeof (class))) != PICL_SUCCESS
) {
3950 if ((rc
= create_table_entry(tblhdl
, refhdl
, class)) !=
3955 device
.nodeh
= refhdl
;
3956 device
.device_tblhdl
= tblhdl
;
3957 device
.first
= NULL
;
3959 device
.create_cache
= B_FALSE
;
3961 if ((rc
= do_action(refhdl
, CREATE_DEVICES_ENTRIES
,
3962 (void *)&device
)) != PICL_SUCCESS
) {
3966 if ((rc
= ptree_get_prop_by_name(refhdl
, PICL_PROP_INSTANCE
,
3967 &proph
)) != PICL_SUCCESS
) {
3970 if ((rc
= ptree_get_propinfo(proph
, &propinfo
)) !=
3974 vbuf
= alloca(propinfo
.piclinfo
.size
);
3976 return (PICL_NOSPACE
);
3978 if ((rc
= ptree_get_propval(proph
, vbuf
,
3979 propinfo
.piclinfo
.size
)) != PICL_SUCCESS
) {
3982 portp
->instance
= *(int *)vbuf
;
3984 if ((rc
= ptree_get_prop_by_name(refhdl
,
3985 PICL_PROP_DRIVER_NAME
, &proph
)) != PICL_SUCCESS
) {
3988 if ((rc
= ptree_get_propinfo(proph
, &propinfo
)) !=
3992 vbuf
= alloca(propinfo
.piclinfo
.size
);
3994 return (PICL_NOSPACE
);
3996 if ((rc
= ptree_get_propval(proph
, vbuf
,
3997 propinfo
.piclinfo
.size
)) != PICL_SUCCESS
) {
4001 (void) strncpy(portp
->driver
, (char *)vbuf
,
4002 sizeof (portp
->driver
));
4004 /* this node is created using libdevinfo or conf file */
4005 if ((rc
= get_port_info(portp
)) != PICL_SUCCESS
) {
4010 /* create state and condition properties */
4011 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
4012 PICL_READ
| PICL_VOLATILE
, PICL_PROPNAMELEN_MAX
,
4013 PICL_PROP_STATE
, get_port_state
, NULLWRITE
, portp
->portnodeh
,
4014 NULL
, port_state
[portp
->state
])) != PICL_SUCCESS
) {
4018 status_time
= (uint64_t)(time(NULL
));
4019 if ((rc
= create_property(PICL_PTYPE_TIMESTAMP
, PICL_READ
,
4020 sizeof (uint64_t), PICL_PROP_STATUS_TIME
, NULLREAD
,
4021 NULLWRITE
, portp
->portnodeh
, NULL
, &status_time
)) !=
4026 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
,
4027 PICL_READ
| PICL_VOLATILE
, PICL_PROPNAMELEN_MAX
,
4028 PICL_PROP_CONDITION
, get_port_condition
, NULLWRITE
,
4029 portp
->portnodeh
, NULL
, port_cond
[portp
->cond
])) !=
4033 if ((rc
= create_property(PICL_PTYPE_TIMESTAMP
, PICL_READ
,
4034 sizeof (uint64_t), PICL_PROP_CONDITION_TIME
, NULLREAD
,
4035 NULLWRITE
, portp
->portnodeh
, NULL
, &status_time
)) !=
4039 (void) update_port_state(portp
, B_FALSE
);
4040 return (PICL_SUCCESS
);
4044 * This routine dynamically determines the scsi name (using libcfgadm)
4045 * that corresponds to the node specified in configuration file
4048 init_scsi_slot(frutree_frunode_t
*frup
, frutree_locnode_t
**ptr2locp
,
4049 boolean_t
*node_name_changed
)
4052 char devfs_path
[PICL_PROPNAMELEN_MAX
];
4053 char bus_addr
[PICL_PROPNAMELEN_MAX
];
4054 char label
[PICL_PROPNAMELEN_MAX
];
4055 char name
[MAXPATHLEN
];
4056 uint8_t geo_addr
= 0;
4057 frutree_locnode_t
*locp
= NULL
, *new_locp
= NULL
;
4058 hashdata_t
*hashptr
= NULL
;
4059 picl_nodehdl_t nodeh
;
4061 if (ptr2locp
== NULL
) {
4062 return (PICL_INVALIDARG
);
4064 locp
= (frutree_locnode_t
*)*ptr2locp
;
4065 *node_name_changed
= B_FALSE
;
4068 return (PICL_FAILURE
);
4071 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
4072 PICL_PROP_DEVFS_PATH
, devfs_path
,
4073 sizeof (devfs_path
))) != PICL_SUCCESS
) {
4077 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
4078 PICL_PROP_BUS_ADDR
, bus_addr
,
4079 sizeof (bus_addr
))) != PICL_SUCCESS
) {
4083 /* find the dynamic ap_id from libcfgadm */
4084 if ((rc
= get_scsislot_name(devfs_path
, bus_addr
,
4085 name
)) != PICL_SUCCESS
) {
4086 /* if rc is NODENOTFOUND, then slot is empty */
4087 if (rc
!= PICL_NODENOTFOUND
) {
4090 return (PICL_SUCCESS
);
4094 /* node name is same, so dont change anything */
4095 if (strcmp(name
, locp
->name
) == 0) {
4096 return (PICL_SUCCESS
);
4099 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
4100 PICL_PROP_GEO_ADDR
, &geo_addr
,
4101 sizeof (geo_addr
))) != PICL_SUCCESS
) {
4105 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
4106 PICL_PROP_LABEL
, label
,
4107 sizeof (label
))) != PICL_SUCCESS
) {
4111 /* Now recreate the node with new name */
4112 if ((rc
= ptree_create_node(name
, PICL_CLASS_LOCATION
,
4113 &nodeh
)) != PICL_SUCCESS
) {
4117 /* add all the properties now */
4118 (void) create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
4119 PICL_PROPNAMELEN_MAX
, PICL_PROP_SLOT_TYPE
, NULLREAD
,
4120 NULLWRITE
, nodeh
, (picl_prophdl_t
*)NULL
,
4123 (void) create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
4124 PICL_PROPNAMELEN_MAX
, PICL_PROP_LABEL
, NULLREAD
,
4125 NULLWRITE
, nodeh
, (picl_prophdl_t
*)NULL
,
4128 (void) create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
4129 PICL_PROPNAMELEN_MAX
, PICL_PROP_BUS_ADDR
, NULLREAD
,
4130 NULLWRITE
, nodeh
, (picl_prophdl_t
*)NULL
,
4133 (void) create_property(PICL_PTYPE_UNSIGNED_INT
, PICL_READ
,
4134 sizeof (uint8_t), PICL_PROP_GEO_ADDR
, NULLREAD
,
4135 NULLWRITE
, nodeh
, (picl_prophdl_t
*)NULL
,
4138 (void) create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
4139 PICL_PROPNAMELEN_MAX
, PICL_PROP_DEVFS_PATH
, NULLREAD
,
4140 NULLWRITE
, nodeh
, (picl_prophdl_t
*)NULL
,
4142 (void) ptree_add_node(frup
->frunodeh
, nodeh
);
4144 if ((rc
= make_loc_data(name
, &hashptr
)) != PICL_SUCCESS
) {
4147 /* save data in hash table */
4148 if ((rc
= hash_add_entry(nodeh
, (void *)hashptr
)) != PICL_SUCCESS
) {
4149 free_data(hashptr
->type
, hashptr
);
4153 new_locp
= LOCDATA_PTR(hashptr
);
4154 new_locp
->locnodeh
= nodeh
;
4155 *ptr2locp
= new_locp
;
4156 *node_name_changed
= B_TRUE
;
4157 return (PICL_SUCCESS
);
4161 * find the child nodes under a fru and initialize them
4164 frutree_initialize_children(picl_nodehdl_t childh
, void *c_args
)
4167 picl_nodehdl_t parenth
;
4168 boolean_t node_changed
= B_FALSE
;
4169 hashdata_t
*datap
= NULL
;
4170 char name
[PICL_PROPNAMELEN_MAX
];
4171 char class[PICL_PROPNAMELEN_MAX
];
4172 frutree_frunode_t
*frup
= NULL
;
4173 frutree_init_callback_arg_t
*arg
;
4175 if (c_args
== NULL
) {
4176 return (PICL_INVALIDARG
);
4178 arg
= (frutree_init_callback_arg_t
*)c_args
;
4181 if ((rc
= ptree_get_propval_by_name(childh
, PICL_PROP_PARENT
,
4182 &parenth
, sizeof (parenth
))) != PICL_SUCCESS
) {
4186 if (parenth
!= frup
->frunodeh
)
4187 return (PICL_WALK_CONTINUE
);
4189 if ((rc
= ptree_get_propval_by_name(childh
, PICL_PROP_CLASSNAME
, class,
4190 sizeof (class))) != PICL_SUCCESS
) {
4194 if ((rc
= ptree_get_propval_by_name(childh
, PICL_PROP_NAME
, name
,
4195 sizeof (name
))) != PICL_SUCCESS
) {
4199 if (strcmp(class, PICL_CLASS_LOCATION
) == 0) {
4200 char slot_type
[PICL_PROPNAMELEN_MAX
];
4201 frutree_locnode_t
*locp
= NULL
;
4202 frutree_frunode_t
*child_frup
= NULL
;
4203 /* initialize internal data structure */
4204 if ((rc
= make_loc_data(name
, &datap
)) != PICL_SUCCESS
) {
4205 return (PICL_WALK_CONTINUE
);
4207 locp
= LOCDATA_PTR(datap
);
4208 locp
->locnodeh
= childh
;
4209 /* save data in hash table */
4210 (void) hash_add_entry(childh
, (void *)datap
);
4211 if ((rc
= ptree_get_propval_by_name(locp
->locnodeh
,
4212 PICL_PROP_SLOT_TYPE
, slot_type
,
4213 sizeof (slot_type
))) != PICL_SUCCESS
) {
4214 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_GET_PROPVAL_ERR
,
4215 PICL_PROP_SLOT_TYPE
, locp
->name
, rc
);
4216 return (PICL_WALK_CONTINUE
);
4218 if (strcmp(slot_type
, SANIBEL_SCSI_SLOT
) == 0 ||
4219 strcmp(slot_type
, SANIBEL_IDE_SLOT
) == 0) {
4221 * this rountine finds the valid cfgadm
4222 * ap_id name for a given node and
4223 * creates a new node with that name.
4224 * If the node name is changed, the present
4225 * node must be added to the list of nodes
4226 * to be deleted from tree after ptree walk.
4228 (void) init_scsi_slot(frup
, &locp
,
4231 delete_list_t
*nodep
= NULL
;
4233 * add this node to list of nodes
4236 nodep
= (delete_list_t
*)malloc(
4237 sizeof (delete_list_t
));
4238 if (nodep
== NULL
) {
4239 return (PICL_NOSPACE
);
4241 nodep
->nodeh
= childh
;
4244 if (arg
->first
== NULL
) {
4246 } else { /* add 2 front */
4247 nodep
->next
= arg
->first
;
4253 if ((rc
= location_init(locp
)) != PICL_SUCCESS
) {
4254 return (PICL_WALK_CONTINUE
);
4257 /* if location is empty, done */
4258 if (locp
->state
== LOC_STATE_EMPTY
||
4259 locp
->state
== LOC_STATE_UNKNOWN
) {
4260 return (PICL_WALK_CONTINUE
);
4263 /* create the fru node and initialize it */
4264 if ((rc
= create_fru_node(locp
, &child_frup
)) !=
4266 return (PICL_WALK_CONTINUE
);
4270 * if fru is already configured, create the
4271 * subtree under the child fru
4273 if (child_frup
->state
== FRU_STATE_CONFIGURED
) {
4274 /* initialize the fru_path */
4275 if ((rc
= probe_fru(child_frup
, B_TRUE
)) !=
4277 FRUTREE_DEBUG2(EVENTS
, PROBE_FRU_ERR
,
4278 child_frup
->name
, rc
);
4281 } else if (strcmp(class, PICL_CLASS_PORT
) == 0) {
4282 frutree_portnode_t
*portp
= NULL
;
4283 if ((rc
= make_port_data(name
, &datap
)) != PICL_SUCCESS
) {
4284 return (PICL_WALK_CONTINUE
);
4286 (void) hash_add_entry(childh
, (void *)datap
);
4287 portp
= PORTDATA_PTR(datap
);
4288 portp
->portnodeh
= childh
;
4289 (void) port_init(portp
);
4291 return (PICL_WALK_CONTINUE
);
4294 /* traverse thru all locations under fru and initiate connects */
4296 initiate_connects(picl_nodehdl_t nodeh
, void *args
)
4299 hashdata_t
*hashptr
= NULL
;
4300 picl_nodehdl_t parenth
;
4301 frutree_frunode_t
*frup
= NULL
;
4302 frutree_locnode_t
*locp
= NULL
;
4305 return (PICL_INVALIDARG
);
4307 frup
= (frutree_frunode_t
*)args
;
4309 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_PARENT
,
4310 &parenth
, sizeof (parenth
))) != PICL_SUCCESS
) {
4314 if (parenth
!= frup
->frunodeh
)
4315 return (PICL_WALK_CONTINUE
);
4317 if ((rc
= hash_lookup_entry(nodeh
, (void **)&hashptr
)) !=
4319 return (PICL_WALK_CONTINUE
);
4321 locp
= LOCDATA_PTR(hashptr
);
4323 if (locp
->state
== LOC_STATE_EMPTY
||
4324 locp
->state
== LOC_STATE_UNKNOWN
||
4325 locp
->state
== LOC_STATE_CONNECTED
) {
4326 return (PICL_WALK_CONTINUE
);
4329 /* if loc is not connected, do a connect operation */
4330 if (locp
->autoconfig_enabled
) {
4331 if ((rc
= connect_fru(locp
)) != PICL_SUCCESS
) {
4332 FRUTREE_DEBUG2(EVENTS
, CONNECT_FAILED_ERR
,
4336 return (PICL_WALK_CONTINUE
);
4340 * Initializes the subtree under a FRU
4343 fru_init(frutree_frunode_t
*frup
)
4346 delete_list_t
*tmp
= NULL
, *curr
= NULL
;
4347 frutree_init_callback_arg_t arg
;
4350 return (PICL_INVALIDARG
);
4357 * this routine creates internal data structures for
4358 * all the children under this fru and initializes them
4360 if ((rc
= do_action(frup
->frunodeh
, INIT_FRU
,
4361 (void *)&arg
)) != PICL_SUCCESS
) {
4365 /* traverse thru delete_nodes_list and delete the nodes from tree */
4369 (void) ptree_delete_node(tmp
->nodeh
);
4370 (void) ptree_destroy_node(tmp
->nodeh
);
4371 (void) hash_remove_entry(tmp
->nodeh
);
4377 * dont post events during intialization (for other FRUs)
4378 * chassis intialization will take care of posting events
4379 * for complete frutree
4381 if ((frup
->frunodeh
== chassish
) ||
4382 (post_picl_events
== B_TRUE
)) {
4383 if ((rc
= do_action(frup
->frunodeh
, POST_EVENTS
, NULL
)) !=
4385 FRUTREE_DEBUG1(LOG_ERR
, "SUNW_frutree:Error in "
4386 "posting picl events(error=%d)", rc
);
4390 if (frup
->frunodeh
== chassish
) {
4391 post_picl_events
= B_TRUE
;
4392 frutree_connects_initiated
= B_TRUE
;
4395 /* initiate connects */
4396 if ((rc
= ptree_walk_tree_by_class(frup
->frunodeh
, PICL_CLASS_LOCATION
,
4397 (void *)frup
, initiate_connects
)) != PICL_SUCCESS
) {
4400 return (PICL_SUCCESS
);
4405 post_events(picl_nodehdl_t childh
, void *c_args
)
4408 hashdata_t
*hashptr
= NULL
;
4409 frutree_frunode_t
*frup
= NULL
;
4410 frutree_locnode_t
*locp
= NULL
;
4411 frutree_portnode_t
*portp
= NULL
;
4412 char classval
[PICL_CLASSNAMELEN_MAX
];
4414 if ((rc
= ptree_get_propval_by_name(childh
, PICL_PROP_CLASSNAME
,
4415 classval
, sizeof (classval
))) != PICL_SUCCESS
) {
4416 return (PICL_WALK_CONTINUE
);
4419 if ((rc
= hash_lookup_entry(childh
, (void **)&hashptr
)) !=
4421 return (PICL_WALK_CONTINUE
);
4424 if (strcmp(classval
, PICL_CLASS_LOCATION
) == 0) {
4425 locp
= LOCDATA_PTR(hashptr
);
4426 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
4427 loc_state
[locp
->state
], loc_state
[locp
->prev_state
],
4428 childh
, WAIT
)) != PICL_SUCCESS
) {
4429 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4430 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
4432 return (PICL_WALK_CONTINUE
);
4435 if (strcmp(classval
, PICL_CLASS_FRU
) == 0) {
4436 frup
= FRUDATA_PTR(hashptr
);
4437 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
4438 fru_state
[frup
->state
], fru_state
[frup
->prev_state
],
4439 childh
, WAIT
)) != PICL_SUCCESS
) {
4440 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4441 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
4443 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
4444 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
4445 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
4446 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4447 frup
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
4449 return (PICL_WALK_CONTINUE
);
4452 if (strcmp(classval
, PICL_CLASS_PORT
) == 0) {
4453 portp
= PORTDATA_PTR(hashptr
);
4454 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
4455 port_state
[portp
->state
], NULL
,
4456 portp
->portnodeh
, WAIT
)) != PICL_SUCCESS
) {
4457 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4458 portp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
4460 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
4461 port_cond
[portp
->cond
], NULL
,
4462 portp
->portnodeh
, WAIT
)) != PICL_SUCCESS
) {
4463 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4464 portp
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
4466 return (PICL_WALK_CONTINUE
);
4468 return (PICL_WALK_CONTINUE
);
4472 * This function is a utility function that calls the
4473 * appropriate call back function for the all the nodes under
4474 * the specified root node.
4475 * future additions can be done by defining new action and callback.
4478 do_action(picl_nodehdl_t root
, int action
, void *cargs
)
4481 callback_t func_ptr
;
4487 func_ptr
= frutree_initialize_children
;
4490 case CREATE_DEVICES_ENTRIES
:
4491 func_ptr
= create_device_entries
;
4495 func_ptr
= post_events
;
4499 return (PICL_INVALIDARG
);
4502 if ((rc
= ptree_walk_tree_by_class(root
, class, cargs
,
4503 func_ptr
)) != PICL_SUCCESS
) {
4506 return (PICL_SUCCESS
);
4510 frutree_update_chassis_state(frutree_frustate_t state
,
4511 frutree_frustate_t prev_state
)
4513 uint64_t ap_status_time
;
4514 picl_errno_t rc
= 0;
4515 char present_state
[PICL_PROPNAMELEN_MAX
];
4517 (void) strncpy(present_state
, fru_state
[state
], sizeof (present_state
));
4518 (void) ptree_update_propval_by_name(chassish
,
4519 PICL_PROP_STATE
, present_state
, sizeof (present_state
));
4521 ap_status_time
= (uint64_t)(time(NULL
));
4522 if ((rc
= ptree_update_propval_by_name(chassish
,
4523 PICL_PROP_STATUS_TIME
, (void *)&ap_status_time
,
4524 sizeof (ap_status_time
))) != PICL_SUCCESS
) {
4525 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
4526 PICL_PROP_STATUS_TIME
, PICL_NODE_CHASSIS
, rc
);
4528 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
4529 fru_state
[state
], fru_state
[prev_state
],
4530 chassish
, WAIT
)) != PICL_SUCCESS
) {
4531 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4532 PICL_NODE_CHASSIS
, PICLEVENT_STATE_CHANGE
, rc
);
4534 return (PICL_SUCCESS
);
4541 frutree_frunode_t
*frup
= NULL
;
4542 hashdata_t
*hashptr
= NULL
;
4544 if ((rc
= ptree_get_node_by_path(PLATFORM_PATH
, &platformh
)) !=
4549 if ((rc
= hash_lookup_entry(chassish
, (void **)&hashptr
)) !=
4553 frup
= FRUDATA_PTR(hashptr
);
4555 /* create the nodes in conf file under chassis node */
4556 if ((rc
= picld_pluginutil_parse_config_file(chassish
,
4557 conf_file
)) != PICL_SUCCESS
) {
4558 /* update chassis state to unconfigured */
4559 (void) frutree_update_chassis_state(
4560 FRU_STATE_UNCONFIGURED
, FRU_STATE_UNKNOWN
);
4564 /* update chassis state to configuring */
4565 (void) frutree_update_chassis_state(
4566 FRU_STATE_CONFIGURING
, FRU_STATE_UNCONFIGURED
);
4568 if (scsi_info_init() != PICL_SUCCESS
) {
4569 /* update chassis state to unconfigured */
4570 (void) frutree_update_chassis_state(
4571 FRU_STATE_UNCONFIGURED
, FRU_STATE_CONFIGURING
);
4572 return (PICL_FAILURE
);
4575 /* traverse thru all the nodes under chassis, initialize them */
4576 if ((rc
= fru_init(frup
)) != PICL_SUCCESS
) {
4577 /* update chassis state to unconfigured */
4578 (void) frutree_update_chassis_state(
4579 FRU_STATE_UNCONFIGURED
, FRU_STATE_CONFIGURING
);
4583 /* free the memory used during initialization */
4585 /* start node monitoring thread */
4586 if (pthread_create(&monitor_tid
, NULL
, monitor_node_status
,
4588 FRUTREE_DEBUG0(EVENTS
, "SUNW_frutree:Error in creating node"
4589 " monitoring thread");
4592 (void) pthread_mutex_lock(&frup
->mutex
);
4593 frup
->state
= FRU_STATE_CONFIGURED
;
4594 (void) pthread_mutex_unlock(&frup
->mutex
);
4596 /* update chassis state to configured */
4597 (void) frutree_update_chassis_state(
4598 FRU_STATE_CONFIGURED
, FRU_STATE_CONFIGURING
);
4599 return (PICL_SUCCESS
);
4604 init_thread(void *arg
)
4608 FRUTREE_DEBUG0(FRUTREE_INIT
, "init_thread begin");
4610 (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
4611 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
4613 if (get_configuration_file() != PICL_SUCCESS
) {
4616 FRUTREE_DEBUG1(FRUTREE_INIT
, "conf_file = %s", conf_file
);
4617 if ((rc
= frutree_init()) != PICL_SUCCESS
) {
4618 FRUTREE_DEBUG1(FRUTREE_INIT
, "frutree_init failed, error = %d",
4621 FRUTREE_DEBUG0(FRUTREE_INIT
, "init_thread end");
4627 event_completion_handler(char *ename
, void *earg
, size_t size
)
4629 if (frutree_debug
& EV_COMPLETION
) {
4630 char name
[PICL_PROPNAMELEN_MAX
];
4634 picl_nodehdl_t fruhdl
;
4635 time_t current_time
;
4637 if (strncmp(ename
, PICLEVENT_STATE_CHANGE
,
4638 strlen(PICLEVENT_STATE_CHANGE
)) == 0) {
4639 arg
= PICLEVENTARG_STATE
;
4640 } else if (strncmp(ename
, PICLEVENT_CONDITION_CHANGE
,
4641 strlen(PICLEVENT_CONDITION_CHANGE
)) == 0) {
4642 arg
= PICLEVENTARG_CONDITION
;
4645 (void) nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
);
4646 (void) nvlist_lookup_uint64(nvlp
, PICLEVENTARG_NODEHANDLE
,
4649 (void) nvlist_lookup_string(nvlp
, arg
, &value
);
4651 (void) ptree_get_propval_by_name(fruhdl
, PICL_PROP_NAME
,
4652 (void *)name
, sizeof (name
));
4653 current_time
= (uint64_t)(time(NULL
));
4654 if (value
!= NULL
) {
4655 FRUTREE_DEBUG4(EV_COMPLETION
, "ev_completed[%s]%s(%s) "
4656 "on %s", ctime(¤t_time
), ename
, value
, name
);
4661 (void) mutex_lock(&piclevent_mutex
);
4662 piclevent_pending
= 0;
4663 (void) cond_broadcast(&piclevent_completed_cv
);
4664 (void) mutex_unlock(&piclevent_mutex
);
4670 post_piclevent(const char *event
, char *val1
,
4671 char *val2
, picl_nodehdl_t nodeh
, frutree_wait_t wait
)
4675 char *pack_buf
= NULL
;
4682 if (event
== NULL
|| val1
== NULL
) {
4683 return (PICL_INVALIDARG
);
4685 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME_TYPE
, NULL
)) {
4686 return (PICL_FAILURE
);
4688 if (nvlist_add_uint64(nvl
, PICLEVENTARG_NODEHANDLE
, nodeh
)) {
4690 return (PICL_FAILURE
);
4693 if ((ename
= strdup(event
)) == NULL
) {
4695 return (PICL_NOSPACE
);
4698 if (strncmp(ename
, PICLEVENT_STATE_CHANGE
,
4699 strlen(PICLEVENT_STATE_CHANGE
)) == 0) {
4700 arg
= PICLEVENTARG_STATE
;
4701 } else if (strncmp(ename
, PICLEVENT_CONDITION_CHANGE
,
4702 strlen(PICLEVENT_CONDITION_CHANGE
)) == 0) {
4703 arg
= PICLEVENTARG_CONDITION
;
4707 return (PICL_INVALIDARG
);
4710 if (nvlist_add_string(nvl
, arg
, val1
)) {
4713 return (PICL_FAILURE
);
4716 if (strncmp(ename
, PICLEVENT_CONDITION_CHANGE
,
4717 strlen(PICLEVENT_CONDITION_CHANGE
)) == 0) {
4718 if (nvlist_pack(nvl
, &pack_buf
, &nvl_size
, NV_ENCODE_NATIVE
,
4722 return (PICL_FAILURE
);
4724 } else { /* state change event */
4727 /* if there is a last state, add it to nvlist */
4728 if (nvlist_add_string(nvl
,
4729 PICLEVENTARG_LAST_STATE
, val2
)) {
4732 return (PICL_FAILURE
);
4737 if (nvlist_pack(nvl
, &pack_buf
, &nvl_size
, NV_ENCODE_NATIVE
, NULL
)) {
4740 return (PICL_FAILURE
);
4743 (void) mutex_lock(&piclevent_mutex
);
4744 while (piclevent_pending
) {
4745 (void) cond_wait(&piclevent_completed_cv
,
4748 piclevent_pending
= 1;
4749 (void) mutex_unlock(&piclevent_mutex
);
4751 if ((rc
= ptree_post_event(ename
, pack_buf
, nvl_size
,
4752 event_completion_handler
)) != PICL_SUCCESS
) {
4756 (void) mutex_lock(&piclevent_mutex
);
4757 piclevent_pending
= 0;
4758 (void) mutex_unlock(&piclevent_mutex
);
4762 if (frutree_debug
) {
4763 char name
[PICL_PROPNAMELEN_MAX
];
4764 (void) ptree_get_propval_by_name(nodeh
, PICL_PROP_NAME
,
4765 name
, sizeof (name
));
4767 FRUTREE_DEBUG4(EVENTS
, "%s(%s -> %s) on %s", ename
,
4770 FRUTREE_DEBUG3(EVENTS
, "%s(%s) on %s", ename
,
4775 if (wait
) { /* wait for the event to be handled */
4776 (void) mutex_lock(&piclevent_mutex
);
4777 while (piclevent_pending
) {
4778 (void) gettimeofday(&tp
, NULL
);
4779 to
.tv_sec
= tp
.tv_sec
+ 1;
4780 to
.tv_nsec
= tp
.tv_usec
* 1000;
4781 (void) cond_timedwait(&piclevent_completed_cv
,
4782 &piclevent_mutex
, &to
);
4784 (void) mutex_unlock(&piclevent_mutex
);
4787 return (PICL_SUCCESS
);
4798 is_autoconfig_enabled(char *loc_name
)
4804 update_loc_type(frutree_locnode_t
*locp
)
4806 cfga_list_data_t
*list
= NULL
;
4807 /* get the info from the libcfgadm interface */
4808 list
= (cfga_list_data_t
*)malloc(sizeof (cfga_list_data_t
));
4810 return (PICL_NOSPACE
);
4813 if (get_cfgadm_state(list
, locp
->name
) == PICL_SUCCESS
) {
4814 locp
->state_mgr
= CFGADM_AP
;
4816 return (PICL_SUCCESS
);
4819 return (PICL_NODENOTFOUND
);
4823 * handles DR_INCOMING_RES on chassis node
4824 * (refresh piclfrutree tree)
4827 reconfigure_chassis(picl_nodehdl_t nodeh
, void *args
)
4830 hashdata_t
*hashptr
= NULL
;
4831 picl_nodehdl_t parenth
, childh
;
4832 frutree_frunode_t
*frup
= NULL
, *child_frup
= NULL
;
4833 frutree_locnode_t
*locp
= NULL
;
4834 boolean_t state_changed
= B_FALSE
;
4835 boolean_t cond_changed
= B_FALSE
;
4836 frutree_dr_arg_t dr_arg
;
4839 return (PICL_INVALIDARG
);
4841 frup
= (frutree_frunode_t
*)args
;
4843 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_PARENT
,
4844 &parenth
, sizeof (parenth
))) != PICL_SUCCESS
) {
4848 if (parenth
!= frup
->frunodeh
)
4849 return (PICL_WALK_CONTINUE
);
4851 if ((rc
= hash_lookup_entry(nodeh
, (void **)&hashptr
)) !=
4853 return (PICL_WALK_CONTINUE
);
4855 locp
= LOCDATA_PTR(hashptr
);
4857 /* if the location has child fru, get its information */
4858 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_CHILD
,
4859 &childh
, sizeof (childh
)) == PICL_SUCCESS
) {
4860 /* get the child fru information */
4861 if (hash_lookup_entry(childh
, (void **)&hashptr
) ==
4863 child_frup
= FRUDATA_PTR(hashptr
);
4867 /* for each location, update the state */
4868 if (locp
->state_mgr
== STATIC_LOC
) {
4869 /* check if cfgadm ap_id is present */
4870 rc
= update_loc_type(locp
);
4871 if (rc
== PICL_SUCCESS
) {
4873 child_frup
->state_mgr
= locp
->state_mgr
;
4874 (void) update_fru_state(child_frup
,
4880 state_changed
= B_FALSE
;
4881 (void) update_loc_state(locp
, &state_changed
);
4882 if (state_changed
) {
4883 switch (locp
->state
) {
4884 case LOC_STATE_CONNECTED
:
4885 case LOC_STATE_DISCONNECTED
:
4886 if (locp
->prev_state
== LOC_STATE_EMPTY
||
4887 locp
->prev_state
== LOC_STATE_UNKNOWN
) {
4888 /* handle fru insertion */
4889 dr_arg
.action
= HANDLE_INSERT
;
4891 /* handle loc state change */
4892 dr_arg
.action
= HANDLE_LOCSTATE_CHANGE
;
4895 case LOC_STATE_EMPTY
:
4896 /* handle fru removal */
4897 if (locp
->prev_state
== LOC_STATE_UNKNOWN
) {
4898 /* post piclevent to update led */
4899 dr_arg
.action
= HANDLE_LOCSTATE_CHANGE
;
4901 /* disconnected fru is removed */
4902 dr_arg
.action
= HANDLE_REMOVE
;
4906 return (PICL_WALK_CONTINUE
);
4907 } /* end of switch */
4910 (void) pthread_mutex_lock(&ev_mutex
);
4911 if ((rc
= add_to_queue(dr_arg
)) != PICL_SUCCESS
) {
4912 (void) pthread_mutex_unlock(&ev_mutex
);
4913 return (PICL_WALK_CONTINUE
);
4915 (void) pthread_cond_signal(&ev_cond
);
4916 (void) pthread_mutex_unlock(&ev_mutex
);
4917 return (PICL_WALK_CONTINUE
);
4919 /* connect the disconnect locations */
4920 if (locp
->state
== LOC_STATE_DISCONNECTED
&&
4921 locp
->autoconfig_enabled
== B_TRUE
) {
4922 if ((rc
= connect_fru(locp
)) != PICL_SUCCESS
) {
4923 FRUTREE_DEBUG2(EVENTS
, CONNECT_FAILED_ERR
,
4926 return (PICL_WALK_CONTINUE
);
4930 /* post picl event for child fru */
4931 if (child_frup
== NULL
) {
4932 return (PICL_WALK_CONTINUE
);
4935 /* update the state */
4936 (void) update_fru_state(child_frup
, &state_changed
);
4937 if (state_changed
) {
4938 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
4939 fru_state
[child_frup
->state
],
4940 fru_state
[child_frup
->prev_state
],
4941 child_frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
4942 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4943 child_frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
4947 /* update the condition */
4948 (void) update_fru_condition(child_frup
, &cond_changed
);
4950 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
4951 fru_cond
[child_frup
->cond
],
4952 fru_cond
[child_frup
->prev_cond
],
4953 child_frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
4954 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
4955 child_frup
->name
, PICLEVENT_CONDITION_CHANGE
,
4959 return (PICL_WALK_CONTINUE
);
4963 handle_chassis_configure(frutree_frunode_t
*frup
)
4968 return (PICL_INVALIDARG
);
4971 (void) pthread_mutex_lock(&frup
->mutex
);
4972 FRUTREE_DEBUG1(EVENTS
, "DR_INCOMING_RES on %s", frup
->name
);
4973 if (frup
->state
== FRU_STATE_UNCONFIGURED
) {
4974 frup
->state
= FRU_STATE_CONFIGURING
;
4975 (void) pthread_mutex_unlock(&frup
->mutex
);
4976 /* initial probe/initialization */
4977 /* create a thread to do the initialization */
4978 if (pthread_create(&init_threadID
, NULL
, &init_thread
,
4980 return (PICL_FAILURE
);
4982 return (PICL_SUCCESS
);
4984 (void) pthread_mutex_unlock(&frup
->mutex
);
4987 * 1. update the state of all the nodes in chassis
4988 * 2. handle all the state changes accordingly
4990 if ((rc
= ptree_walk_tree_by_class(chassish
, PICL_CLASS_LOCATION
,
4991 (void *)frup
, reconfigure_chassis
)) != PICL_SUCCESS
) {
4994 return (PICL_SUCCESS
);
4998 handle_chassis_unconfigure(frutree_frunode_t
*frup
)
5002 if (frup
->state
== FRU_STATE_UNCONFIGURED
) {
5003 return (PICL_SUCCESS
);
5006 /* do any cleanups here */
5007 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5008 PICLEVENTARGVAL_UNCONFIGURING
, PICLEVENTARGVAL_CONFIGURED
,
5009 chassish
, WAIT
)) != PICL_SUCCESS
) {
5010 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5011 PICL_NODE_CHASSIS
, PICLEVENT_STATE_CHANGE
, rc
);
5014 if ((rc
= ptree_update_propval_by_name(chassish
,
5015 PICL_PROP_STATE
, PICLEVENTARGVAL_UNCONFIGURED
,
5016 PICL_PROPNAMELEN_MAX
)) != PICL_SUCCESS
) {
5017 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
5018 PICL_PROP_STATE
, PICL_NODE_CHASSIS
, rc
);
5020 frup
->prev_state
= FRU_STATE_CONFIGURED
;
5021 frup
->state
= FRU_STATE_UNCONFIGURED
;
5022 (void) handle_fru_unconfigure(frup
);
5024 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5025 PICLEVENTARGVAL_UNCONFIGURED
, PICLEVENTARGVAL_UNCONFIGURING
,
5026 chassish
, WAIT
)) != PICL_SUCCESS
) {
5027 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5028 PICL_NODE_CHASSIS
, PICLEVENT_STATE_CHANGE
, rc
);
5030 return (PICL_SUCCESS
);
5034 configuration_fn(frutree_dr_arg_t
*dr_arg
)
5037 picl_nodehdl_t parenth
;
5038 cfga_flags_t flags
= 0;
5039 frutree_frunode_t
*frup
= NULL
;
5040 frutree_locnode_t
*locp
= NULL
;
5041 hashdata_t
*hashptr
= NULL
;
5042 boolean_t state_changed
= B_FALSE
;
5045 return (PICL_FAILURE
);
5047 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5050 return (PICL_FAILURE
);
5053 if (frup
->frunodeh
== chassish
) {
5054 rc
= handle_chassis_configure(frup
);
5059 if ((rc
= ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
5060 &parenth
, sizeof (parenth
))) != PICL_SUCCESS
) {
5065 if ((rc
= hash_lookup_entry(parenth
, (void **)&hashptr
)) !=
5070 locp
= LOCDATA_PTR(hashptr
);
5073 * update the location state also, as this could be
5074 * user initiated connect operation
5076 (void) update_loc_state(locp
, &state_changed
);
5078 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5079 loc_state
[locp
->state
], loc_state
[locp
->prev_state
],
5080 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5081 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5082 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5085 switch (dr_arg
->action
) {
5087 flags
|= CFGA_FLAG_FORCE
;
5088 FRUTREE_DEBUG1(EVENTS
, "CPU online on %s", frup
->name
);
5089 if (locp
->state
!= LOC_STATE_CONNECTED
) {
5090 if (locp
->autoconfig_enabled
) {
5091 if ((rc
= connect_fru(locp
)) != PICL_SUCCESS
) {
5092 FRUTREE_DEBUG2(EVENTS
,
5100 /* do configure now */
5101 case CONFIGURE_FRU
: /* dr_incoming_res */
5102 FRUTREE_DEBUG1(EVENTS
, "DR_INCOMING_RES on %s", frup
->name
);
5103 if ((rc
= configure_fru(frup
, flags
)) != PICL_SUCCESS
) {
5104 FRUTREE_DEBUG2(EVENTS
, CONFIGURE_FAILED_ERR
,
5110 return (PICL_SUCCESS
);
5113 /* handles all dr related events */
5115 handle_dr_event(frutree_dr_arg_t
*dr_arg
)
5118 picl_nodehdl_t loch
, childh
;
5119 hashdata_t
*hashptr
= NULL
;
5120 cfga_flags_t flags
= 0;
5121 frutree_dr_arg_t
*arg
= NULL
;
5122 frutree_dr_arg_t fru_dr_arg
;
5123 frutree_locnode_t
*locp
= NULL
;
5124 frutree_frunode_t
*frup
= NULL
, *child_frup
= NULL
;
5125 boolean_t state_changed
= B_FALSE
, cond_changed
= B_FALSE
;
5127 switch (dr_arg
->action
) {
5131 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5132 arg
= (frutree_dr_arg_t
*)malloc(sizeof (frutree_dr_arg_t
));
5134 FRUTREE_DEBUG2(EVENTS
, CONFIGURE_FAILED_ERR
,
5135 frup
->name
, PICL_NOSPACE
);
5138 arg
->action
= dr_arg
->action
;
5139 arg
->data
= dr_arg
->data
;
5140 (void) configuration_fn((void *)arg
);
5144 flags
|= CFGA_FLAG_FORCE
;
5145 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5149 FRUTREE_DEBUG1(EVENTS
, "CPU_OFFLINE on %s", frup
->name
);
5150 if ((rc
= unconfigure_fru(frup
, flags
)) != PICL_SUCCESS
) {
5151 FRUTREE_DEBUG2(EVENTS
, UNCONFIG_FAILED_ERR
, frup
->name
, rc
);
5155 if ((rc
= handle_fru_unconfigure(frup
)) != PICL_SUCCESS
) {
5156 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
, PICLEVENT_DR_REQ
,
5161 case UNCONFIGURE_FRU
: /* dr_outgoing_res */
5162 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5166 FRUTREE_DEBUG1(EVENTS
, "DR_OUTGOING_RES on %s", frup
->name
);
5167 if (frup
->frunodeh
== chassish
) {
5168 (void) handle_chassis_unconfigure(frup
);
5172 if ((rc
= unconfigure_fru(frup
, flags
)) != PICL_SUCCESS
) {
5173 FRUTREE_DEBUG2(EVENTS
, UNCONFIG_FAILED_ERR
, frup
->name
, rc
);
5177 if ((rc
= handle_fru_unconfigure(frup
)) != PICL_SUCCESS
) {
5178 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
,
5179 PICLEVENT_DR_REQ
, frup
->name
, rc
);
5182 if (ptree_get_propval_by_name(frup
->frunodeh
, PICL_PROP_PARENT
,
5183 &loch
, sizeof (loch
)) != PICL_SUCCESS
) {
5187 if ((rc
= hash_lookup_entry(loch
, (void **)&hashptr
)) !=
5191 locp
= LOCDATA_PTR(hashptr
);
5193 /* check the autoconfig flag */
5194 if (locp
->autoconfig_enabled
== B_FALSE
) {
5198 if ((rc
= disconnect_fru(locp
)) != PICL_SUCCESS
) {
5199 FRUTREE_DEBUG2(EVENTS
, "SUNW_frutree:Disconnect on %s "
5200 "failed(error=%d)", locp
->name
, rc
);
5204 case HANDLE_CONFIGURE
: /* basic hotswap operation */
5206 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5210 FRUTREE_DEBUG1(EVENTS
, "HANDLE CONFIGURE on %s", frup
->name
);
5211 handle_fru_configure(frup
);
5214 case HANDLE_UNCONFIGURE
: /* basic hotswap operation */
5216 /* cleanup the internal data structures */
5218 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5222 FRUTREE_DEBUG1(EVENTS
, "HANDLE UNCONFIGURE on %s", frup
->name
);
5224 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5225 fru_state
[frup
->state
], fru_state
[frup
->prev_state
],
5226 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5227 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5228 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5231 /* update the fru condition */
5232 (void) update_fru_condition(frup
, &state_changed
);
5233 if (state_changed
) {
5234 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
5235 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
5236 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5237 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5238 frup
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
5241 if ((rc
= handle_fru_unconfigure(frup
)) != PICL_SUCCESS
) {
5242 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
,
5243 PICLEVENT_DR_AP_STATE_CHANGE
, frup
->name
, rc
);
5247 case HANDLE_LOCSTATE_CHANGE
: /* basic hotswap operation */
5248 /* posts state change events of location */
5249 locp
= (frutree_locnode_t
*)dr_arg
->data
;
5253 FRUTREE_DEBUG1(EVENTS
, "HANDLE LOC STATE CHANGE on %s", locp
->name
);
5254 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5255 loc_state
[locp
->state
], loc_state
[locp
->prev_state
],
5256 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5257 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5258 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5261 /* wakeup threads sleeping on this condition */
5262 (void) pthread_mutex_lock(&locp
->mutex
);
5263 if (locp
->state
== LOC_STATE_CONNECTED
) {
5264 (void) pthread_cond_broadcast(&locp
->cond_cv
);
5266 (void) pthread_mutex_unlock(&locp
->mutex
);
5268 /* if the location has child fru, get its information */
5269 if (ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_CHILD
,
5270 &childh
, sizeof (childh
)) == PICL_SUCCESS
) {
5271 /* get the child fru information */
5272 if (hash_lookup_entry(childh
, (void **)&hashptr
) ==
5274 child_frup
= FRUDATA_PTR(hashptr
);
5277 /* update the child fru state and handle any state changes */
5278 if (child_frup
== NULL
) {
5282 if ((rc
= update_fru_state(child_frup
, &state_changed
)) !=
5284 FRUTREE_DEBUG2(EVENTS
, GET_FRU_STATE_ERR
, child_frup
->name
, rc
);
5288 if (state_changed
== B_FALSE
) {
5290 * if there is no change in state, check for condition
5292 * if there is a state change, handling state change
5293 * will take care of condition changes also.
5295 (void) update_fru_condition(child_frup
, &cond_changed
);
5296 if (cond_changed
== B_FALSE
) {
5300 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
5301 fru_cond
[child_frup
->cond
],
5302 fru_cond
[child_frup
->prev_cond
],
5303 child_frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5304 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5306 PICLEVENT_CONDITION_CHANGE
, rc
);
5311 /* add to queue to handle the fru state change */
5312 (void) pthread_mutex_lock(&child_frup
->mutex
);
5313 /* figure out if this is config/unconfig operation */
5314 if (child_frup
->state
== FRU_STATE_CONFIGURED
) {
5315 fru_dr_arg
.action
= HANDLE_CONFIGURE
;
5316 fru_dr_arg
.data
= child_frup
;
5317 } else if (child_frup
->state
== FRU_STATE_UNCONFIGURED
) {
5318 fru_dr_arg
.action
= HANDLE_UNCONFIGURE
;
5319 fru_dr_arg
.data
= child_frup
;
5321 (void) pthread_mutex_unlock(&child_frup
->mutex
);
5323 (void) pthread_mutex_lock(&ev_mutex
);
5324 if ((rc
= add_to_queue(fru_dr_arg
)) != PICL_SUCCESS
) {
5325 (void) pthread_mutex_unlock(&ev_mutex
);
5328 (void) pthread_cond_signal(&ev_cond
);
5329 (void) pthread_mutex_unlock(&ev_mutex
);
5332 case HANDLE_INSERT
: /* dr_apstate_change (HINT_INSERT) */
5333 locp
= (frutree_locnode_t
*)dr_arg
->data
;
5337 FRUTREE_DEBUG1(EVENTS
, "HANDLE INSERT on %s", locp
->name
);
5338 /* if the location has child fru, get its information */
5339 if (ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_CHILD
,
5340 &childh
, sizeof (childh
)) == PICL_SUCCESS
) {
5341 /* get the child fru information */
5342 if (hash_lookup_entry(childh
, (void **)&hashptr
) ==
5344 child_frup
= FRUDATA_PTR(hashptr
);
5349 * if previous state is not empty, it could be a
5350 * hint insert to retry connects
5352 (void) update_loc_state(locp
, &state_changed
);
5353 if (state_changed
) {
5354 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5355 loc_state
[locp
->state
],
5356 loc_state
[locp
->prev_state
], locp
->locnodeh
,
5357 WAIT
)) != PICL_SUCCESS
) {
5358 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5359 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5363 (void) update_fru_condition(child_frup
, &cond_changed
);
5364 if (cond_changed
== B_TRUE
) {
5365 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
5366 fru_cond
[child_frup
->cond
],
5367 fru_cond
[child_frup
->prev_cond
],
5368 child_frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5369 FRUTREE_DEBUG3(EVENTS
,
5370 PTREE_POST_PICLEVENT_ERR
,
5372 PICLEVENT_CONDITION_CHANGE
, rc
);
5375 if (!locp
->autoconfig_enabled
) {
5379 if (locp
->state
!= LOC_STATE_CONNECTED
) {
5380 if ((rc
= connect_fru(locp
)) != PICL_SUCCESS
) {
5381 FRUTREE_DEBUG2(EVENTS
, CONNECT_FAILED_ERR
,
5388 (void) update_loc_state(locp
, &state_changed
);
5389 if ((rc
= create_fru_node(locp
, &child_frup
)) != PICL_SUCCESS
) {
5390 FRUTREE_DEBUG3(EVENTS
, EVENT_NOT_HANDLED
,
5391 PICLEVENT_DR_AP_STATE_CHANGE
, locp
->name
, rc
);
5395 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5396 loc_state
[locp
->state
], loc_state
[locp
->prev_state
],
5397 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5398 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5399 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5402 if (locp
->autoconfig_enabled
) {
5403 if ((rc
= connect_fru(locp
)) != PICL_SUCCESS
) {
5404 FRUTREE_DEBUG2(EVENTS
, CONNECT_FAILED_ERR
,
5410 case HANDLE_REMOVE
: /* dr_apstate_change (HINT_REMOVE) */
5411 locp
= (frutree_locnode_t
*)dr_arg
->data
;
5415 FRUTREE_DEBUG1(EVENTS
, "HANDLE REMOVE on %s", locp
->name
);
5417 if (locp
->state
== LOC_STATE_EMPTY
) {
5418 break; /* discard the spurious event */
5421 (void) update_loc_state(locp
, &state_changed
);
5422 /* if the location has child fru, get its information */
5423 if (ptree_get_propval_by_name(locp
->locnodeh
, PICL_PROP_CHILD
,
5424 &childh
, sizeof (childh
)) == PICL_SUCCESS
) {
5425 /* get the child fru information */
5426 if (hash_lookup_entry(childh
, (void **)&hashptr
) ==
5428 frup
= FRUDATA_PTR(hashptr
);
5436 * frutree need to post this event before handling the
5437 * fru remove, so that other plugins (like frudata) can
5440 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5441 loc_state
[locp
->state
], loc_state
[locp
->prev_state
],
5442 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5443 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5444 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5447 if ((rc
= handle_fru_remove(frup
)) != PICL_SUCCESS
) {
5448 FRUTREE_DEBUG2(EVENTS
, "SUNW_frutree:Error in handling"
5449 "removal of fru under %s(error=%d)", locp
->name
, rc
);
5453 case POST_COND_EVENT
:
5454 frup
= (frutree_frunode_t
*)dr_arg
->data
;
5458 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
5459 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
5460 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5461 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5462 frup
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
5467 return (PICL_SUCCESS
);
5472 dr_thread(void * arg
)
5474 ev_queue_t
*event
= NULL
;
5476 (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
5477 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
5481 (void) pthread_mutex_lock(&ev_mutex
);
5482 while (queue_head
== NULL
) {
5483 (void) pthread_cond_wait(&ev_cond
, &ev_mutex
);
5486 event
= remove_from_queue();
5487 (void) pthread_mutex_unlock(&ev_mutex
);
5489 (void) handle_dr_event(&event
->arg
);
5492 (void) pthread_mutex_lock(&ev_mutex
);
5493 event
= remove_from_queue();
5494 (void) pthread_mutex_unlock(&ev_mutex
);
5501 update_port_state(frutree_portnode_t
*portp
, boolean_t post_ev
)
5505 uint64_t ap_status_time
;
5506 boolean_t state_changed
= B_FALSE
;
5507 boolean_t cond_changed
= B_FALSE
;
5508 frutree_port_type_t port_type
;
5510 if (portp
== NULL
) {
5511 return (PICL_INVALIDARG
);
5513 port_type
= frutree_get_port_type(portp
);
5515 if (port_type
== UNKNOWN_PORT
) {
5516 return (PICL_SUCCESS
);
5518 state
= kstat_port_state(port_type
, portp
->driver
,
5520 cond
= kstat_port_cond(port_type
, portp
->driver
,
5525 if (portp
->state
!= PORT_STATE_DOWN
) {
5526 portp
->state
= PORT_STATE_DOWN
;
5527 state_changed
= B_TRUE
;
5532 if (portp
->state
!= PORT_STATE_UP
) {
5533 portp
->state
= PORT_STATE_UP
;
5534 state_changed
= B_TRUE
;
5539 if (portp
->state
!= PORT_STATE_UNKNOWN
) {
5540 portp
->state
= PORT_STATE_UNKNOWN
;
5541 state_changed
= B_TRUE
;
5545 if (post_ev
&& state_changed
) {
5546 ap_status_time
= (uint64_t)(time(NULL
));
5547 if ((rc
= ptree_update_propval_by_name(portp
->portnodeh
,
5548 PICL_PROP_STATUS_TIME
, &ap_status_time
,
5549 sizeof (uint64_t))) != PICL_SUCCESS
) {
5550 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
5551 PICL_PROP_STATUS_TIME
, portp
->name
, rc
);
5554 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5555 port_state
[portp
->state
], NULL
,
5556 portp
->portnodeh
, WAIT
)) != PICL_SUCCESS
) {
5557 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5558 portp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5564 if (portp
->cond
!= PORT_COND_OK
) {
5565 portp
->cond
= PORT_COND_OK
;
5566 cond_changed
= B_TRUE
;
5570 if (portp
->cond
!= PORT_COND_FAILING
) {
5571 portp
->cond
= PORT_COND_FAILING
;
5572 cond_changed
= B_TRUE
;
5576 if (portp
->cond
!= PORT_COND_FAILED
) {
5577 portp
->cond
= PORT_COND_FAILED
;
5578 cond_changed
= B_TRUE
;
5582 if (portp
->cond
!= PORT_COND_TESTING
) {
5583 portp
->cond
= PORT_COND_TESTING
;
5584 cond_changed
= B_TRUE
;
5588 if (portp
->cond
!= PORT_COND_UNKNOWN
) {
5589 portp
->cond
= PORT_COND_UNKNOWN
;
5590 cond_changed
= B_TRUE
;
5594 if (post_ev
&& cond_changed
) {
5595 ap_status_time
= (uint64_t)(time(NULL
));
5596 if ((rc
= ptree_update_propval_by_name(portp
->portnodeh
,
5597 PICL_PROP_CONDITION_TIME
, &ap_status_time
,
5598 sizeof (uint64_t))) != PICL_SUCCESS
) {
5599 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
5600 PICL_PROP_CONDITION_TIME
, portp
->name
, rc
);
5602 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
5603 port_cond
[portp
->cond
], NULL
,
5604 portp
->portnodeh
, WAIT
)) != PICL_SUCCESS
) {
5605 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5606 portp
->name
, PICLEVENT_CONDITION_CHANGE
, rc
);
5609 return (PICL_SUCCESS
);
5613 * monitor port nodes and scsi nodes under a fru
5616 monitor_nodes_under_fru(picl_nodehdl_t nodeh
, void *c_args
)
5619 picl_nodehdl_t parenth
;
5620 hashdata_t
*hashptr
= NULL
;
5621 boolean_t state_changed
;
5622 frutree_portnode_t
*portp
= NULL
;
5623 frutree_locnode_t
*locp
= NULL
;
5624 frutree_frunode_t
*frup
= NULL
;
5625 char class[PICL_PROPNAMELEN_MAX
];
5626 char slot_type
[PICL_PROPNAMELEN_MAX
];
5628 if (c_args
== NULL
) {
5629 return (PICL_INVALIDARG
);
5631 frup
= (frutree_frunode_t
*)c_args
;
5633 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_PARENT
,
5634 &parenth
, sizeof (parenth
)) != PICL_SUCCESS
) {
5635 return (PICL_WALK_CONTINUE
);
5638 if (parenth
!= frup
->frunodeh
)
5639 return (PICL_WALK_CONTINUE
);
5641 if ((rc
= ptree_get_propval_by_name(nodeh
, PICL_PROP_CLASSNAME
, class,
5642 sizeof (class))) != PICL_SUCCESS
) {
5643 return (PICL_WALK_CONTINUE
);
5646 if ((rc
= hash_lookup_entry(nodeh
, (void **)&hashptr
)) !=
5648 return (PICL_WALK_CONTINUE
);
5651 if (strcmp(class, PICL_CLASS_LOCATION
) == 0) {
5652 locp
= LOCDATA_PTR(hashptr
);
5653 if (ptree_get_propval_by_name(locp
->locnodeh
,
5654 PICL_PROP_SLOT_TYPE
, slot_type
,
5655 sizeof (slot_type
)) != PICL_SUCCESS
) {
5656 return (PICL_WALK_CONTINUE
);
5658 if (strcmp(slot_type
, SANIBEL_SCSI_SLOT
) == 0 ||
5659 strcmp(slot_type
, SANIBEL_IDE_SLOT
) == 0) {
5660 return (PICL_WALK_CONTINUE
);
5662 (void) update_loc_state(locp
, &state_changed
);
5663 if (state_changed
) {
5664 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5665 loc_state
[locp
->state
],
5666 loc_state
[locp
->prev_state
],
5667 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5668 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5669 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5672 } else if (strcmp(class, PICL_CLASS_PORT
) == 0) {
5673 portp
= PORTDATA_PTR(hashptr
);
5674 (void) update_port_state(portp
, B_TRUE
);
5676 return (PICL_WALK_CONTINUE
);
5679 /* This routine monitors only port node, scsi nodes */
5682 monitor_fru(picl_nodehdl_t nodeh
, void *c_args
)
5685 picl_nodehdl_t loch
;
5686 hashdata_t
*hashptr
= NULL
;
5687 frutree_frunode_t
*frup
= NULL
;
5688 boolean_t state_changed
, cond_changed
;
5689 char slot_type
[PICL_PROPNAMELEN_MAX
];
5691 if (hash_lookup_entry(nodeh
, (void **)&hashptr
) !=
5693 return (PICL_WALK_CONTINUE
);
5695 frup
= FRUDATA_PTR(hashptr
);
5697 (void) pthread_mutex_lock(&frup
->mutex
);
5698 if (frup
->dr_in_progress
) {
5699 (void) pthread_mutex_unlock(&frup
->mutex
);
5700 return (PICL_WALK_CONTINUE
);
5702 frup
->busy
= B_TRUE
;
5703 (void) pthread_mutex_unlock(&frup
->mutex
);
5705 /* get the parent information to determine if it is scsi slot or not */
5706 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_PARENT
,
5707 &loch
, sizeof (loch
)) != PICL_SUCCESS
) {
5708 return (PICL_WALK_CONTINUE
);
5710 if (ptree_get_propval_by_name(loch
, PICL_PROP_SLOT_TYPE
, slot_type
,
5711 sizeof (slot_type
)) != PICL_SUCCESS
) {
5712 return (PICL_WALK_CONTINUE
);
5715 if (strcmp(slot_type
, SANIBEL_SCSI_SLOT
) == 0 ||
5716 strcmp(slot_type
, SANIBEL_IDE_SLOT
) == 0) {
5718 (void) update_fru_state(frup
, &state_changed
);
5719 (void) update_fru_condition(frup
, &cond_changed
);
5720 if (state_changed
) {
5721 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5722 fru_state
[frup
->state
],
5723 fru_state
[frup
->prev_state
],
5724 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5725 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5726 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5730 if ((rc
= post_piclevent(PICLEVENT_CONDITION_CHANGE
,
5731 fru_cond
[frup
->cond
], fru_cond
[frup
->prev_cond
],
5732 frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5733 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5734 frup
->name
, PICLEVENT_CONDITION_CHANGE
,
5738 (void) pthread_mutex_lock(&frup
->mutex
);
5739 frup
->busy
= B_FALSE
;
5740 (void) pthread_cond_signal(&frup
->busy_cond_cv
);
5741 (void) pthread_mutex_unlock(&frup
->mutex
);
5742 return (PICL_WALK_CONTINUE
);
5745 if (frup
->state
!= FRU_STATE_CONFIGURED
) {
5746 (void) pthread_mutex_lock(&frup
->mutex
);
5747 frup
->busy
= B_FALSE
;
5748 (void) pthread_cond_signal(&frup
->busy_cond_cv
);
5749 (void) pthread_mutex_unlock(&frup
->mutex
);
5750 return (PICL_WALK_CONTINUE
);
5753 (void) ptree_walk_tree_by_class(chassish
,
5754 NULL
, (void *)frup
, monitor_nodes_under_fru
);
5756 (void) pthread_mutex_lock(&frup
->mutex
);
5757 frup
->busy
= B_FALSE
;
5758 (void) pthread_cond_signal(&frup
->busy_cond_cv
);
5759 (void) pthread_mutex_unlock(&frup
->mutex
);
5760 return (PICL_WALK_CONTINUE
);
5765 monitor_node_status(void *arg
)
5771 (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
5772 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
5774 FRUTREE_DEBUG0(EVENTS
, "Monitoring for port status started");
5777 (void) pthread_mutex_lock(&monitor_mutex
);
5778 (void) gettimeofday(&tp
, NULL
);
5779 to
.tv_sec
= tp
.tv_sec
+ frutree_poll_timeout
;
5780 to
.tv_nsec
= tp
.tv_usec
* 1000;
5781 err
= pthread_cond_timedwait(&monitor_cv
, &monitor_mutex
, &to
);
5783 (void) pthread_mutex_unlock(&monitor_mutex
);
5784 if (err
== ETIMEDOUT
) { /* woke up from sleep */
5785 (void) ptree_walk_tree_by_class(chassish
,
5786 PICL_CLASS_FRU
, (void *)NULL
, monitor_fru
);
5788 } while (fini_called
== 0);
5793 create_children(frutree_frunode_t
*frup
, char *scsi_loc
, char *bus_addr
,
5794 int slot_no
, char *slot_type
, boolean_t is_cfgadm_ap
)
5798 picl_nodehdl_t nodeh
;
5799 uint8_t geo_addr
= 0;
5800 hashdata_t
*datap
= NULL
;
5801 frutree_locnode_t
*locp
= NULL
;
5802 hashdata_t
*hashptr
= NULL
;
5803 char fru_type
[PICL_PROPNAMELEN_MAX
];
5804 frutree_frunode_t
*child_frup
= NULL
;
5805 frutree_callback_data_t fru_arg
;
5807 if (frup
== NULL
|| scsi_loc
== NULL
|| slot_type
== NULL
) {
5808 return (PICL_FAILURE
);
5811 /* check if the location is already created */
5812 (void) strncpy(fru_arg
.node_name
, scsi_loc
,
5813 sizeof (fru_arg
.node_name
));
5814 fru_arg
.retnodeh
= 0;
5815 if ((rc
= ptree_walk_tree_by_class(chassish
, PICL_CLASS_LOCATION
,
5816 &fru_arg
, frutree_get_nodehdl
)) == PICL_SUCCESS
) {
5817 if (fru_arg
.retnodeh
!= 0) { /* node is already present */
5818 return (PICL_SUCCESS
);
5822 /* create the location node and all its properties */
5823 if ((rc
= ptree_create_node(scsi_loc
, PICL_CLASS_LOCATION
,
5824 &nodeh
)) != PICL_SUCCESS
) {
5828 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
5829 PICL_PROPNAMELEN_MAX
, PICL_PROP_SLOT_TYPE
, NULLREAD
,
5830 NULLWRITE
, nodeh
, NULL
, slot_type
)) !=
5832 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
5833 PICL_PROP_SLOT_TYPE
, scsi_loc
, rc
);
5836 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
5837 PICL_PROPNAMELEN_MAX
, PICL_PROP_LABEL
, NULLREAD
,
5838 NULLWRITE
, nodeh
, NULL
, bus_addr
)) != PICL_SUCCESS
) {
5839 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
5840 PICL_PROP_LABEL
, scsi_loc
, rc
);
5843 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
5844 PICL_PROPNAMELEN_MAX
, PICL_PROP_BUS_ADDR
, NULLREAD
,
5845 NULLWRITE
, nodeh
, NULL
, bus_addr
)) != PICL_SUCCESS
) {
5846 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
5847 PICL_PROP_BUS_ADDR
, scsi_loc
, rc
);
5851 if ((rc
= create_property(PICL_PTYPE_UNSIGNED_INT
, PICL_READ
,
5852 sizeof (uint8_t), PICL_PROP_GEO_ADDR
, NULLREAD
,
5853 NULLWRITE
, nodeh
, (picl_prophdl_t
*)NULL
,
5854 &geo_addr
)) != PICL_SUCCESS
) {
5855 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
5856 PICL_PROP_GEO_ADDR
, scsi_loc
, rc
);
5859 if ((rc
= create_property(PICL_PTYPE_CHARSTRING
, PICL_READ
,
5860 PICL_PROPNAMELEN_MAX
, PICL_PROP_DEVFS_PATH
, NULLREAD
,
5861 NULLWRITE
, nodeh
, NULL
, frup
->fru_path
)) !=
5863 FRUTREE_DEBUG3(FRUTREE_INIT
, PTREE_CREATE_PROP_FAILED
,
5864 PICL_PROP_DEVFS_PATH
, scsi_loc
, rc
);
5867 if ((rc
= ptree_add_node(frup
->frunodeh
, nodeh
)) != PICL_SUCCESS
) {
5868 (void) ptree_destroy_node(nodeh
);
5872 /* save the node in hashtable */
5873 if ((rc
= make_loc_data(scsi_loc
, &datap
)) != PICL_SUCCESS
) {
5876 locp
= LOCDATA_PTR(datap
);
5877 locp
->locnodeh
= nodeh
;
5878 /* save data in hash table */
5879 (void) hash_add_entry(nodeh
, (void *)datap
);
5881 if ((rc
= hash_lookup_entry(nodeh
, (void **)&hashptr
)) !=
5885 locp
= LOCDATA_PTR(hashptr
);
5887 if (is_cfgadm_ap
!= B_TRUE
) { /* device found in libdevinfo */
5888 locp
->state_mgr
= STATIC_LOC
;
5889 locp
->state
= LOC_STATE_CONNECTED
;
5892 if ((rc
= location_init(locp
)) != PICL_SUCCESS
) {
5896 /* if location is empty, done */
5897 if (locp
->state
== LOC_STATE_EMPTY
) {
5898 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5899 PICLEVENTARGVAL_EMPTY
, NULL
,
5900 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5901 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5902 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5904 return (PICL_SUCCESS
);
5907 /* create the fru node and initilize it */
5908 if ((rc
= create_fru_node(locp
, &child_frup
)) != PICL_SUCCESS
) {
5912 /* post picl event on location (frudata is consumer for these events) */
5913 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5914 loc_state
[locp
->state
], PICLEVENTARGVAL_EMPTY
,
5915 locp
->locnodeh
, WAIT
)) != PICL_SUCCESS
) {
5916 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5917 locp
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5920 if (child_frup
->state_mgr
== STATIC_LOC
) {
5921 /* derive the fru_type from name */
5922 while (i
< strlen(scsi_loc
)) {
5923 if (isdigit(scsi_loc
[i
])) {
5924 (void) strncpy(fru_type
, scsi_loc
, i
);
5930 if ((rc
= ptree_update_propval_by_name(child_frup
->frunodeh
,
5931 PICL_PROP_FRU_TYPE
, fru_type
, sizeof (fru_type
))) !=
5933 FRUTREE_DEBUG3(EVENTS
, PTREE_UPDATE_PROP_ERR
,
5934 PICL_PROP_FRU_TYPE
, child_frup
->name
, rc
);
5938 /* post picl state change event on fru state */
5939 if ((rc
= post_piclevent(PICLEVENT_STATE_CHANGE
,
5940 fru_state
[child_frup
->state
], PICLEVENTARGVAL_UNKNOWN
,
5941 child_frup
->frunodeh
, WAIT
)) != PICL_SUCCESS
) {
5942 FRUTREE_DEBUG3(EVENTS
, PTREE_POST_PICLEVENT_ERR
,
5943 frup
->name
, PICLEVENT_STATE_CHANGE
, rc
);
5945 /* for scsi FRUs we need not probe further */
5946 return (PICL_SUCCESS
);
5950 * recursive search in the subtree
5954 is_location_present_in_subtree(frutree_frunode_t
*frup
, const char *name
,
5957 frutree_callback_data_t fru_arg
;
5959 (void) strncpy(fru_arg
.node_name
, name
,
5960 sizeof (fru_arg
.node_name
));
5961 fru_arg
.retnodeh
= 0;
5962 if (ptree_walk_tree_by_class(frup
->frunodeh
, PICL_CLASS_LOCATION
,
5963 &fru_arg
, frutree_get_nodehdl
) == PICL_SUCCESS
) {
5964 if (fru_arg
.retnodeh
!= 0) { /* node is already present */