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