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(¤t_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 }