8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / snowbird / frutree / piclfrutree.c
blobf4a906c2329e20585a0c1c260678b9229d87f674
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
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]
20 * CDDL HEADER END
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
44 #include <stdlib.h>
45 #include <sys/param.h>
46 #include <strings.h>
47 #include <string.h>
48 #include <limits.h>
49 #include <syslog.h>
50 #include <pthread.h>
51 #include <thread.h>
52 #include <libintl.h>
53 #include <sys/systeminfo.h>
54 #include <sys/types.h>
55 #include <unistd.h>
56 #include <sys/stat.h>
57 #include <dirent.h>
58 #include <fcntl.h>
59 #include <ctype.h>
60 #include <time.h>
61 #include <poll.h>
62 #include <assert.h>
63 #include <libnvpair.h>
64 #include <alloca.h>
65 #include <stdarg.h>
66 #include <config_admin.h>
67 #include <libdevinfo.h>
68 #include <synch.h>
69 #include <sys/time.h>
70 #include <picl.h>
71 #include <picltree.h>
72 #include <picldefs.h>
73 #include <picld_pluginutil.h>
74 #include <libfru.h>
75 #include <sys/sysevent/dr.h>
76 #include <ptree_impl.h>
77 #include "piclfrutree.h"
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)
93 #define BUF_SIZE 25
94 #define HASH_INDEX(s, x) ((int)((x) & ((s) - 1)))
95 #define FRUDATA_PTR(_X) ((frutree_frunode_t *)(((hashdata_t *)(_X))->data))
96 #define LOCDATA_PTR(_X) ((frutree_locnode_t *)(((hashdata_t *)(_X))->data))
97 #define PORTDATA_PTR(_X) ((frutree_portnode_t *)(((hashdata_t *)(_X))->data))
99 /* Hash table structure */
100 typedef struct frutree_hash_elm {
101 picl_nodehdl_t hdl;
102 void *nodep;
103 struct frutree_hash_elm *nextp;
104 } frutree_hashelm_t;
106 typedef struct {
107 int hash_size;
108 frutree_hashelm_t **tbl;
109 } frutree_hash_t;
111 typedef struct {
112 frutree_datatype_t type;
113 void *data;
114 } hashdata_t;
116 typedef int (*callback_t)(picl_nodehdl_t, void *);
117 typedef enum {
118 INIT_FRU = 0x0,
119 CREATE_DEVICES_ENTRIES,
120 CONFIGURE_FRU,
121 UNCONFIGURE_FRU,
122 CPU_OFFLINE,
123 CPU_ONLINE,
124 HANDLE_CONFIGURE,
125 HANDLE_UNCONFIGURE,
126 HANDLE_INSERT,
127 HANDLE_REMOVE,
128 HANDLE_LOCSTATE_CHANGE,
129 POST_COND_EVENT,
130 POST_EVENTS
131 } action_t;
133 typedef struct {
134 action_t action;
135 void *data;
136 } frutree_dr_arg_t;
138 typedef struct event_queue {
139 frutree_dr_arg_t arg;
140 struct event_queue *next;
141 }ev_queue_t;
143 typedef struct {
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;
151 } delete_list_t;
153 typedef struct {
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);
191 * location states.
193 static char *loc_state[] = {
194 PICLEVENTARGVAL_UNKNOWN,
195 PICLEVENTARGVAL_EMPTY,
196 PICLEVENTARGVAL_CONNECTED,
197 PICLEVENTARGVAL_DISCONNECTED,
198 PICLEVENTARGVAL_CONNECTING,
199 PICLEVENTARGVAL_DISCONNECTING,
200 NULL
204 * fru states.
206 static char *fru_state[] = {
207 PICLEVENTARGVAL_UNKNOWN,
208 PICLEVENTARGVAL_CONFIGURED,
209 PICLEVENTARGVAL_UNCONFIGURED,
210 PICLEVENTARGVAL_CONFIGURING,
211 PICLEVENTARGVAL_UNCONFIGURING,
212 NULL
216 * fru condition.
218 static char *fru_cond[] = {
219 PICLEVENTARGVAL_UNKNOWN,
220 PICLEVENTARGVAL_FAILED,
221 PICLEVENTARGVAL_FAILING,
222 PICLEVENTARGVAL_OK,
223 PICLEVENTARGVAL_TESTING,
224 NULL
228 * port states.
230 static char *port_state[] = {
231 PICLEVENTARGVAL_DOWN,
232 PICLEVENTARGVAL_UP,
233 PICLEVENTARGVAL_UNKNOWN,
234 NULL
238 * port condition.
240 static char *port_cond[] = {
241 PICLEVENTARGVAL_OK,
242 PICLEVENTARGVAL_FAILING,
243 PICLEVENTARGVAL_FAILED,
244 PICLEVENTARGVAL_TESTING,
245 PICLEVENTARGVAL_UNKNOWN,
246 NULL
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 *,
275 size_t, void *);
276 static void frutree_dr_req_evhandler(const char *, const void *,
277 size_t, void *);
278 static void frutree_cpu_state_change_evhandler(const char *, const void *,
279 size_t, void *);
280 static void init_queue(void);
281 static void frutree_get_env();
282 static picl_errno_t hash_init(void);
283 static picl_errno_t hash_remove_entry(picl_nodehdl_t);
284 static picl_errno_t hash_lookup_entry(picl_nodehdl_t, void **);
285 static void hash_destroy();
286 static picl_errno_t initialize_frutree();
287 static picl_errno_t update_loc_state(frutree_locnode_t *, boolean_t *);
288 static int is_autoconfig_enabled(char *);
289 static picl_errno_t do_action(picl_nodehdl_t, int action, void *);
290 static picl_errno_t probe_fru(frutree_frunode_t *, boolean_t);
291 static picl_errno_t handle_fru_unconfigure(frutree_frunode_t *);
292 static picl_errno_t update_loc_state(frutree_locnode_t *, boolean_t *);
293 static picl_errno_t update_fru_state(frutree_frunode_t *, boolean_t *);
294 static picl_errno_t update_port_state(frutree_portnode_t *, boolean_t);
295 static picl_errno_t configure_fru(frutree_frunode_t *, cfga_flags_t);
296 static picl_errno_t post_piclevent(const char *, char *, char *,
297 picl_nodehdl_t, frutree_wait_t);
298 static picl_errno_t fru_init(frutree_frunode_t *);
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,
318 "SUNW_piclfrutree",
319 piclfrutree_init,
320 piclfrutree_fini
323 /* ptree entry points */
324 static void
325 piclfrutree_register(void)
327 FRUTREE_DEBUG0(FRUTREE_INIT, "piclfrutree register");
328 (void) picld_plugin_register(&frutree_reg_info);
331 static void
332 piclfrutree_init(void)
334 FRUTREE_DEBUG0(FRUTREE_INIT, "piclfrutree_init begin");
335 (void) rwlock_init(&hash_lock, USYNC_THREAD, NULL);
336 fini_called = 0;
338 /* read the environment variables */
339 frutree_get_env();
341 if (sysinfo(SI_PLATFORM, sys_name, sizeof (sys_name)) == -1) {
342 return;
345 if (hash_init() != PICL_SUCCESS) {
346 return;
348 if (initialize_frutree() != PICL_SUCCESS) {
349 return;
352 /* initialize the event queue */
353 (void) init_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) {
358 return;
360 /* register for picl events */
361 if (ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
362 frutree_dr_apstate_change_evhandler, NULL) !=
363 PICL_SUCCESS) {
364 return;
367 if (ptree_register_handler(PICLEVENT_DR_REQ,
368 frutree_dr_req_evhandler, NULL) != PICL_SUCCESS) {
369 return;
372 if (ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE,
373 frutree_cpu_state_change_evhandler, NULL) !=
374 PICL_SUCCESS) {
375 return;
378 if (ptree_register_handler(PICLEVENT_STATE_CHANGE,
379 frutree_wd_evhandler, NULL) != PICL_SUCCESS) {
380 return;
382 FRUTREE_DEBUG0(FRUTREE_INIT, "piclfrutree_init end");
385 static void
386 piclfrutree_fini(void)
388 ev_queue_t *event = NULL;
389 void *exitval;
391 FRUTREE_DEBUG0(EVENTS, "piclfrutree_fini begin");
393 fini_called = 1;
394 /* unregister event handlers */
395 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
396 frutree_dr_apstate_change_evhandler, NULL);
397 (void) ptree_unregister_handler(PICLEVENT_DR_REQ,
398 frutree_dr_req_evhandler, NULL);
399 (void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE,
400 frutree_cpu_state_change_evhandler, NULL);
401 (void) ptree_unregister_handler(PICLEVENT_STATE_CHANGE,
402 frutree_wd_evhandler, NULL);
404 /* flush the event queue */
405 (void) pthread_mutex_lock(&ev_mutex);
406 event = remove_from_queue();
407 while (event) {
408 free(event);
409 event = remove_from_queue();
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);
422 hash_destroy();
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 */
434 static void
435 frutree_get_env()
437 char *val;
438 int intval = 0;
440 /* read frutree debug flag value */
441 if (val = getenv(FRUTREE_DEBUG)) {
442 errno = 0;
443 intval = strtol(val, (char **)NULL, 0);
444 if (errno == 0) {
445 frutree_debug = intval;
446 FRUTREE_DEBUG1(PRINT_ALL, "SUNW_frutree:debug = %x",
447 frutree_debug);
451 /* read poll timeout value */
452 if (val = getenv(FRUTREE_POLL_TIMEOUT)) {
453 errno = 0;
454 intval = strtol(val, (char **)NULL, 0);
455 if (errno == 0) {
456 frutree_poll_timeout = intval;
460 /* read drwait time value */
461 if (val = getenv(FRUTREE_DRWAIT)) {
462 errno = 0;
463 intval = strtol(val, (char **)NULL, 0);
464 if (errno == 0) {
465 frutree_drwait_time = intval;
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
475 static int
476 frutree_get_nodehdl(picl_nodehdl_t nodeh, void *c_args)
478 picl_errno_t rc;
479 char name[PICL_PROPNAMELEN_MAX];
480 frutree_callback_data_t *fru_arg;
482 if (c_args == NULL)
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) {
488 return (rc);
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) */
499 static void
500 init_queue(void)
502 queue_head = NULL;
503 queue_tail = NULL;
506 /* add an event to the queue */
507 static int
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;
522 } else {
523 queue_tail->next = new_event;
525 queue_tail = new_event;
527 return (PICL_SUCCESS);
530 static ev_queue_t *
531 remove_from_queue(void)
533 ev_queue_t *event = NULL;
535 if (queue_head == NULL)
536 return (NULL);
538 event = queue_head;
539 queue_head = queue_head->next;
541 if (queue_head == NULL)
542 queue_tail = NULL;
543 return (event);
547 * event handler for watchdog expiry event (picl-state-change) event on
548 * watchdog-timer node
550 /* ARGSUSED */
551 static void
552 frutree_wd_evhandler(const char *ename, const void *earg, size_t size,
553 void *cookie)
555 nvlist_t *nvlp;
556 char *wd_state = NULL;
557 picl_errno_t rc;
558 picl_nodehdl_t wd_nodehdl;
559 char value[PICL_PROPNAMELEN_MAX];
560 frutree_callback_data_t fru_arg;
562 if (ename == NULL)
563 return;
565 if (strncmp(ename, PICLEVENT_STATE_CHANGE,
566 strlen(PICLEVENT_STATE_CHANGE))) {
567 return;
570 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
571 return;
574 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE,
575 &wd_nodehdl) == -1) {
576 nvlist_free(nvlp);
577 return;
580 if (nvlist_lookup_string(nvlp, PICLEVENTARG_STATE,
581 &wd_state) != 0) {
582 nvlist_free(nvlp);
583 return;
586 if ((rc = ptree_get_propval_by_name(wd_nodehdl,
587 PICL_PROP_CLASSNAME, value, sizeof (value))) != PICL_SUCCESS) {
588 nvlist_free(nvlp);
589 return;
592 /* if the event is not of watchdog-timer, return */
593 if (strcmp(value, PICL_CLASS_WATCHDOG_TIMER) != 0) {
594 nvlist_free(nvlp);
595 return;
598 FRUTREE_DEBUG1(EVENTS, "frutree:Received WD event(%s)", wd_state);
599 /* frutree plugin handles only watchdog expiry events */
600 if (strcmp(wd_state, PICL_PROPVAL_WD_STATE_EXPIRED) != 0) {
601 nvlist_free(nvlp);
602 return;
605 if ((rc = ptree_get_propval_by_name(wd_nodehdl,
606 PICL_PROP_WATCHDOG_ACTION, value, sizeof (value))) !=
607 PICL_SUCCESS) {
608 nvlist_free(nvlp);
609 return;
612 /* if action is none, dont do anything */
613 if (strcmp(value, PICL_PROPVAL_WD_ACTION_NONE) == 0) {
614 nvlist_free(nvlp);
615 return;
618 /* find the CPU nodehdl */
619 (void) strncpy(fru_arg.node_name, SANIBEL_PICLNODE_CPU,
620 sizeof (fru_arg.node_name));
621 fru_arg.retnodeh = 0;
622 if ((rc = ptree_walk_tree_by_class(chassish, PICL_CLASS_FRU,
623 &fru_arg, frutree_get_nodehdl)) != PICL_SUCCESS) {
624 nvlist_free(nvlp);
625 return;
628 if (fru_arg.retnodeh == NULL) {
629 nvlist_free(nvlp);
630 return;
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);
639 nvlist_free(nvlp);
643 * event handler for dr_ap_state_change event
644 * - determine the event type and queue it in dr_queue to handle it
646 /* ARGSUSED */
647 static void
648 frutree_dr_apstate_change_evhandler(const char *ename, const void *earg,
649 size_t size, void *cookie)
651 nvlist_t *nvlp;
652 char *name = NULL;
653 char *ap_id = NULL;
654 char *hint = NULL;
655 picl_nodehdl_t nodeh, childh;
656 hashdata_t *hashptr = NULL;
657 frutree_dr_arg_t dr_arg;
658 frutree_frunode_t *frup = NULL;
659 frutree_locnode_t *locp = NULL;
660 frutree_callback_data_t fru_arg;
661 boolean_t state_changed = B_FALSE;
663 if (ename == NULL)
664 return;
666 if (strncmp(ename, PICLEVENT_DR_AP_STATE_CHANGE,
667 strlen(PICLEVENT_DR_AP_STATE_CHANGE)) != 0) {
668 return;
671 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
672 return;
675 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id) == -1) {
676 nvlist_free(nvlp);
677 return;
680 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint) == -1) {
681 nvlist_free(nvlp);
682 return;
685 /* check for empty strings */
686 if (!ap_id || !hint) {
687 FRUTREE_DEBUG0(EVENTS, "Empty hint/ap_id");
688 nvlist_free(nvlp);
689 return;
692 /* get the location name */
693 name = strrchr(ap_id, ':');
694 if (name == NULL) {
695 name = ap_id;
696 } else {
697 name++;
700 /* find the loc object */
701 (void) strncpy(fru_arg.node_name, name, sizeof (fru_arg.node_name));
702 fru_arg.retnodeh = 0;
703 if (ptree_walk_tree_by_class(chassish, PICL_CLASS_LOCATION,
704 &fru_arg, frutree_get_nodehdl) != PICL_SUCCESS) {
705 nvlist_free(nvlp);
706 return;
709 if (fru_arg.retnodeh == NULL) {
710 nvlist_free(nvlp);
711 return;
713 nodeh = fru_arg.retnodeh;
715 if (hash_lookup_entry(nodeh, (void **)&hashptr) != PICL_SUCCESS) {
716 nvlist_free(nvlp);
717 return;
719 locp = LOCDATA_PTR(hashptr);
720 if (locp == NULL) {
721 nvlist_free(nvlp);
722 return;
725 if (strcmp(hint, DR_HINT_INSERT) == 0) {
726 dr_arg.action = HANDLE_INSERT;
727 dr_arg.data = locp;
728 (void) pthread_mutex_lock(&ev_mutex);
729 if (add_to_queue(dr_arg) != PICL_SUCCESS) {
730 (void) pthread_mutex_unlock(&ev_mutex);
731 nvlist_free(nvlp);
732 return;
734 (void) pthread_cond_signal(&ev_cond);
735 (void) pthread_mutex_unlock(&ev_mutex);
736 nvlist_free(nvlp);
737 return;
740 if (strcmp(hint, DR_HINT_REMOVE) == 0) {
741 dr_arg.action = HANDLE_REMOVE;
742 dr_arg.data = locp;
743 (void) pthread_mutex_lock(&ev_mutex);
744 if (add_to_queue(dr_arg) != PICL_SUCCESS) {
745 (void) pthread_mutex_unlock(&ev_mutex);
746 nvlist_free(nvlp);
747 return;
749 (void) pthread_cond_signal(&ev_cond);
750 (void) pthread_mutex_unlock(&ev_mutex);
751 nvlist_free(nvlp);
752 return;
755 if (strcmp(hint, DR_RESERVED_ATTR) != 0) { /* unknown event */
756 nvlist_free(nvlp);
757 return;
760 /* handle DR_RESERVED_ATTR HINT */
761 /* check if this is a fru event */
762 if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
763 &childh, sizeof (childh)) == PICL_SUCCESS) {
764 /* get the child fru information */
765 if (hash_lookup_entry(childh, (void **)&hashptr) ==
766 PICL_SUCCESS) {
767 frup = FRUDATA_PTR(hashptr);
770 if (frup == NULL) {
771 nvlist_free(nvlp);
772 return;
775 (void) pthread_mutex_lock(&frup->mutex);
776 if (frup->dr_in_progress) {
777 /* dr in progress, neglect the event */
778 (void) pthread_mutex_unlock(&frup->mutex);
779 nvlist_free(nvlp);
780 return;
782 (void) pthread_mutex_unlock(&frup->mutex);
784 if (update_fru_state(frup, &state_changed) != PICL_SUCCESS) {
785 nvlist_free(nvlp);
786 return;
789 if (state_changed) {
790 (void) pthread_mutex_lock(&frup->mutex);
791 /* figure out if this is config/unconfig operation */
792 if (frup->state == FRU_STATE_CONFIGURED) {
793 dr_arg.action = HANDLE_CONFIGURE;
794 dr_arg.data = frup;
795 } else if (frup->state == FRU_STATE_UNCONFIGURED) {
796 dr_arg.action = HANDLE_UNCONFIGURE;
797 dr_arg.data = frup;
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);
804 nvlist_free(nvlp);
805 return;
807 (void) pthread_cond_signal(&ev_cond);
808 (void) pthread_mutex_unlock(&ev_mutex);
809 nvlist_free(nvlp);
810 return;
813 /* check if this event is related to location */
814 (void) pthread_mutex_lock(&locp->mutex);
815 if (locp->dr_in_progress) {
816 /* dr in progress, neglect the event */
817 (void) pthread_mutex_unlock(&locp->mutex);
818 nvlist_free(nvlp);
819 return;
821 (void) pthread_mutex_unlock(&locp->mutex);
822 if (update_loc_state(locp, &state_changed) != PICL_SUCCESS) {
823 nvlist_free(nvlp);
824 return;
827 if (state_changed) { /* location state has changed */
828 dr_arg.action = HANDLE_LOCSTATE_CHANGE;
829 dr_arg.data = locp;
831 (void) pthread_mutex_lock(&ev_mutex);
832 if (add_to_queue(dr_arg) != PICL_SUCCESS) {
833 (void) pthread_mutex_unlock(&ev_mutex);
834 nvlist_free(nvlp);
835 return;
837 (void) pthread_cond_signal(&ev_cond);
838 (void) pthread_mutex_unlock(&ev_mutex);
839 nvlist_free(nvlp);
840 return;
842 /* duplicate event */
843 nvlist_free(nvlp);
847 * Event handler for dr_req event
849 /* ARGSUSED */
850 static void
851 frutree_dr_req_evhandler(const char *ename, const void *earg, size_t size,
852 void *cookie)
854 nvlist_t *nvlp;
855 char *name = NULL;
856 char *ap_id = NULL;
857 char *dr_req = NULL;
858 picl_nodehdl_t nodeh;
859 frutree_dr_arg_t dr_arg;
860 hashdata_t *hashptr = NULL;
861 frutree_frunode_t *frup = NULL;
862 frutree_callback_data_t fru_arg;
864 if (ename == NULL)
865 return;
867 if (strncmp(ename, PICLEVENT_DR_REQ, strlen(PICLEVENT_DR_REQ)) != 0) {
868 return;
870 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
871 return;
873 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id) == -1) {
874 nvlist_free(nvlp);
875 return;
877 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DR_REQ_TYPE,
878 &dr_req) == -1) {
879 nvlist_free(nvlp);
880 return;
883 if (!ap_id || !dr_req) {
884 FRUTREE_DEBUG0(EVENTS, "Empty dr_req/ap_id");
885 nvlist_free(nvlp);
886 return;
889 /* get the location name */
890 name = strrchr(ap_id, ':');
891 if (name == NULL) {
892 name = ap_id;
893 } else {
894 name++;
897 if (name == NULL) {
898 nvlist_free(nvlp);
899 return;
902 FRUTREE_DEBUG2(EVENTS, "DR_REQ:%s on %s", dr_req, name);
903 (void) strncpy(fru_arg.node_name, name, sizeof (fru_arg.node_name));
904 fru_arg.retnodeh = 0;
905 if (ptree_walk_tree_by_class(frutreeh, PICL_CLASS_FRU,
906 &fru_arg, frutree_get_nodehdl) != PICL_SUCCESS) {
907 nvlist_free(nvlp);
908 return;
911 if (fru_arg.retnodeh == NULL) {
912 nvlist_free(nvlp);
913 return;
915 nodeh = fru_arg.retnodeh;
917 /* find the fru object */
918 if (hash_lookup_entry(nodeh, (void **)&hashptr) != PICL_SUCCESS) {
919 nvlist_free(nvlp);
920 return;
922 frup = FRUDATA_PTR(hashptr);
923 if (frup == NULL) {
924 nvlist_free(nvlp);
925 return;
928 if (strcmp(dr_req, DR_REQ_INCOMING_RES) == 0) {
929 dr_arg.action = CONFIGURE_FRU;
930 dr_arg.data = frup;
932 } else if (strcmp(dr_req, DR_REQ_OUTGOING_RES) == 0) {
933 dr_arg.action = UNCONFIGURE_FRU;
934 dr_arg.data = frup;
936 } else {
937 nvlist_free(nvlp);
938 return;
941 (void) pthread_mutex_lock(&ev_mutex);
942 if (add_to_queue(dr_arg) != PICL_SUCCESS) {
943 (void) pthread_mutex_unlock(&ev_mutex);
944 nvlist_free(nvlp);
945 return;
947 (void) pthread_cond_signal(&ev_cond);
948 (void) pthread_mutex_unlock(&ev_mutex);
949 nvlist_free(nvlp);
953 * Event handler for cpu_state_change event
955 /* ARGSUSED */
956 static void
957 frutree_cpu_state_change_evhandler(const char *ename, const void *earg,
958 size_t size, void *cookie)
960 char *hint = NULL;
961 nvlist_t *nvlp;
962 frutree_frunode_t *frup = NULL;
963 hashdata_t *hashptr = NULL;
964 picl_nodehdl_t nodeh;
965 frutree_dr_arg_t dr_arg;
967 if (ename == NULL)
968 return;
970 if (strncmp(ename, PICLEVENT_CPU_STATE_CHANGE,
971 strlen(PICLEVENT_CPU_STATE_CHANGE)) != 0) {
972 return;
975 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
976 return;
978 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh) == -1) {
979 nvlist_free(nvlp);
980 return;
982 if (nvlist_lookup_string(nvlp, PICLEVENTARG_CPU_EV_TYPE, &hint) == -1) {
983 nvlist_free(nvlp);
984 return;
987 if (hash_lookup_entry(nodeh, (void **)&hashptr) != PICL_SUCCESS) {
988 nvlist_free(nvlp);
989 return;
991 frup = FRUDATA_PTR(hashptr);
992 if (frup == NULL) {
993 nvlist_free(nvlp);
994 return;
997 if (strcmp(hint, PICLEVENTARGVAL_OFFLINE) == 0) {
998 dr_arg.action = CPU_OFFLINE;
999 dr_arg.data = frup;
1000 } else if (strcmp(hint, PICLEVENTARGVAL_ONLINE) == 0) {
1001 dr_arg.action = CPU_ONLINE;
1002 dr_arg.data = frup;
1003 } else {
1004 nvlist_free(nvlp);
1005 return;
1008 (void) pthread_mutex_lock(&ev_mutex);
1009 if (add_to_queue(dr_arg) != PICL_SUCCESS) {
1010 (void) pthread_mutex_unlock(&ev_mutex);
1011 nvlist_free(nvlp);
1012 return;
1014 (void) pthread_cond_signal(&ev_cond);
1015 (void) pthread_mutex_unlock(&ev_mutex);
1016 nvlist_free(nvlp);
1019 static void
1020 attach_driver(char *driver)
1022 char cmd[BUF_SIZE];
1023 cmd[0] = '\0';
1024 (void) snprintf(cmd, sizeof (cmd), "%s %s",
1025 DEVFSADM_CMD, driver);
1026 (void) pclose(popen(cmd, "r"));
1030 * Find the node in platform tree with given devfs-path.
1031 * ptree_find_node is getting a node with devfs-path /pci@1f,0/pci@1,1
1032 * when we want to find node with /pci@1f,0/pci@1. The fix
1033 * is required in libpicltree. For now use ptree_walk_tree_by_class
1034 * to find the node.
1036 static int
1037 find_ref_parent(picl_nodehdl_t nodeh, void *c_args)
1039 picl_prophdl_t proph;
1040 ptree_propinfo_t propinfo;
1041 void *vbuf;
1042 frutree_callback_data_t *fru_arg;
1044 if (c_args == NULL)
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);
1058 if (vbuf == NULL)
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;
1082 void *vbuf;
1083 picl_errno_t rc = PICL_SUCCESS;
1084 char devfs_path[PICL_PROPNAMELEN_MAX];
1085 char value[PICL_PROPNAMELEN_MAX];
1086 char class[PICL_PROPNAMELEN_MAX];
1087 frutree_callback_data_t fru_arg;
1088 picl_nodehdl_t refhdl = 0, ref_parent = 0, nodehdl = 0;
1091 * for fru node, get the devfspath and bus-addr of
1092 * its parent.
1094 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
1095 class, sizeof (class)) != PICL_SUCCESS) {
1096 return (0);
1099 if (strcmp(class, PICL_CLASS_FRU) == 0) {
1100 if (ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
1101 &nodehdl, sizeof (nodehdl)) != PICL_SUCCESS) {
1102 return (0);
1104 } else if (strcmp(class, PICL_CLASS_PORT) == 0) {
1105 nodehdl = nodeh;
1106 } else {
1107 return (0);
1110 if (ptree_get_propval_by_name(nodehdl, PICL_PROP_DEVFS_PATH,
1111 devfs_path, sizeof (devfs_path)) != PICL_SUCCESS) {
1112 return (0);
1114 if (ptree_get_propval_by_name(nodehdl, PICL_PROP_BUS_ADDR,
1115 value, sizeof (value)) != PICL_SUCCESS) {
1116 return (0);
1119 /* find the node with same devfs-path */
1120 (void) strncpy(fru_arg.node_name, devfs_path,
1121 sizeof (fru_arg.node_name));
1122 fru_arg.retnodeh = 0;
1123 if (ptree_walk_tree_by_class(platformh, NULL,
1124 (void *)&fru_arg, find_ref_parent) != PICL_SUCCESS) {
1125 return (0);
1128 if (fru_arg.retnodeh == NULL)
1129 return (0);
1131 ref_parent = fru_arg.retnodeh;
1132 /* traverse thru childeren and find the reference node */
1133 rc = ptree_get_propval_by_name(ref_parent, PICL_PROP_CHILD,
1134 &refhdl, sizeof (picl_nodehdl_t));
1135 while (rc == PICL_SUCCESS) {
1136 nodehdl = refhdl;
1137 rc = ptree_get_propval_by_name(refhdl, PICL_PROP_PEER,
1138 &refhdl, sizeof (picl_nodehdl_t));
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) !=
1147 PICL_SUCCESS) {
1148 continue;
1152 if (ptree_get_propinfo(proph, &propinfo) != PICL_SUCCESS) {
1153 continue;
1156 vbuf = alloca(propinfo.piclinfo.size);
1157 if (vbuf == NULL)
1158 continue;
1160 if (ptree_get_propval(proph, vbuf,
1161 propinfo.piclinfo.size) != PICL_SUCCESS) {
1162 continue;
1165 if (strchr((char *)vbuf, ',') != NULL) {
1166 if (strcmp(value, (char *)vbuf) == 0) {
1167 return (nodehdl);
1169 } else {
1170 if (strtoul((char *)vbuf, NULL, 16) ==
1171 strtoul(value, NULL, 16)) {
1172 return (nodehdl);
1176 return (0);
1179 /* Hash Table Management */
1180 static void
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) {
1188 return;
1191 switch (type) {
1192 case FRU_TYPE:
1193 frup = (frutree_frunode_t *)datap->data;
1194 free(frup->name);
1195 (void) pthread_mutex_destroy(&frup->mutex);
1196 (void) pthread_cond_destroy(&frup->cond_cv);
1197 (void) pthread_cond_destroy(&frup->busy_cond_cv);
1198 free(frup);
1199 break;
1200 case LOC_TYPE:
1201 locp = (frutree_locnode_t *)datap->data;
1202 free(locp->name);
1203 (void) pthread_mutex_destroy(&locp->mutex);
1204 (void) pthread_cond_destroy(&locp->cond_cv);
1205 free(locp);
1206 break;
1207 case PORT_TYPE:
1208 portp = (frutree_portnode_t *)datap->data;
1209 free(portp->name);
1210 free(portp);
1211 break;
1213 free(datap);
1217 * Initialize the hash table
1219 static picl_errno_t
1220 hash_init(void)
1222 int i;
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
1243 static void
1244 hash_destroy(void)
1246 int i;
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);
1253 return;
1256 /* loop thru each linked list in the table and free */
1257 for (i = 0; i < node_hash_table.hash_size; ++i) {
1258 while (node_hash_table.tbl[i] != NULL) {
1259 el = node_hash_table.tbl[i];
1260 node_hash_table.tbl[i] = el->nextp;
1261 datap = (hashdata_t *)el->nodep;
1262 free_data(datap->type, datap);
1263 el->nodep = NULL;
1264 free(el);
1265 el = NULL;
1268 free(node_hash_table.tbl);
1269 (void) rw_unlock(&hash_lock);
1273 * Add an entry to the hash table
1275 static picl_errno_t
1276 hash_add_entry(picl_nodehdl_t hdl, void *nodep)
1278 int indx;
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));
1290 if (el == NULL) {
1291 (void) rw_unlock(&hash_lock);
1292 return (PICL_NOSPACE);
1295 el->hdl = hdl;
1296 el->nodep = nodep;
1297 el->nextp = NULL;
1299 if (frutree_debug & HASHTABLE) {
1300 picl_nodehdl_t nodeid;
1301 nodeid = hdl;
1302 cvt_ptree2picl(&nodeid);
1303 FRUTREE_DEBUG1(HASHTABLE, "added node: %llx", nodeid);
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
1323 static picl_errno_t
1324 hash_remove_entry(picl_nodehdl_t hdl)
1326 int i;
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 */
1346 prev = NULL;
1347 cur = node_hash_table.tbl[i];
1348 while (cur) {
1349 if (cur->hdl == hdl) {
1350 if (prev == NULL) { /* 1st elem in hash chain */
1351 node_hash_table.tbl[i] = cur->nextp;
1352 } else {
1353 prev->nextp = cur->nextp;
1355 datap = (hashdata_t *)cur->nodep;
1356 free_data(datap->type, datap);
1357 cur->nodep = NULL;
1358 free(cur);
1359 cur = NULL;
1361 if (frutree_debug & HASHTABLE) {
1362 picl_nodehdl_t nodeid;
1363 nodeid = hdl;
1364 cvt_ptree2picl(&nodeid);
1365 FRUTREE_DEBUG1(HASHTABLE, "removed node: %llx",
1366 nodeid);
1369 (void) rw_unlock(&hash_lock);
1370 return (PICL_SUCCESS);
1372 prev = cur;
1373 cur = cur->nextp;
1376 /* entry was not found */
1377 (void) rw_unlock(&hash_lock);
1378 return (PICL_NODENOTFOUND);
1382 * Lookup a handle in the table
1384 static picl_errno_t
1385 hash_lookup_entry(picl_nodehdl_t hdl, void **nodepp)
1387 int i;
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];
1410 while (el) {
1411 if (el->hdl == hdl) {
1412 *nodepp = el->nodep;
1413 (void) rw_unlock(&hash_lock);
1414 return (PICL_SUCCESS);
1416 el = el->nextp;
1418 (void) rw_unlock(&hash_lock);
1419 return (PICL_NODENOTFOUND);
1422 /* create and initialize data structure for a loc node */
1423 static picl_errno_t
1424 make_loc_data(char *full_name, hashdata_t **hashptr)
1426 char *name_copy;
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));
1438 if (locp == NULL) {
1439 free(datap);
1440 return (PICL_NOSPACE);
1443 /* make a copy of the name */
1444 name_copy = strdup(full_name);
1445 if (name_copy == NULL) {
1446 free(locp);
1447 free(datap);
1448 return (PICL_NOSPACE);
1451 /* initialize the data */
1452 locp->name = name_copy;
1453 locp->locnodeh = 0;
1454 locp->state = LOC_STATE_UNKNOWN;
1455 locp->prev_state = LOC_STATE_UNKNOWN;
1456 locp->cpu_node = B_FALSE;
1457 locp->autoconfig_enabled = B_FALSE;
1458 locp->state_mgr = UNKNOWN;
1459 locp->dr_in_progress = B_FALSE;
1460 (void) pthread_mutex_init(&locp->mutex, NULL);
1461 (void) pthread_cond_init(&locp->cond_cv, NULL);
1463 datap->data = locp;
1464 *hashptr = datap;
1465 return (PICL_SUCCESS);
1468 /* create and initialize data structure for a fru node */
1469 static picl_errno_t
1470 make_fru_data(char *full_name, hashdata_t **hashptr)
1472 char *name_copy;
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));
1484 if (frup == NULL) {
1485 free(datap);
1486 return (PICL_NOSPACE);
1489 /* make a copy of the name */
1490 name_copy = strdup(full_name);
1491 if (name_copy == NULL) {
1492 free(frup);
1493 free(datap);
1494 return (PICL_NOSPACE);
1497 /* initialize the data */
1498 frup->name = name_copy;
1499 frup->frunodeh = 0;
1500 frup->state = FRU_STATE_UNCONFIGURED;
1501 frup->prev_state = FRU_STATE_UNKNOWN;
1502 frup->cond = FRU_COND_UNKNOWN;
1503 frup->prev_cond = FRU_COND_UNKNOWN;
1504 frup->cpu_node = B_FALSE;
1505 frup->autoconfig_enabled = B_FALSE;
1506 frup->dr_in_progress = B_FALSE;
1507 frup->busy = B_FALSE;
1508 frup->state_mgr = UNKNOWN;
1509 frup->fru_path[0] = '\0';
1510 (void) pthread_mutex_init(&frup->mutex, NULL);
1511 (void) pthread_cond_init(&frup->cond_cv, NULL);
1512 (void) pthread_cond_init(&frup->busy_cond_cv, NULL);
1514 datap->data = frup;
1515 *hashptr = datap;
1516 return (PICL_SUCCESS);
1519 /* create and initialize data structure for a port node */
1520 static picl_errno_t
1521 make_port_data(char *full_name, hashdata_t **hashptr)
1523 char *name_copy;
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) {
1536 free(datap);
1537 return (PICL_NOSPACE);
1539 /* make a copy of the name */
1540 name_copy = strdup(full_name);
1541 if (name_copy == NULL) {
1542 free(portp);
1543 free(datap);
1544 return (PICL_NOSPACE);
1547 /* initialize the data */
1548 portp->name = name_copy;
1549 portp->portnodeh = 0;
1550 portp->state = PORT_STATE_UNKNOWN;
1551 portp->cond = PORT_COND_UNKNOWN;
1552 datap->data = portp;
1553 *hashptr = datap;
1554 return (PICL_SUCCESS);
1558 * utility routine to create table entries
1560 static picl_errno_t
1561 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
1563 picl_errno_t rc;
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) {
1573 return (rc);
1576 if ((rc = ptree_create_prop(&propinfo, class,
1577 &prophdl[0])) != PICL_SUCCESS) {
1578 return (rc);
1581 /* second column is reference property */
1582 (void) snprintf(buf, sizeof (buf), "_%s_", class);
1583 if ((rc = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1584 PICL_PTYPE_REFERENCE, PICL_READ,
1585 sizeof (picl_nodehdl_t), buf, NULLREAD,
1586 NULLWRITE)) != PICL_SUCCESS) {
1587 return (rc);
1590 if ((rc = ptree_create_prop(&propinfo, &refhdl,
1591 &prophdl[1])) != PICL_SUCCESS) {
1592 return (rc);
1595 /* add row to table */
1596 if ((rc = ptree_add_row_to_table(tblhdl, 2, prophdl)) != PICL_SUCCESS) {
1597 return (rc);
1599 return (PICL_SUCCESS);
1603 * Utility routine to create picl property
1605 static picl_errno_t
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)
1611 picl_errno_t rc;
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))
1621 != PICL_SUCCESS) {
1622 return (rc);
1626 if ((rc = ptree_get_prop_by_name(nodeh, pname, &proph)) ==
1627 PICL_SUCCESS) { /* property already exists */
1628 return (rc);
1631 rc = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1632 ptype, pmode, psize, pname, readfn, writefn);
1633 if (rc != PICL_SUCCESS) {
1634 return (rc);
1637 rc = ptree_create_and_add_prop(nodeh, &propinfo, vbuf, prophp);
1638 if (rc != PICL_SUCCESS) {
1639 return (rc);
1641 return (PICL_SUCCESS);
1645 * create frutree node, chassis node
1647 static picl_errno_t
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) {
1658 return (rc);
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) {
1665 return (rc);
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) {
1672 return (rc);
1674 FRUTREE_DEBUG1(FRUTREE_INIT, "chassish = %llx", chassish);
1676 /* Allocate fru data */
1677 if ((rc = make_fru_data(PICL_NODE_CHASSIS, &datap)) !=
1678 PICL_SUCCESS) {
1679 (void) ptree_destroy_node(chassish);
1680 return (rc);
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);
1690 return (rc);
1693 /* create chassis state property */
1694 if ((rc = create_property(PICL_PTYPE_CHARSTRING,
1695 PICL_READ, PICL_PROPNAMELEN_MAX, PICL_PROP_STATE,
1696 NULLREAD, NULLWRITE, chassish, (picl_prophdl_t *)NULL,
1697 PICLEVENTARGVAL_UNCONFIGURED)) != PICL_SUCCESS) {
1698 free_data(datap->type, datap);
1699 (void) ptree_delete_node(chassish);
1700 (void) ptree_destroy_node(chassish);
1701 return (rc);
1703 ap_status_time = (uint64_t)(time(NULL));
1704 if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
1705 sizeof (ap_status_time), PICL_PROP_STATUS_TIME,
1706 NULLREAD, NULLWRITE, chassish,
1707 NULL, &ap_status_time)) != PICL_SUCCESS) {
1708 free_data(datap->type, datap);
1709 (void) ptree_delete_node(chassish);
1710 (void) ptree_destroy_node(chassish);
1711 return (rc);
1714 /* save chassis info in hashtable */
1715 if ((rc = hash_add_entry(chassish,
1716 (void *)datap)) != PICL_SUCCESS) {
1717 free_data(datap->type, datap);
1718 (void) ptree_delete_node(chassish);
1719 (void) ptree_destroy_node(chassish);
1720 return (rc);
1722 return (PICL_SUCCESS);
1726 * Read the temporary property created by platform specific
1727 * plugin to get the config file name.
1729 static picl_errno_t
1730 get_configuration_file()
1732 picl_errno_t rc;
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) {
1738 return (rc);
1741 if ((rc = ptree_get_propval(proph, file_name,
1742 sizeof (file_name))) != PICL_SUCCESS) {
1743 return (rc);
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
1758 static picl_errno_t
1759 get_cfgadm_state(cfga_list_data_t *data, char *ap_id)
1761 int nlist;
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,
1771 NULL, NULL, 0);
1772 if (ap_list_err != CFGA_OK) {
1773 free(list);
1774 return (cfg2picl_errmap[ap_list_err][1]);
1777 (void) memcpy(data, list, sizeof (cfga_list_data_t));
1778 free(list);
1779 return (PICL_SUCCESS);
1783 * syncup with cfgadm data and read latest location state information
1785 static picl_errno_t
1786 update_loc_state(frutree_locnode_t *locp, boolean_t *updated)
1788 int i = 0;
1789 cfga_list_data_t *list = NULL;
1790 picl_errno_t rc, rc1;
1791 char valbuf[PICL_PROPNAMELEN_MAX];
1792 char slot_type[PICL_PROPNAMELEN_MAX];
1793 uint64_t ap_status_time;
1795 *updated = B_FALSE;
1796 if (locp->state_mgr == PLUGIN_PVT) {
1797 if ((rc = ptree_get_propval_by_name(locp->locnodeh,
1798 PICL_PROP_STATE, (void *)valbuf,
1799 PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
1800 return (rc);
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);
1812 *updated = B_TRUE;
1813 locp->prev_state = locp->state;
1814 for (i = 0; (loc_state[i] != NULL); i++) {
1815 if (strcmp(loc_state[i], valbuf) == 0) {
1816 locp->state = i;
1817 return (PICL_SUCCESS);
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));
1828 if (list == NULL) {
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) {
1836 free(list);
1837 return (rc1);
1839 if (strcmp(slot_type, SANIBEL_SCSI_SLOT) != 0 &&
1840 strcmp(slot_type, SANIBEL_IDE_SLOT) != 0) {
1841 free(list);
1842 return (rc);
1844 /* this is a scsi location */
1845 if (rc != PICL_NODENOTFOUND) {
1846 free(list);
1847 return (rc);
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) {
1856 *updated = B_TRUE;
1857 locp->prev_state = locp->state;
1858 locp->state = LOC_STATE_EMPTY;
1859 ap_status_time = (uint64_t)(time(NULL));
1860 if ((rc = ptree_update_propval_by_name(locp->locnodeh,
1861 PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
1862 sizeof (ap_status_time))) != PICL_SUCCESS) {
1863 FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
1864 PICL_PROP_STATUS_TIME, locp->name, rc);
1867 (void) pthread_mutex_unlock(&locp->mutex);
1868 free(list);
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) {
1876 *updated = B_TRUE;
1877 locp->prev_state = locp->state;
1878 locp->state = LOC_STATE_CONNECTED;
1880 break;
1881 case CFGA_STAT_DISCONNECTED:
1882 if (locp->state != LOC_STATE_DISCONNECTED) {
1883 *updated = B_TRUE;
1884 locp->prev_state = locp->state;
1885 locp->state = LOC_STATE_DISCONNECTED;
1887 break;
1888 case CFGA_STAT_EMPTY:
1889 if (locp->state != LOC_STATE_EMPTY) {
1890 *updated = B_TRUE;
1891 locp->prev_state = locp->state;
1892 locp->state = LOC_STATE_EMPTY;
1894 break;
1895 default:
1896 if (locp->state != LOC_STATE_UNKNOWN) {
1897 *updated = B_TRUE;
1898 locp->prev_state = locp->state;
1899 locp->state = LOC_STATE_UNKNOWN;
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)) {
1915 case 1:
1916 locp->autoconfig_enabled = B_TRUE;
1917 break;
1918 case 0:
1919 default:
1920 locp->autoconfig_enabled = B_FALSE;
1921 break;
1923 (void) pthread_mutex_unlock(&locp->mutex);
1925 free(list);
1926 return (PICL_SUCCESS);
1930 * volatile callback function to return the state value for a location
1932 static int
1933 get_loc_state(ptree_rarg_t *rarg, void *buf)
1935 picl_errno_t rc;
1936 frutree_dr_arg_t dr_arg;
1937 hashdata_t *hashptr = NULL;
1938 frutree_locnode_t *locp = NULL;
1939 boolean_t state_change = B_FALSE;
1941 if (buf == NULL) {
1942 return (PICL_INVALIDARG);
1945 if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
1946 PICL_SUCCESS) {
1947 return (rc);
1950 locp = LOCDATA_PTR(hashptr);
1951 if (locp == NULL) {
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);
1970 return (rc);
1973 /* if there is a state change, handle the event */
1974 if (state_change) {
1975 (void) pthread_mutex_lock(&locp->mutex);
1976 if (locp->state == LOC_STATE_EMPTY) { /* card removed */
1977 dr_arg.action = HANDLE_REMOVE;
1978 } else if (locp->prev_state == LOC_STATE_EMPTY) {
1979 dr_arg.action = HANDLE_INSERT; /* card inserted */
1980 } else {
1981 /* loc state changed */
1982 dr_arg.action = HANDLE_LOCSTATE_CHANGE;
1984 (void) pthread_mutex_unlock(&locp->mutex);
1985 dr_arg.data = locp;
1986 (void) pthread_mutex_lock(&ev_mutex);
1987 if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
1988 (void) pthread_mutex_unlock(&ev_mutex);
1989 FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
1990 "dr_ap_state_change", locp->name, rc);
1991 } else {
1992 (void) pthread_cond_signal(&ev_cond);
1993 (void) pthread_mutex_unlock(&ev_mutex);
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
2005 static picl_errno_t
2006 update_fru_state(frutree_frunode_t *frup, boolean_t *updated)
2008 int i;
2009 picl_errno_t rc;
2010 picl_nodehdl_t loch;
2011 uint64_t ap_status_time;
2012 hashdata_t *hashptr = NULL;
2013 cfga_list_data_t *list = NULL;
2014 frutree_locnode_t *locp = NULL;
2015 char valbuf[PICL_PROPNAMELEN_MAX];
2017 *updated = B_FALSE;
2018 if (frup->state_mgr == PLUGIN_PVT) {
2019 if ((rc = ptree_get_propval_by_name(frup->frunodeh,
2020 PICL_PROP_STATE, (void *)valbuf,
2021 PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
2022 return (rc);
2025 /* if there is a change in state, update the internal value */
2026 if (strcmp(fru_state[frup->state], valbuf) != 0) {
2027 *updated = B_TRUE;
2028 frup->prev_state = frup->state;
2029 ap_status_time = (uint64_t)(time(NULL));
2030 if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2031 PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
2032 sizeof (ap_status_time))) != PICL_SUCCESS) {
2033 if (rc == PICL_PROPNOTFOUND) {
2034 (void) create_property(
2035 PICL_PTYPE_TIMESTAMP, PICL_READ,
2036 sizeof (ap_status_time),
2037 PICL_PROP_STATUS_TIME,
2038 NULLREAD, NULLWRITE,
2039 frup->frunodeh,
2040 NULL, &ap_status_time);
2041 } else {
2042 FRUTREE_DEBUG3(EVENTS,
2043 PTREE_UPDATE_PROP_ERR,
2044 PICL_PROP_STATUS_TIME,
2045 frup->name, rc);
2048 for (i = 0; (fru_state[i] != NULL); i++) {
2049 if (strcmp(fru_state[i], valbuf) == 0) {
2050 frup->state = i;
2051 return (PICL_SUCCESS);
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) {
2063 return (rc);
2066 if ((rc = hash_lookup_entry(loch, (void **)&hashptr)) !=
2067 PICL_SUCCESS) {
2068 return (rc);
2070 locp = LOCDATA_PTR(hashptr);
2071 if (locp == NULL) {
2072 return (PICL_FAILURE);
2075 list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
2076 if (list == NULL) {
2077 return (PICL_NOSPACE);
2080 if ((rc = get_cfgadm_state(list, locp->name)) != PICL_SUCCESS) {
2081 free(list);
2082 return (rc);
2085 (void) pthread_mutex_lock(&frup->mutex);
2086 switch (list->ap_o_state) {
2087 case CFGA_STAT_CONFIGURED:
2088 if (frup->state != FRU_STATE_CONFIGURED) {
2089 *updated = B_TRUE;
2090 frup->prev_state = frup->state;
2091 frup->state = FRU_STATE_CONFIGURED;
2093 break;
2094 case CFGA_STAT_UNCONFIGURED:
2095 if (frup->state != FRU_STATE_UNCONFIGURED) {
2096 *updated = B_TRUE;
2097 frup->prev_state = frup->state;
2098 frup->state = FRU_STATE_UNCONFIGURED;
2100 break;
2101 default:
2102 if (frup->state != FRU_STATE_UNKNOWN) {
2103 *updated = B_TRUE;
2104 frup->prev_state = frup->state;
2105 frup->state = FRU_STATE_UNKNOWN;
2107 break;
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);
2131 free(list);
2132 return (PICL_SUCCESS);
2136 * syncup with cfgadm data and read latest fru condition information
2138 static picl_errno_t
2139 update_fru_condition(frutree_frunode_t *frup, boolean_t *updated)
2141 int i = 0;
2142 picl_errno_t rc;
2143 picl_nodehdl_t loch;
2144 uint64_t ap_cond_time;
2145 hashdata_t *hashptr = NULL;
2146 cfga_list_data_t *list = NULL;
2147 frutree_locnode_t *locp = NULL;
2148 char valbuf[PICL_PROPNAMELEN_MAX];
2150 *updated = B_FALSE;
2151 if (frup->state_mgr == PLUGIN_PVT) {
2152 if ((rc = ptree_get_propval_by_name(frup->frunodeh,
2153 PICL_PROP_CONDITION, (void *)valbuf,
2154 PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
2155 return (rc);
2159 * if there is a change in condition, update the
2160 * internal value
2162 if (strcmp(fru_cond[frup->cond], valbuf) != 0) {
2163 *updated = B_TRUE;
2164 ap_cond_time = (uint64_t)(time(NULL));
2165 if ((rc = ptree_update_propval_by_name(frup->frunodeh,
2166 PICL_PROP_CONDITION_TIME, (void *)&ap_cond_time,
2167 sizeof (ap_cond_time))) != PICL_SUCCESS) {
2168 FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
2169 PICL_PROP_CONDITION_TIME, frup->name,
2170 rc);
2172 frup->prev_cond = frup->cond;
2174 for (i = 0; (fru_cond[i] != NULL); i++) {
2175 if (strcmp(fru_cond[i], valbuf) == 0) {
2176 frup->cond = i;
2177 return (PICL_SUCCESS);
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) {
2189 return (rc);
2192 if ((rc = hash_lookup_entry(loch, (void **)&hashptr)) !=
2193 PICL_SUCCESS) {
2194 return (rc);
2197 locp = LOCDATA_PTR(hashptr);
2198 if (locp == NULL) {
2199 return (PICL_FAILURE);
2201 list = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
2202 if (list == NULL) {
2203 return (PICL_NOSPACE);
2206 if ((rc = get_cfgadm_state(list, locp->name)) != PICL_SUCCESS) {
2207 free(list);
2208 return (rc);
2211 switch (list->ap_cond) {
2212 case CFGA_COND_OK:
2213 if (frup->cond != FRU_COND_OK) {
2214 *updated = B_TRUE;
2215 frup->prev_cond = frup->cond;
2216 frup->cond = FRU_COND_OK;
2218 break;
2219 case CFGA_COND_FAILING:
2220 if (frup->cond != FRU_COND_FAILING) {
2221 *updated = B_TRUE;
2222 frup->prev_cond = frup->cond;
2223 frup->cond = FRU_COND_FAILING;
2225 break;
2226 case CFGA_COND_FAILED:
2227 case CFGA_COND_UNUSABLE:
2228 if (frup->cond != FRU_COND_FAILED) {
2229 *updated = B_TRUE;
2230 frup->prev_cond = frup->cond;
2231 frup->cond = FRU_COND_FAILED;
2233 break;
2234 default:
2235 if (frup->cond != FRU_COND_UNKNOWN) {
2236 *updated = B_TRUE;
2237 frup->prev_cond = frup->cond;
2238 frup->cond = FRU_COND_UNKNOWN;
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);
2251 free(list);
2252 return (PICL_SUCCESS);
2256 * Volatile callback function to read fru state
2258 static int
2259 get_fru_state(ptree_rarg_t *rarg, void *buf)
2261 picl_errno_t rc;
2262 hashdata_t *hashptr = NULL;
2263 frutree_frunode_t *frup = NULL;
2264 boolean_t state_change = B_FALSE;
2265 frutree_dr_arg_t dr_arg;
2267 if (buf == NULL) {
2268 return (PICL_INVALIDARG);
2271 if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
2272 PICL_SUCCESS) {
2273 return (rc);
2276 frup = FRUDATA_PTR(hashptr);
2277 if (frup == NULL) {
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);
2296 return (rc);
2299 /* if there is a state change, handle the event */
2300 if (state_change) {
2301 (void) pthread_mutex_lock(&frup->mutex);
2302 /* figure out if this is config/unconfig operation */
2303 if (frup->state == FRU_STATE_CONFIGURED) {
2304 dr_arg.action = HANDLE_CONFIGURE;
2305 dr_arg.data = frup;
2306 } else if (frup->state == FRU_STATE_UNCONFIGURED) {
2307 dr_arg.action = HANDLE_UNCONFIGURE;
2308 dr_arg.data = frup;
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);
2317 } else {
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
2332 static int
2333 get_fru_condition(ptree_rarg_t *rarg, void *buf)
2335 picl_errno_t rc;
2336 frutree_dr_arg_t dr_arg;
2337 hashdata_t *hashptr = NULL;
2338 frutree_frunode_t *frup = NULL;
2339 boolean_t cond_changed = B_FALSE;
2341 if (buf == NULL) {
2342 return (PICL_INVALIDARG);
2345 if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
2346 PICL_SUCCESS) {
2347 return (rc);
2350 frup = FRUDATA_PTR(hashptr);
2351 if (frup == NULL) {
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);
2371 return (rc);
2373 if (cond_changed) {
2374 dr_arg.action = POST_COND_EVENT;
2375 dr_arg.data = frup;
2376 (void) pthread_mutex_lock(&ev_mutex);
2377 if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
2378 (void) pthread_mutex_unlock(&ev_mutex);
2379 FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
2380 "condition event", frup->name, rc);
2381 } else {
2382 (void) pthread_cond_signal(&ev_cond);
2383 (void) pthread_mutex_unlock(&ev_mutex);
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);
2394 static void
2395 free_cache(frutree_cache_t *cachep)
2397 frutree_cache_t *tmp = NULL;
2398 if (cachep == NULL)
2399 return;
2401 while (cachep != NULL) {
2402 tmp = cachep;
2403 cachep = cachep->next;
2404 free(tmp);
2409 * traverse the /platform tree in PICL tree to create logical devices table
2411 static picl_errno_t
2412 probe_platform_tree(frutree_frunode_t *frup, frutree_device_args_t **devp)
2414 picl_errno_t rc;
2415 picl_nodehdl_t refhdl = 0;
2416 char class[PICL_CLASSNAMELEN_MAX];
2417 frutree_device_args_t *device = NULL;
2418 picl_prophdl_t tblprophdl;
2419 picl_prophdl_t dev_tblhdl, env_tblhdl = 0;
2421 if (devp == NULL) {
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)) !=
2438 PICL_SUCCESS) {
2439 return (rc);
2442 if ((rc = ptree_get_propval_by_name(refhdl, PICL_PROP_CLASSNAME,
2443 class, sizeof (class))) != PICL_SUCCESS) {
2444 return (rc);
2447 if ((rc = create_table_entry(dev_tblhdl, refhdl, class)) !=
2448 PICL_SUCCESS) {
2449 return (rc);
2452 /* create Environment devices table property */
2453 if ((rc = create_property(PICL_PTYPE_TABLE, PICL_READ,
2454 sizeof (picl_prophdl_t), PICL_PROP_ENV, NULLREAD,
2455 NULLWRITE, frup->frunodeh, &tblprophdl, &env_tblhdl)) !=
2456 PICL_SUCCESS) {
2457 return (rc);
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);
2471 return (rc);
2473 return (PICL_SUCCESS);
2477 * create temp conf file to pass it to picld util lib to create
2478 * nodes under the fru
2480 static picl_errno_t
2481 create_fru_children(frutree_frunode_t *frup, frutree_device_args_t device)
2483 int fd;
2484 picl_errno_t rc;
2485 char conffile[MAXPATHLEN];
2486 char dir[MAXPATHLEN];
2487 struct stat file_stat;
2488 char version[BUF_SIZE];
2489 frutree_cache_t *cachep = NULL;
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) {
2507 (void) rmdir(dir);
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);
2515 (void) rmdir(dir);
2516 (void) close(fd);
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)) {
2524 (void) close(fd);
2525 (void) remove(conffile);
2526 (void) rmdir(dir);
2527 return (PICL_FAILURE);
2529 cachep = cachep->next;
2531 (void) close(fd);
2533 /* create child nodes for fru using the conffile created */
2534 if ((rc = picld_pluginutil_parse_config_file(frup->frunodeh,
2535 conffile)) != PICL_SUCCESS) {
2536 (void) remove(conffile);
2537 (void) rmdir(dir);
2538 return (rc);
2540 (void) remove(conffile);
2541 (void) rmdir(dir);
2543 if ((rc = fru_init(frup)) != PICL_SUCCESS) {
2544 return (rc);
2546 return (PICL_SUCCESS);
2550 * probes libdevinfo and create the port nodes under a fru
2551 * probes for any scsi devices under a fru
2553 static picl_errno_t
2554 probe_fru(frutree_frunode_t *frup, boolean_t load_drivers)
2556 picl_errno_t rc;
2557 picl_nodehdl_t child, loch;
2558 char slot_type[PICL_PROPNAMELEN_MAX];
2559 char devfs_path[PICL_PROPNAMELEN_MAX];
2560 char probe_path[PICL_PROPNAMELEN_MAX];
2561 frutree_device_args_t *device = NULL;
2563 if (frup == 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) {
2570 return (rc);
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);
2586 free(device);
2590 * if parent has NULL probe-path, skip probing this fru
2591 * probe only child locations (if present).
2592 * if probe-path is not present use devfs-path as path for
2593 * probing the fru.
2595 rc = ptree_get_propval_by_name(loch, PICL_PROP_PROBE_PATH,
2596 probe_path, sizeof (probe_path));
2597 if (rc != PICL_SUCCESS) {
2598 if (!devfs_path[0]) { /* devfspath is also not present */
2599 return (PICL_SUCCESS); /* nothing to probe */
2600 } else {
2601 /* use devfs-path as path for probing */
2602 if ((rc = get_fru_path(devfs_path, frup)) !=
2603 PICL_SUCCESS) {
2604 return (rc);
2607 } else {
2608 /* NULL path, skip probing this fru */
2609 if (strlen(probe_path) == 0) {
2610 rc = fru_init(frup); /* probe its children */
2611 return (rc);
2612 } else {
2613 /* valid probe-path */
2614 if ((rc = get_fru_path(probe_path, frup)) !=
2615 PICL_SUCCESS) {
2616 return (rc);
2621 /* children present already, no need to probe libdevinfo */
2622 rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_CHILD,
2623 &child, sizeof (picl_nodehdl_t));
2624 if (rc == PICL_SUCCESS) { /* child present */
2625 if ((rc = fru_init(frup)) != PICL_SUCCESS) {
2626 return (rc);
2628 /* now create the scsi nodes for this fru */
2629 if ((rc = probe_for_scsi_frus(frup)) != PICL_SUCCESS) {
2630 return (rc);
2632 return (PICL_SUCCESS);
2635 if (ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
2636 &loch, sizeof (loch)) != PICL_SUCCESS) {
2637 return (rc);
2639 if ((rc = ptree_get_propval_by_name(loch, PICL_PROP_SLOT_TYPE,
2640 slot_type, sizeof (slot_type))) != PICL_SUCCESS) {
2641 return (rc);
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)) !=
2658 PICL_SUCCESS) {
2659 free_cache(device->first);
2660 free(device);
2661 return (rc);
2664 if (device->first != NULL) {
2665 if ((rc = create_fru_children(frup, *device)) != PICL_SUCCESS) {
2666 free_cache(device->first);
2667 free(device);
2668 return (rc);
2671 free_cache(device->first);
2672 free(device);
2674 /* now create the scsi nodes for this fru */
2675 if ((rc = probe_for_scsi_frus(frup)) != PICL_SUCCESS) {
2676 return (rc);
2678 return (PICL_SUCCESS);
2682 * callback function for ptree_walk_tree_by_class,
2683 * used to update hashtable during DR_HINT_REMOVE event
2685 /*ARGSUSED*/
2686 static int
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) {
2691 return (rc);
2693 return (PICL_WALK_CONTINUE);
2697 * routine to handle DR_HINT_REMOVE
2699 static picl_errno_t
2700 handle_fru_remove(frutree_frunode_t *frup)
2702 picl_errno_t rc = PICL_SUCCESS;
2704 if (frup == NULL) {
2705 return (PICL_FAILURE);
2708 if ((rc = ptree_walk_tree_by_class(frup->frunodeh,
2709 NULL, NULL, frutree_update_hash)) != PICL_SUCCESS) {
2710 return (rc);
2712 (void) ptree_delete_node(frup->frunodeh);
2713 (void) ptree_destroy_node(frup->frunodeh);
2714 if ((rc = hash_remove_entry(frup->frunodeh)) !=
2715 PICL_SUCCESS) {
2716 return (rc);
2718 return (PICL_SUCCESS);
2721 /* remove State and Condition props for all the nodes under fru */
2722 /*ARGSUSED*/
2723 static int
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) {
2743 return (rc);
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
2770 static picl_errno_t
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];
2780 if (frup == NULL) {
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) {
2800 return (rc);
2803 /* remove all the fru nodes under the child locations */
2804 retval = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_CHILD,
2805 &peerh, sizeof (peerh));
2806 while (retval == PICL_SUCCESS) {
2807 nodeh = peerh;
2808 retval = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
2809 &peerh, sizeof (peerh));
2810 if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2811 class, sizeof (class))) != PICL_SUCCESS) {
2812 return (rc);
2815 if (strcmp(class, PICL_CLASS_PORT) == 0) {
2816 continue;
2819 /* if the child location has fru, delete the fru */
2820 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
2821 &childh, sizeof (childh)) != PICL_SUCCESS) {
2822 continue;
2825 /* child is present under the location */
2826 if ((rc = hash_lookup_entry(childh, (void **)&hashptr)) !=
2827 PICL_SUCCESS) {
2828 return (rc);
2830 child_frup = FRUDATA_PTR(hashptr);
2831 (void) handle_fru_remove(child_frup);
2833 return (PICL_SUCCESS);
2837 * create the properties under the fru
2839 static picl_errno_t
2840 create_fru_props(frutree_frunode_t *frup)
2842 picl_errno_t rc;
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])) !=
2851 PICL_SUCCESS) {
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);
2867 return (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])) !=
2875 PICL_SUCCESS) {
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);
2889 return (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)) !=
2897 PICL_SUCCESS) {
2898 FRUTREE_DEBUG3(EVENTS, PTREE_CREATE_PROP_FAILED,
2899 PICL_PROP_ADMIN_LOCK, frup->name, rc);
2901 return (rc);
2905 * calls libcfgadm API to do a connect on a location
2907 static picl_errno_t
2908 connect_fru(frutree_locnode_t *locp)
2910 picl_errno_t rc;
2911 cfga_err_t ap_list_err;
2912 cfga_flags_t flags = 0;
2913 boolean_t state_change;
2914 uint64_t ap_status_time;
2915 hrtime_t start;
2916 hrtime_t end;
2918 if (locp == NULL) {
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) {
2939 end = gethrtime();
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
2994 static picl_errno_t
2995 disconnect_fru(frutree_locnode_t *locp)
2997 picl_errno_t rc;
2998 picl_nodehdl_t childh;
2999 hashdata_t *hashptr = NULL;
3000 timestruc_t to;
3001 struct timeval tp;
3002 hrtime_t start, end;
3003 cfga_err_t ap_list_err;
3004 cfga_flags_t flags = 0;
3005 boolean_t state_change;
3006 uint64_t ap_status_time;
3007 frutree_frunode_t *frup = NULL;
3009 if (locp == 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) ==
3024 PICL_SUCCESS) {
3025 frup = FRUDATA_PTR(hashptr);
3029 if (frup == NULL) {
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,
3041 &frup->mutex, &to);
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) {
3070 end = gethrtime();
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
3120 static void
3121 handle_fru_configure(frutree_frunode_t *frup)
3123 picl_errno_t rc;
3124 boolean_t cond_changed;
3126 if (frup == NULL)
3127 return;
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);
3135 if (cond_changed) {
3136 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3137 fru_cond[frup->cond], fru_cond[frup->prev_cond],
3138 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3139 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3140 frup->name, PICLEVENT_CONDITION_CHANGE, rc);
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)
3156 static picl_errno_t
3157 configure_fru(frutree_frunode_t *frup, cfga_flags_t flags)
3159 picl_errno_t rc;
3160 picl_nodehdl_t parenth;
3161 timestruc_t to;
3162 struct timeval tp;
3163 hrtime_t start, end;
3164 cfga_err_t ap_list_err;
3165 uint64_t ap_status_time;
3166 hashdata_t *hashptr = NULL;
3167 frutree_locnode_t *locp = NULL;
3168 boolean_t state_change, cond_changed;
3170 if (frup == NULL) {
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) {
3185 return (rc);
3188 if ((rc = hash_lookup_entry(parenth, (void **)&hashptr)) !=
3189 PICL_SUCCESS) {
3190 return (rc);
3192 locp = LOCDATA_PTR(hashptr);
3193 if (locp == NULL) {
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,
3206 &locp->mutex, &to);
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) {
3235 end = gethrtime();
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);
3254 if (state_change) {
3255 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3256 fru_cond[frup->cond], fru_cond[frup->prev_cond],
3257 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3258 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3259 frup->name, PICLEVENT_CONDITION_CHANGE,
3260 rc);
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);
3283 if (cond_changed) {
3284 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3285 fru_cond[frup->cond], fru_cond[frup->prev_cond],
3286 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3287 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3288 frup->name, PICLEVENT_CONDITION_CHANGE, rc);
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)
3306 static picl_errno_t
3307 unconfigure_fru(frutree_frunode_t *frup, cfga_flags_t flags)
3309 picl_errno_t rc;
3310 cfga_err_t ap_list_err;
3311 boolean_t state_change;
3312 uint64_t ap_status_time;
3313 hrtime_t start;
3314 hrtime_t end;
3316 if (frup == NULL) {
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,
3337 &frup->mutex);
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) {
3349 end = gethrtime();
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);
3367 if (state_change) {
3368 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3369 fru_cond[frup->cond], fru_cond[frup->prev_cond],
3370 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3371 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3372 frup->name, PICLEVENT_CONDITION_CHANGE,
3373 rc);
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,
3405 frup->name, rc);
3407 if (state_change) {
3408 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
3409 fru_cond[frup->cond], fru_cond[frup->prev_cond],
3410 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
3411 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
3412 frup->name, PICLEVENT_CONDITION_CHANGE, rc);
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 */
3426 static int
3427 create_fru_node(frutree_locnode_t *locp, frutree_frunode_t **child_frupp)
3429 picl_errno_t rc;
3430 hashdata_t *fru_data = NULL;
3431 frutree_frunode_t *frup = NULL;
3432 picl_nodehdl_t fruh, child;
3433 char slot_type[PICL_PROPNAMELEN_MAX];
3434 char fru_name[PICL_PROPNAMELEN_MAX];
3435 char apid_type[PICL_PROPNAMELEN_MAX];
3436 boolean_t fru_present = B_FALSE;
3437 boolean_t state_changed = B_FALSE;
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;
3448 fruh = child;
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) {
3458 return (rc);
3462 /* initialize internal data structures */
3463 if ((rc = make_fru_data(fru_name, &fru_data)) != PICL_SUCCESS) {
3464 return (rc);
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));
3476 return (rc);
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)) !=
3492 PICL_SUCCESS) {
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)) !=
3499 PICL_SUCCESS) {
3500 (void) ptree_destroy_node(fruh);
3501 (void) hash_remove_entry(fruh);
3502 return (rc);
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) {
3512 return (rc);
3514 return (PICL_SUCCESS);
3517 static picl_errno_t
3518 add_node2cache(picl_nodehdl_t nodeh, char *class, frutree_cache_t **cacheptr)
3520 int instance;
3521 picl_errno_t rc;
3522 char driver[PICL_PROPNAMELEN_MAX];
3523 char bus_addr[PICL_PROPNAMELEN_MAX];
3524 char devfs_path[PICL_PROPNAMELEN_MAX];
3525 char node_name[PICL_PROPNAMELEN_MAX];
3526 char port_type[PICL_PROPNAMELEN_MAX];
3527 char label[PICL_PROPNAMELEN_MAX];
3528 frutree_cache_t *cachep = NULL;
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));
3548 } else {
3549 return (PICL_FAILURE);
3552 if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_INSTANCE,
3553 &instance, sizeof (instance))) != PICL_SUCCESS) {
3554 return (rc);
3557 /* load the driver */
3558 if (instance < 0) {
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) {
3564 return (rc);
3567 /* get either bus address or unit address */
3568 if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_BUS_ADDR, bus_addr,
3569 sizeof (bus_addr))) != PICL_SUCCESS) {
3570 if ((rc = ptree_get_propval_by_name(nodeh,
3571 PICL_PROP_UNIT_ADDRESS, bus_addr,
3572 sizeof (bus_addr))) != PICL_SUCCESS) {
3573 return (rc);
3577 if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_DRIVER_NAME,
3578 driver, sizeof (driver))) != PICL_SUCCESS) {
3579 return (rc);
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),
3590 "\n%s %s%d %s\n"
3591 "\t%s %s %s %s 0 \"%s %d\"\n"
3592 "\t%s %s %s %s 0 \"%s\"\n"
3593 "\t%s %s %s %s 1 %d\n"
3594 "\t%s %s %s %s 0 \"%s\"\n"
3595 "\t%s %s %s %s 0 \"%s\"\n"
3596 "%s\n",
3597 "NODE", driver, instance, node_name,
3598 "PROP", PICL_PROP_LABEL, "string", "r", label, instance,
3599 "PROP", PICL_PROP_BUS_ADDR, "string", "r", bus_addr,
3600 "PROP", PICL_PROP_GEO_ADDR, "uint", "r", instance,
3601 "PROP", PICL_PROP_PORT_TYPE, "string", "r", port_type,
3602 "PROP", PICL_PROP_DEVFS_PATH, "string", "r", devfs_path,
3603 "ENDNODE");
3604 *cacheptr = cachep;
3605 return (PICL_SUCCESS);
3608 /* ARGSUSED */
3609 static int
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,
3634 class);
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
3678 static picl_errno_t
3679 get_loc_type(frutree_locnode_t *locp)
3681 picl_errno_t rc;
3682 cfga_list_data_t *list = NULL;
3683 char valbuf[PICL_PROPNAMELEN_MAX];
3684 char slot_type[PICL_PROPNAMELEN_MAX];
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));
3698 if (list == NULL) {
3699 return (PICL_NOSPACE);
3702 if ((rc = get_cfgadm_state(list, locp->name)) == PICL_SUCCESS) {
3703 locp->state_mgr = CFGADM_AP;
3704 } else {
3705 if ((rc = ptree_get_propval_by_name(locp->locnodeh,
3706 PICL_PROP_SLOT_TYPE, slot_type,
3707 sizeof (slot_type))) != PICL_SUCCESS) {
3708 free(list);
3709 return (rc);
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
3716 * not present
3718 locp->state_mgr = CFGADM_AP;
3719 } else {
3721 * devices like PMC card doesnt showup in cfgadm
3723 locp->state_mgr = STATIC_LOC;
3726 free(list);
3727 return (PICL_SUCCESS);
3731 * Initialize the location node.(create all the props)
3733 static picl_errno_t
3734 location_init(frutree_locnode_t *locp)
3736 picl_errno_t rc;
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;
3750 * Algorithm:
3751 * if "State" prop is already created (node is managed by other plugin)
3752 * does nothing
3753 * else if cfgadm ap is found
3754 * creates State prop and intializes it
3755 * else
3756 * find the nodes using libdevinfo under a given path
3757 * at given geoaddr
3758 * if node is found
3759 * mark node state a connected
3760 * else
3761 * mark node state a empty
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;
3777 } else {
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);
3789 return (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)) !=
3797 PICL_SUCCESS) {
3798 FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
3799 PICL_PROP_STATUS_TIME, locp->name, rc);
3800 return (rc);
3803 if ((rc = update_loc_state(locp, &state_change)) != PICL_SUCCESS) {
3804 FRUTREE_DEBUG2(FRUTREE_INIT, GET_LOC_STATE_ERR, locp->name, rc);
3805 return (rc);
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) {
3817 return (port_type);
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;
3833 return (port_type);
3836 /* volatile callback function to get port condition */
3837 static int
3838 get_port_condition(ptree_rarg_t *rarg, void *buf)
3840 picl_errno_t rc;
3841 hashdata_t *hashptr = NULL;
3842 frutree_portnode_t *portp = NULL;
3843 frutree_port_type_t port_type;
3845 if (buf == NULL) {
3846 return (PICL_INVALIDARG);
3849 if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
3850 PICL_SUCCESS) {
3851 return (rc);
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) {
3868 return (rc);
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 */
3877 static int
3878 get_port_state(ptree_rarg_t *rarg, void *buf)
3880 picl_errno_t rc;
3881 hashdata_t *hashptr = NULL;
3882 frutree_portnode_t *portp = NULL;
3883 frutree_port_type_t port_type;
3885 if (buf == NULL) {
3886 return (PICL_INVALIDARG);
3888 if ((rc = hash_lookup_entry(rarg->nodeh, (void **)&hashptr)) !=
3889 PICL_SUCCESS) {
3890 return (rc);
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) {
3906 return (rc);
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
3916 static picl_errno_t
3917 port_init(frutree_portnode_t *portp)
3919 picl_prophdl_t proph;
3920 ptree_propinfo_t propinfo;
3921 void *vbuf;
3922 picl_errno_t rc;
3923 uint64_t status_time;
3924 picl_nodehdl_t refhdl;
3925 frutree_device_args_t device;
3926 picl_prophdl_t tblprophdl, tblhdl;
3927 char class[PICL_PROPNAMELEN_MAX];
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 */
3935 if (refhdl != 0) {
3936 /* create Devices table property */
3937 if ((rc = create_property(PICL_PTYPE_TABLE, PICL_READ,
3938 sizeof (picl_prophdl_t), PICL_PROP_DEVICES,
3939 NULLREAD, NULLWRITE, portp->portnodeh, &tblprophdl,
3940 &tblhdl)) != PICL_SUCCESS) {
3941 return (rc);
3944 /* walk down the subtree and populate Devices */
3945 if ((rc = ptree_get_propval_by_name(refhdl,
3946 PICL_PROP_CLASSNAME, class,
3947 sizeof (class))) != PICL_SUCCESS) {
3948 return (rc);
3950 if ((rc = create_table_entry(tblhdl, refhdl, class)) !=
3951 PICL_SUCCESS) {
3952 return (rc);
3955 device.nodeh = refhdl;
3956 device.device_tblhdl = tblhdl;
3957 device.first = NULL;
3958 device.last = NULL;
3959 device.create_cache = B_FALSE;
3961 if ((rc = do_action(refhdl, CREATE_DEVICES_ENTRIES,
3962 (void *)&device)) != PICL_SUCCESS) {
3963 return (rc);
3966 if ((rc = ptree_get_prop_by_name(refhdl, PICL_PROP_INSTANCE,
3967 &proph)) != PICL_SUCCESS) {
3968 return (rc);
3970 if ((rc = ptree_get_propinfo(proph, &propinfo)) !=
3971 PICL_SUCCESS) {
3972 return (rc);
3974 vbuf = alloca(propinfo.piclinfo.size);
3975 if (vbuf == NULL)
3976 return (PICL_NOSPACE);
3978 if ((rc = ptree_get_propval(proph, vbuf,
3979 propinfo.piclinfo.size)) != PICL_SUCCESS) {
3980 return (rc);
3982 portp->instance = *(int *)vbuf;
3984 if ((rc = ptree_get_prop_by_name(refhdl,
3985 PICL_PROP_DRIVER_NAME, &proph)) != PICL_SUCCESS) {
3986 return (rc);
3988 if ((rc = ptree_get_propinfo(proph, &propinfo)) !=
3989 PICL_SUCCESS) {
3990 return (rc);
3992 vbuf = alloca(propinfo.piclinfo.size);
3993 if (vbuf == NULL)
3994 return (PICL_NOSPACE);
3996 if ((rc = ptree_get_propval(proph, vbuf,
3997 propinfo.piclinfo.size)) != PICL_SUCCESS) {
3998 return (rc);
4001 (void) strncpy(portp->driver, (char *)vbuf,
4002 sizeof (portp->driver));
4003 } else {
4004 /* this node is created using libdevinfo or conf file */
4005 if ((rc = get_port_info(portp)) != PICL_SUCCESS) {
4006 return (rc);
4010 /* create state and condition properties */
4011 if ((rc = create_property(PICL_PTYPE_CHARSTRING,
4012 PICL_READ | PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
4013 PICL_PROP_STATE, get_port_state, NULLWRITE, portp->portnodeh,
4014 NULL, port_state[portp->state])) != PICL_SUCCESS) {
4015 return (rc);
4018 status_time = (uint64_t)(time(NULL));
4019 if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
4020 sizeof (uint64_t), PICL_PROP_STATUS_TIME, NULLREAD,
4021 NULLWRITE, portp->portnodeh, NULL, &status_time)) !=
4022 PICL_SUCCESS) {
4023 return (rc);
4026 if ((rc = create_property(PICL_PTYPE_CHARSTRING,
4027 PICL_READ | PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
4028 PICL_PROP_CONDITION, get_port_condition, NULLWRITE,
4029 portp->portnodeh, NULL, port_cond[portp->cond])) !=
4030 PICL_SUCCESS) {
4031 return (rc);
4033 if ((rc = create_property(PICL_PTYPE_TIMESTAMP, PICL_READ,
4034 sizeof (uint64_t), PICL_PROP_CONDITION_TIME, NULLREAD,
4035 NULLWRITE, portp->portnodeh, NULL, &status_time)) !=
4036 PICL_SUCCESS) {
4037 return (rc);
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
4047 static picl_errno_t
4048 init_scsi_slot(frutree_frunode_t *frup, frutree_locnode_t **ptr2locp,
4049 boolean_t *node_name_changed)
4051 picl_errno_t rc;
4052 char devfs_path[PICL_PROPNAMELEN_MAX];
4053 char bus_addr[PICL_PROPNAMELEN_MAX];
4054 char label[PICL_PROPNAMELEN_MAX];
4055 char name[MAXPATHLEN];
4056 uint8_t geo_addr = 0;
4057 frutree_locnode_t *locp = NULL, *new_locp = NULL;
4058 hashdata_t *hashptr = NULL;
4059 picl_nodehdl_t nodeh;
4061 if (ptr2locp == NULL) {
4062 return (PICL_INVALIDARG);
4064 locp = (frutree_locnode_t *)*ptr2locp;
4065 *node_name_changed = B_FALSE;
4067 if (locp == NULL) {
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) {
4074 return (rc);
4077 if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4078 PICL_PROP_BUS_ADDR, bus_addr,
4079 sizeof (bus_addr))) != PICL_SUCCESS) {
4080 return (rc);
4083 /* find the dynamic ap_id from libcfgadm */
4084 if ((rc = get_scsislot_name(devfs_path, bus_addr,
4085 name)) != PICL_SUCCESS) {
4086 /* if rc is NODENOTFOUND, then slot is empty */
4087 if (rc != PICL_NODENOTFOUND) {
4088 return (rc);
4089 } else {
4090 return (PICL_SUCCESS);
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) {
4102 geo_addr = 0;
4105 if ((rc = ptree_get_propval_by_name(locp->locnodeh,
4106 PICL_PROP_LABEL, label,
4107 sizeof (label))) != PICL_SUCCESS) {
4108 return (rc);
4111 /* Now recreate the node with new name */
4112 if ((rc = ptree_create_node(name, PICL_CLASS_LOCATION,
4113 &nodeh)) != PICL_SUCCESS) {
4114 return (rc);
4117 /* add all the properties now */
4118 (void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4119 PICL_PROPNAMELEN_MAX, PICL_PROP_SLOT_TYPE, NULLREAD,
4120 NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4121 SANIBEL_SCSI_SLOT);
4123 (void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4124 PICL_PROPNAMELEN_MAX, PICL_PROP_LABEL, NULLREAD,
4125 NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4126 label);
4128 (void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4129 PICL_PROPNAMELEN_MAX, PICL_PROP_BUS_ADDR, NULLREAD,
4130 NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4131 bus_addr);
4133 (void) create_property(PICL_PTYPE_UNSIGNED_INT, PICL_READ,
4134 sizeof (uint8_t), PICL_PROP_GEO_ADDR, NULLREAD,
4135 NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4136 &geo_addr);
4138 (void) create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
4139 PICL_PROPNAMELEN_MAX, PICL_PROP_DEVFS_PATH, NULLREAD,
4140 NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
4141 devfs_path);
4142 (void) ptree_add_node(frup->frunodeh, nodeh);
4144 if ((rc = make_loc_data(name, &hashptr)) != PICL_SUCCESS) {
4145 return (rc);
4147 /* save data in hash table */
4148 if ((rc = hash_add_entry(nodeh, (void *)hashptr)) != PICL_SUCCESS) {
4149 free_data(hashptr->type, hashptr);
4150 return (rc);
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
4163 static int
4164 frutree_initialize_children(picl_nodehdl_t childh, void *c_args)
4166 picl_errno_t rc;
4167 picl_nodehdl_t parenth;
4168 boolean_t node_changed = B_FALSE;
4169 hashdata_t *datap = NULL;
4170 char name[PICL_PROPNAMELEN_MAX];
4171 char class[PICL_PROPNAMELEN_MAX];
4172 frutree_frunode_t *frup = NULL;
4173 frutree_init_callback_arg_t *arg;
4175 if (c_args == NULL) {
4176 return (PICL_INVALIDARG);
4178 arg = (frutree_init_callback_arg_t *)c_args;
4179 frup = arg->frup;
4181 if ((rc = ptree_get_propval_by_name(childh, PICL_PROP_PARENT,
4182 &parenth, sizeof (parenth))) != PICL_SUCCESS) {
4183 return (rc);
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) {
4191 return (rc);
4194 if ((rc = ptree_get_propval_by_name(childh, PICL_PROP_NAME, name,
4195 sizeof (name))) != PICL_SUCCESS) {
4196 return (rc);
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);
4217 } else {
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,
4229 &node_changed);
4230 if (node_changed) {
4231 delete_list_t *nodep = NULL;
4233 * add this node to list of nodes
4234 * to be removed
4236 nodep = (delete_list_t *)malloc(
4237 sizeof (delete_list_t));
4238 if (nodep == NULL) {
4239 return (PICL_NOSPACE);
4241 nodep->nodeh = childh;
4242 nodep->next = NULL;
4244 if (arg->first == NULL) {
4245 arg->first = nodep;
4246 } else { /* add 2 front */
4247 nodep->next = arg->first;
4248 arg->first = nodep;
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)) !=
4265 PICL_SUCCESS) {
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)) !=
4276 PICL_SUCCESS) {
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 */
4295 static int
4296 initiate_connects(picl_nodehdl_t nodeh, void *args)
4298 picl_errno_t rc;
4299 hashdata_t *hashptr = NULL;
4300 picl_nodehdl_t parenth;
4301 frutree_frunode_t *frup = NULL;
4302 frutree_locnode_t *locp = NULL;
4304 if (args == 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) {
4311 return (rc);
4314 if (parenth != frup->frunodeh)
4315 return (PICL_WALK_CONTINUE);
4317 if ((rc = hash_lookup_entry(nodeh, (void **)&hashptr)) !=
4318 PICL_SUCCESS) {
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,
4333 locp->name, rc);
4336 return (PICL_WALK_CONTINUE);
4340 * Initializes the subtree under a FRU
4342 static picl_errno_t
4343 fru_init(frutree_frunode_t *frup)
4345 picl_errno_t rc;
4346 delete_list_t *tmp = NULL, *curr = NULL;
4347 frutree_init_callback_arg_t arg;
4349 if (frup == NULL) {
4350 return (PICL_INVALIDARG);
4353 arg.frup = frup;
4354 arg.first = NULL;
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) {
4362 return (rc);
4365 /* traverse thru delete_nodes_list and delete the nodes from tree */
4366 curr = arg.first;
4367 while (curr) {
4368 tmp = curr;
4369 (void) ptree_delete_node(tmp->nodeh);
4370 (void) ptree_destroy_node(tmp->nodeh);
4371 (void) hash_remove_entry(tmp->nodeh);
4372 free(tmp);
4373 curr = curr->next;
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)) !=
4384 PICL_SUCCESS) {
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) {
4398 return (rc);
4400 return (PICL_SUCCESS);
4403 /*ARGSUSED*/
4404 static int
4405 post_events(picl_nodehdl_t childh, void *c_args)
4407 int rc;
4408 hashdata_t *hashptr = NULL;
4409 frutree_frunode_t *frup = NULL;
4410 frutree_locnode_t *locp = NULL;
4411 frutree_portnode_t *portp = NULL;
4412 char classval[PICL_CLASSNAMELEN_MAX];
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)) !=
4420 PICL_SUCCESS) {
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.
4477 static picl_errno_t
4478 do_action(picl_nodehdl_t root, int action, void *cargs)
4480 int rc;
4481 callback_t func_ptr;
4482 char *class = NULL;
4484 switch (action) {
4486 case INIT_FRU:
4487 func_ptr = frutree_initialize_children;
4488 class = NULL;
4489 break;
4490 case CREATE_DEVICES_ENTRIES:
4491 func_ptr = create_device_entries;
4492 class = NULL;
4493 break;
4494 case POST_EVENTS:
4495 func_ptr = post_events;
4496 class = NULL;
4497 break;
4498 default:
4499 return (PICL_INVALIDARG);
4502 if ((rc = ptree_walk_tree_by_class(root, class, cargs,
4503 func_ptr)) != PICL_SUCCESS) {
4504 return (rc);
4506 return (PICL_SUCCESS);
4509 static picl_errno_t
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);
4537 static picl_errno_t
4538 frutree_init()
4540 picl_errno_t rc;
4541 frutree_frunode_t *frup = NULL;
4542 hashdata_t *hashptr = NULL;
4544 if ((rc = ptree_get_node_by_path(PLATFORM_PATH, &platformh)) !=
4545 PICL_SUCCESS) {
4546 return (rc);
4549 if ((rc = hash_lookup_entry(chassish, (void **)&hashptr)) !=
4550 PICL_SUCCESS) {
4551 return (rc);
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);
4561 return (rc);
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);
4580 scsi_info_fini();
4581 return (rc);
4583 /* free the memory used during initialization */
4584 scsi_info_fini();
4585 /* start node monitoring thread */
4586 if (pthread_create(&monitor_tid, NULL, monitor_node_status,
4587 NULL) != 0) {
4588 FRUTREE_DEBUG0(EVENTS, "SUNW_frutree:Error in creating node"
4589 " monitoring thread");
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);
4602 /* ARGSUSED */
4603 static void *
4604 init_thread(void *arg)
4606 picl_errno_t rc;
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) {
4614 return (NULL);
4616 FRUTREE_DEBUG1(FRUTREE_INIT, "conf_file = %s", conf_file);
4617 if ((rc = frutree_init()) != PICL_SUCCESS) {
4618 FRUTREE_DEBUG1(FRUTREE_INIT, "frutree_init failed, error = %d",
4619 rc);
4621 FRUTREE_DEBUG0(FRUTREE_INIT, "init_thread end");
4622 return (NULL);
4625 /* ARGSUSED */
4626 static void
4627 event_completion_handler(char *ename, void *earg, size_t size)
4629 if (frutree_debug & EV_COMPLETION) {
4630 char name[PICL_PROPNAMELEN_MAX];
4631 nvlist_t *nvlp;
4632 char *value = NULL;
4633 char *arg = NULL;
4634 picl_nodehdl_t fruhdl;
4635 time_t current_time;
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,
4647 &fruhdl);
4648 if (arg != NULL)
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(&current_time), ename, value, name);
4658 nvlist_free(nvlp);
4661 (void) mutex_lock(&piclevent_mutex);
4662 piclevent_pending = 0;
4663 (void) cond_broadcast(&piclevent_completed_cv);
4664 (void) mutex_unlock(&piclevent_mutex);
4665 free(earg);
4666 free(ename);
4669 picl_errno_t
4670 post_piclevent(const char *event, char *val1,
4671 char *val2, picl_nodehdl_t nodeh, frutree_wait_t wait)
4673 nvlist_t *nvl;
4674 size_t nvl_size;
4675 char *pack_buf = NULL;
4676 char *ename = NULL;
4677 char *arg = NULL;
4678 picl_errno_t rc;
4679 timestruc_t to;
4680 struct timeval tp;
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)) {
4689 nvlist_free(nvl);
4690 return (PICL_FAILURE);
4693 if ((ename = strdup(event)) == NULL) {
4694 nvlist_free(nvl);
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;
4704 } else {
4705 free(ename);
4706 nvlist_free(nvl);
4707 return (PICL_INVALIDARG);
4710 if (nvlist_add_string(nvl, arg, val1)) {
4711 free(ename);
4712 nvlist_free(nvl);
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,
4719 NULL)) {
4720 free(ename);
4721 nvlist_free(nvl);
4722 return (PICL_FAILURE);
4724 } else { /* state change event */
4726 if (val2 != NULL) {
4727 /* if there is a last state, add it to nvlist */
4728 if (nvlist_add_string(nvl,
4729 PICLEVENTARG_LAST_STATE, val2)) {
4730 free(ename);
4731 nvlist_free(nvl);
4732 return (PICL_FAILURE);
4737 if (nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, NULL)) {
4738 free(ename);
4739 nvlist_free(nvl);
4740 return (PICL_FAILURE);
4743 (void) mutex_lock(&piclevent_mutex);
4744 while (piclevent_pending) {
4745 (void) cond_wait(&piclevent_completed_cv,
4746 &piclevent_mutex);
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) {
4753 free(ename);
4754 free(pack_buf);
4755 nvlist_free(nvl);
4756 (void) mutex_lock(&piclevent_mutex);
4757 piclevent_pending = 0;
4758 (void) mutex_unlock(&piclevent_mutex);
4759 return (rc);
4762 if (frutree_debug) {
4763 char name[PICL_PROPNAMELEN_MAX];
4764 (void) ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
4765 name, sizeof (name));
4766 if (val2 != NULL) {
4767 FRUTREE_DEBUG4(EVENTS, "%s(%s -> %s) on %s", ename,
4768 val2, val1, name);
4769 } else {
4770 FRUTREE_DEBUG3(EVENTS, "%s(%s) on %s", ename,
4771 val1, name);
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);
4786 nvlist_free(nvl);
4787 return (PICL_SUCCESS);
4791 * return values
4792 * -1 : error
4793 * 0 : not enabled
4794 * 1 : enabled
4796 /* ARGSUSED */
4797 static int
4798 is_autoconfig_enabled(char *loc_name)
4800 return (1);
4803 static picl_errno_t
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));
4809 if (list == NULL) {
4810 return (PICL_NOSPACE);
4813 if (get_cfgadm_state(list, locp->name) == PICL_SUCCESS) {
4814 locp->state_mgr = CFGADM_AP;
4815 free(list);
4816 return (PICL_SUCCESS);
4818 free(list);
4819 return (PICL_NODENOTFOUND);
4823 * handles DR_INCOMING_RES on chassis node
4824 * (refresh piclfrutree tree)
4826 static int
4827 reconfigure_chassis(picl_nodehdl_t nodeh, void *args)
4829 picl_errno_t rc;
4830 hashdata_t *hashptr = NULL;
4831 picl_nodehdl_t parenth, childh;
4832 frutree_frunode_t *frup = NULL, *child_frup = NULL;
4833 frutree_locnode_t *locp = NULL;
4834 boolean_t state_changed = B_FALSE;
4835 boolean_t cond_changed = B_FALSE;
4836 frutree_dr_arg_t dr_arg;
4838 if (args == NULL) {
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) {
4845 return (rc);
4848 if (parenth != frup->frunodeh)
4849 return (PICL_WALK_CONTINUE);
4851 if ((rc = hash_lookup_entry(nodeh, (void **)&hashptr)) !=
4852 PICL_SUCCESS) {
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) ==
4862 PICL_SUCCESS) {
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) {
4872 if (child_frup) {
4873 child_frup->state_mgr = locp->state_mgr;
4874 (void) update_fru_state(child_frup,
4875 &state_changed);
4880 state_changed = B_FALSE;
4881 (void) update_loc_state(locp, &state_changed);
4882 if (state_changed) {
4883 switch (locp->state) {
4884 case LOC_STATE_CONNECTED:
4885 case LOC_STATE_DISCONNECTED:
4886 if (locp->prev_state == LOC_STATE_EMPTY ||
4887 locp->prev_state == LOC_STATE_UNKNOWN) {
4888 /* handle fru insertion */
4889 dr_arg.action = HANDLE_INSERT;
4890 } else {
4891 /* handle loc state change */
4892 dr_arg.action = HANDLE_LOCSTATE_CHANGE;
4894 break;
4895 case LOC_STATE_EMPTY:
4896 /* handle fru removal */
4897 if (locp->prev_state == LOC_STATE_UNKNOWN) {
4898 /* post piclevent to update led */
4899 dr_arg.action = HANDLE_LOCSTATE_CHANGE;
4900 } else {
4901 /* disconnected fru is removed */
4902 dr_arg.action = HANDLE_REMOVE;
4904 break;
4905 default:
4906 return (PICL_WALK_CONTINUE);
4907 } /* end of switch */
4909 dr_arg.data = locp;
4910 (void) pthread_mutex_lock(&ev_mutex);
4911 if ((rc = add_to_queue(dr_arg)) != PICL_SUCCESS) {
4912 (void) pthread_mutex_unlock(&ev_mutex);
4913 return (PICL_WALK_CONTINUE);
4915 (void) pthread_cond_signal(&ev_cond);
4916 (void) pthread_mutex_unlock(&ev_mutex);
4917 return (PICL_WALK_CONTINUE);
4918 } else {
4919 /* connect the disconnect locations */
4920 if (locp->state == LOC_STATE_DISCONNECTED &&
4921 locp->autoconfig_enabled == B_TRUE) {
4922 if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
4923 FRUTREE_DEBUG2(EVENTS, CONNECT_FAILED_ERR,
4924 locp->name, rc);
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);
4949 if (cond_changed) {
4950 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
4951 fru_cond[child_frup->cond],
4952 fru_cond[child_frup->prev_cond],
4953 child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
4954 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
4955 child_frup->name, PICLEVENT_CONDITION_CHANGE,
4956 rc);
4959 return (PICL_WALK_CONTINUE);
4962 static picl_errno_t
4963 handle_chassis_configure(frutree_frunode_t *frup)
4965 picl_errno_t rc;
4967 if (frup == NULL) {
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,
4979 NULL) != 0) {
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) {
4992 return (rc);
4994 return (PICL_SUCCESS);
4997 static picl_errno_t
4998 handle_chassis_unconfigure(frutree_frunode_t *frup)
5000 picl_errno_t rc;
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);
5033 static picl_errno_t
5034 configuration_fn(frutree_dr_arg_t *dr_arg)
5036 picl_errno_t rc;
5037 picl_nodehdl_t parenth;
5038 cfga_flags_t flags = 0;
5039 frutree_frunode_t *frup = NULL;
5040 frutree_locnode_t *locp = NULL;
5041 hashdata_t *hashptr = NULL;
5042 boolean_t state_changed = B_FALSE;
5044 if (dr_arg == NULL)
5045 return (PICL_FAILURE);
5047 frup = (frutree_frunode_t *)dr_arg->data;
5048 if (frup == NULL) {
5049 free(dr_arg);
5050 return (PICL_FAILURE);
5053 if (frup->frunodeh == chassish) {
5054 rc = handle_chassis_configure(frup);
5055 free(dr_arg);
5056 return (rc);
5059 if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
5060 &parenth, sizeof (parenth))) != PICL_SUCCESS) {
5061 free(dr_arg);
5062 return (rc);
5065 if ((rc = hash_lookup_entry(parenth, (void **)&hashptr)) !=
5066 PICL_SUCCESS) {
5067 free(dr_arg);
5068 return (rc);
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);
5077 if (state_changed)
5078 if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5079 loc_state[locp->state], loc_state[locp->prev_state],
5080 locp->locnodeh, WAIT)) != PICL_SUCCESS) {
5081 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5082 locp->name, PICLEVENT_STATE_CHANGE, rc);
5085 switch (dr_arg->action) {
5086 case CPU_ONLINE:
5087 flags |= CFGA_FLAG_FORCE;
5088 FRUTREE_DEBUG1(EVENTS, "CPU online on %s", frup->name);
5089 if (locp->state != LOC_STATE_CONNECTED) {
5090 if (locp->autoconfig_enabled) {
5091 if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
5092 FRUTREE_DEBUG2(EVENTS,
5093 CONNECT_FAILED_ERR,
5094 locp->name, rc);
5097 break;
5098 } /*FALLTHRU*/
5100 /* do configure now */
5101 case CONFIGURE_FRU: /* dr_incoming_res */
5102 FRUTREE_DEBUG1(EVENTS, "DR_INCOMING_RES on %s", frup->name);
5103 if ((rc = configure_fru(frup, flags)) != PICL_SUCCESS) {
5104 FRUTREE_DEBUG2(EVENTS, CONFIGURE_FAILED_ERR,
5105 frup->name, rc);
5106 break;
5109 free(dr_arg);
5110 return (PICL_SUCCESS);
5113 /* handles all dr related events */
5114 static picl_errno_t
5115 handle_dr_event(frutree_dr_arg_t *dr_arg)
5117 picl_errno_t rc;
5118 picl_nodehdl_t loch, childh;
5119 hashdata_t *hashptr = NULL;
5120 cfga_flags_t flags = 0;
5121 frutree_dr_arg_t *arg = NULL;
5122 frutree_dr_arg_t fru_dr_arg;
5123 frutree_locnode_t *locp = NULL;
5124 frutree_frunode_t *frup = NULL, *child_frup = NULL;
5125 boolean_t state_changed = B_FALSE, cond_changed = B_FALSE;
5127 switch (dr_arg->action) {
5128 case CPU_ONLINE:
5129 case CONFIGURE_FRU:
5131 frup = (frutree_frunode_t *)dr_arg->data;
5132 arg = (frutree_dr_arg_t *)malloc(sizeof (frutree_dr_arg_t));
5133 if (arg == NULL) {
5134 FRUTREE_DEBUG2(EVENTS, CONFIGURE_FAILED_ERR,
5135 frup->name, PICL_NOSPACE);
5136 return (NULL);
5138 arg->action = dr_arg->action;
5139 arg->data = dr_arg->data;
5140 (void) configuration_fn((void *)arg);
5141 break;
5143 case CPU_OFFLINE:
5144 flags |= CFGA_FLAG_FORCE;
5145 frup = (frutree_frunode_t *)dr_arg->data;
5146 if (frup == NULL) {
5147 break;
5149 FRUTREE_DEBUG1(EVENTS, "CPU_OFFLINE on %s", frup->name);
5150 if ((rc = unconfigure_fru(frup, flags)) != PICL_SUCCESS) {
5151 FRUTREE_DEBUG2(EVENTS, UNCONFIG_FAILED_ERR, frup->name, rc);
5152 break;
5155 if ((rc = handle_fru_unconfigure(frup)) != PICL_SUCCESS) {
5156 FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED, PICLEVENT_DR_REQ,
5157 frup->name, rc);
5159 break;
5161 case UNCONFIGURE_FRU: /* dr_outgoing_res */
5162 frup = (frutree_frunode_t *)dr_arg->data;
5163 if (frup == NULL) {
5164 break;
5166 FRUTREE_DEBUG1(EVENTS, "DR_OUTGOING_RES on %s", frup->name);
5167 if (frup->frunodeh == chassish) {
5168 (void) handle_chassis_unconfigure(frup);
5169 break;
5172 if ((rc = unconfigure_fru(frup, flags)) != PICL_SUCCESS) {
5173 FRUTREE_DEBUG2(EVENTS, UNCONFIG_FAILED_ERR, frup->name, rc);
5174 break;
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) {
5184 break;
5187 if ((rc = hash_lookup_entry(loch, (void **)&hashptr)) !=
5188 PICL_SUCCESS) {
5189 break;
5191 locp = LOCDATA_PTR(hashptr);
5193 /* check the autoconfig flag */
5194 if (locp->autoconfig_enabled == B_FALSE) {
5195 break;
5198 if ((rc = disconnect_fru(locp)) != PICL_SUCCESS) {
5199 FRUTREE_DEBUG2(EVENTS, "SUNW_frutree:Disconnect on %s "
5200 "failed(error=%d)", locp->name, rc);
5202 break;
5204 case HANDLE_CONFIGURE: /* basic hotswap operation */
5206 frup = (frutree_frunode_t *)dr_arg->data;
5207 if (frup == NULL) {
5208 break;
5210 FRUTREE_DEBUG1(EVENTS, "HANDLE CONFIGURE on %s", frup->name);
5211 handle_fru_configure(frup);
5212 break;
5214 case HANDLE_UNCONFIGURE: /* basic hotswap operation */
5216 /* cleanup the internal data structures */
5218 frup = (frutree_frunode_t *)dr_arg->data;
5219 if (frup == NULL) {
5220 break;
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);
5245 break;
5247 case HANDLE_LOCSTATE_CHANGE: /* basic hotswap operation */
5248 /* posts state change events of location */
5249 locp = (frutree_locnode_t *)dr_arg->data;
5250 if (locp == NULL) {
5251 break;
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) ==
5273 PICL_SUCCESS) {
5274 child_frup = FRUDATA_PTR(hashptr);
5277 /* update the child fru state and handle any state changes */
5278 if (child_frup == NULL) {
5279 break;
5282 if ((rc = update_fru_state(child_frup, &state_changed)) !=
5283 PICL_SUCCESS) {
5284 FRUTREE_DEBUG2(EVENTS, GET_FRU_STATE_ERR, child_frup->name, rc);
5285 break;
5288 if (state_changed == B_FALSE) {
5290 * if there is no change in state, check for condition
5291 * changes.
5292 * if there is a state change, handling state change
5293 * will take care of condition changes also.
5295 (void) update_fru_condition(child_frup, &cond_changed);
5296 if (cond_changed == B_FALSE) {
5297 break;
5300 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5301 fru_cond[child_frup->cond],
5302 fru_cond[child_frup->prev_cond],
5303 child_frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5304 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5305 child_frup->name,
5306 PICLEVENT_CONDITION_CHANGE, rc);
5308 break;
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);
5326 break;
5328 (void) pthread_cond_signal(&ev_cond);
5329 (void) pthread_mutex_unlock(&ev_mutex);
5330 break;
5332 case HANDLE_INSERT: /* dr_apstate_change (HINT_INSERT) */
5333 locp = (frutree_locnode_t *)dr_arg->data;
5334 if (locp == NULL) {
5335 break;
5337 FRUTREE_DEBUG1(EVENTS, "HANDLE INSERT on %s", locp->name);
5338 /* if the location has child fru, get its information */
5339 if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_CHILD,
5340 &childh, sizeof (childh)) == PICL_SUCCESS) {
5341 /* get the child fru information */
5342 if (hash_lookup_entry(childh, (void **)&hashptr) ==
5343 PICL_SUCCESS) {
5344 child_frup = FRUDATA_PTR(hashptr);
5347 if (child_frup) {
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,
5371 child_frup->name,
5372 PICLEVENT_CONDITION_CHANGE, rc);
5375 if (!locp->autoconfig_enabled) {
5376 break;
5379 if (locp->state != LOC_STATE_CONNECTED) {
5380 if ((rc = connect_fru(locp)) != PICL_SUCCESS) {
5381 FRUTREE_DEBUG2(EVENTS, CONNECT_FAILED_ERR,
5382 locp->name, rc);
5385 break;
5388 (void) update_loc_state(locp, &state_changed);
5389 if ((rc = create_fru_node(locp, &child_frup)) != PICL_SUCCESS) {
5390 FRUTREE_DEBUG3(EVENTS, EVENT_NOT_HANDLED,
5391 PICLEVENT_DR_AP_STATE_CHANGE, locp->name, rc);
5392 break;
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,
5405 locp->name, rc);
5408 break;
5410 case HANDLE_REMOVE: /* dr_apstate_change (HINT_REMOVE) */
5411 locp = (frutree_locnode_t *)dr_arg->data;
5412 if (locp == NULL) {
5413 break;
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) ==
5427 PICL_SUCCESS) {
5428 frup = FRUDATA_PTR(hashptr);
5431 if (frup == NULL) {
5432 break;
5436 * frutree need to post this event before handling the
5437 * fru remove, so that other plugins (like frudata) can
5438 * do the cleanup
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);
5451 break;
5453 case POST_COND_EVENT:
5454 frup = (frutree_frunode_t *)dr_arg->data;
5455 if (frup == NULL) {
5456 break;
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);
5464 default:
5465 break;
5467 return (PICL_SUCCESS);
5470 /*ARGSUSED*/
5471 static void*
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);
5478 for (;;) {
5479 if (fini_called)
5480 break;
5481 (void) pthread_mutex_lock(&ev_mutex);
5482 while (queue_head == NULL) {
5483 (void) pthread_cond_wait(&ev_cond, &ev_mutex);
5486 event = remove_from_queue();
5487 (void) pthread_mutex_unlock(&ev_mutex);
5488 while (event) {
5489 (void) handle_dr_event(&event->arg);
5490 free(event);
5491 event = NULL;
5492 (void) pthread_mutex_lock(&ev_mutex);
5493 event = remove_from_queue();
5494 (void) pthread_mutex_unlock(&ev_mutex);
5497 return (NULL);
5500 static picl_errno_t
5501 update_port_state(frutree_portnode_t *portp, boolean_t post_ev)
5503 int state, cond;
5504 picl_errno_t rc;
5505 uint64_t ap_status_time;
5506 boolean_t state_changed = B_FALSE;
5507 boolean_t cond_changed = B_FALSE;
5508 frutree_port_type_t port_type;
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,
5519 portp->instance);
5520 cond = kstat_port_cond(port_type, portp->driver,
5521 portp->instance);
5522 switch (state) {
5523 case 0:
5524 /* DOWN */
5525 if (portp->state != PORT_STATE_DOWN) {
5526 portp->state = PORT_STATE_DOWN;
5527 state_changed = B_TRUE;
5529 break;
5530 case 1:
5531 /* UP */
5532 if (portp->state != PORT_STATE_UP) {
5533 portp->state = PORT_STATE_UP;
5534 state_changed = B_TRUE;
5536 break;
5537 default:
5538 /* UNKNOWN */
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);
5562 switch (cond) {
5563 case 0:
5564 if (portp->cond != PORT_COND_OK) {
5565 portp->cond = PORT_COND_OK;
5566 cond_changed = B_TRUE;
5568 break;
5569 case 1:
5570 if (portp->cond != PORT_COND_FAILING) {
5571 portp->cond = PORT_COND_FAILING;
5572 cond_changed = B_TRUE;
5574 break;
5575 case 2:
5576 if (portp->cond != PORT_COND_FAILED) {
5577 portp->cond = PORT_COND_FAILED;
5578 cond_changed = B_TRUE;
5580 break;
5581 case 3:
5582 if (portp->cond != PORT_COND_TESTING) {
5583 portp->cond = PORT_COND_TESTING;
5584 cond_changed = B_TRUE;
5586 break;
5587 default:
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
5615 static int
5616 monitor_nodes_under_fru(picl_nodehdl_t nodeh, void *c_args)
5618 picl_errno_t rc;
5619 picl_nodehdl_t parenth;
5620 hashdata_t *hashptr = NULL;
5621 boolean_t state_changed;
5622 frutree_portnode_t *portp = NULL;
5623 frutree_locnode_t *locp = NULL;
5624 frutree_frunode_t *frup = NULL;
5625 char class[PICL_PROPNAMELEN_MAX];
5626 char slot_type[PICL_PROPNAMELEN_MAX];
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)) !=
5647 PICL_SUCCESS) {
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 */
5680 /* ARGSUSED */
5681 static int
5682 monitor_fru(picl_nodehdl_t nodeh, void *c_args)
5684 picl_errno_t rc;
5685 picl_nodehdl_t loch;
5686 hashdata_t *hashptr = NULL;
5687 frutree_frunode_t *frup = NULL;
5688 boolean_t state_changed, cond_changed;
5689 char slot_type[PICL_PROPNAMELEN_MAX];
5691 if (hash_lookup_entry(nodeh, (void **)&hashptr) !=
5692 PICL_SUCCESS) {
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) {
5717 /* scsi fru */
5718 (void) update_fru_state(frup, &state_changed);
5719 (void) update_fru_condition(frup, &cond_changed);
5720 if (state_changed) {
5721 if ((rc = post_piclevent(PICLEVENT_STATE_CHANGE,
5722 fru_state[frup->state],
5723 fru_state[frup->prev_state],
5724 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5725 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5726 frup->name, PICLEVENT_STATE_CHANGE, rc);
5729 if (cond_changed) {
5730 if ((rc = post_piclevent(PICLEVENT_CONDITION_CHANGE,
5731 fru_cond[frup->cond], fru_cond[frup->prev_cond],
5732 frup->frunodeh, WAIT)) != PICL_SUCCESS) {
5733 FRUTREE_DEBUG3(EVENTS, PTREE_POST_PICLEVENT_ERR,
5734 frup->name, PICLEVENT_CONDITION_CHANGE,
5735 rc);
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);
5763 /* ARGSUSED */
5764 static void *
5765 monitor_node_status(void *arg)
5767 int err;
5768 timestruc_t to;
5769 struct timeval tp;
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);
5789 return (NULL);
5792 picl_errno_t
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)
5796 int i = 0;
5797 picl_errno_t rc;
5798 picl_nodehdl_t nodeh;
5799 uint8_t geo_addr = 0;
5800 hashdata_t *datap = NULL;
5801 frutree_locnode_t *locp = NULL;
5802 hashdata_t *hashptr = NULL;
5803 char fru_type[PICL_PROPNAMELEN_MAX];
5804 frutree_frunode_t *child_frup = NULL;
5805 frutree_callback_data_t fru_arg;
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) {
5825 return (rc);
5828 if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
5829 PICL_PROPNAMELEN_MAX, PICL_PROP_SLOT_TYPE, NULLREAD,
5830 NULLWRITE, nodeh, NULL, slot_type)) !=
5831 PICL_SUCCESS) {
5832 FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5833 PICL_PROP_SLOT_TYPE, scsi_loc, rc);
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);
5850 geo_addr = slot_no;
5851 if ((rc = create_property(PICL_PTYPE_UNSIGNED_INT, PICL_READ,
5852 sizeof (uint8_t), PICL_PROP_GEO_ADDR, NULLREAD,
5853 NULLWRITE, nodeh, (picl_prophdl_t *)NULL,
5854 &geo_addr)) != PICL_SUCCESS) {
5855 FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5856 PICL_PROP_GEO_ADDR, scsi_loc, rc);
5859 if ((rc = create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
5860 PICL_PROPNAMELEN_MAX, PICL_PROP_DEVFS_PATH, NULLREAD,
5861 NULLWRITE, nodeh, NULL, frup->fru_path)) !=
5862 PICL_SUCCESS) {
5863 FRUTREE_DEBUG3(FRUTREE_INIT, PTREE_CREATE_PROP_FAILED,
5864 PICL_PROP_DEVFS_PATH, scsi_loc, rc);
5867 if ((rc = ptree_add_node(frup->frunodeh, nodeh)) != PICL_SUCCESS) {
5868 (void) ptree_destroy_node(nodeh);
5869 return (rc);
5872 /* save the node in hashtable */
5873 if ((rc = make_loc_data(scsi_loc, &datap)) != PICL_SUCCESS) {
5874 return (rc);
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)) !=
5882 PICL_SUCCESS) {
5883 return (rc);
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) {
5893 return (rc);
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) {
5909 return (rc);
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);
5925 fru_type[i] = '\0';
5926 break;
5928 ++i;
5930 if ((rc = ptree_update_propval_by_name(child_frup->frunodeh,
5931 PICL_PROP_FRU_TYPE, fru_type, sizeof (fru_type))) !=
5932 PICL_SUCCESS) {
5933 FRUTREE_DEBUG3(EVENTS, PTREE_UPDATE_PROP_ERR,
5934 PICL_PROP_FRU_TYPE, child_frup->name, rc);
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
5952 /*ARGSUSED*/
5953 boolean_t
5954 is_location_present_in_subtree(frutree_frunode_t *frup, const char *name,
5955 const char *path)
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 */
5965 return (B_TRUE);
5968 return (B_FALSE);