Home | History | Annotate | Download | only in envmond
      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 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <limits.h>
     32 #include <sys/systeminfo.h>
     33 #include <pthread.h>
     34 #include <syslog.h>
     35 #include <picl.h>
     36 #include <picltree.h>
     37 #include <picldefs.h>
     38 #include <string.h>
     39 #include <strings.h>
     40 #include <sys/param.h>
     41 #include <sys/types.h>
     42 #include <sys/stat.h>
     43 #include <fcntl.h>
     44 #include <unistd.h>
     45 #include <stropts.h>
     46 #include <assert.h>
     47 #include <libnvpair.h>
     48 #include <libintl.h>
     49 #include <poll.h>
     50 #include <smclib.h>
     51 #include "piclenvmond.h"
     52 #include "picldr.h"
     53 
     54 /* external functions */
     55 extern picl_errno_t env_platmod_init();
     56 extern void env_platmod_handle_event(const char *, const void *, size_t);
     57 extern picl_errno_t env_platmod_create_sensors();
     58 extern picl_errno_t env_platmod_setup_hotswap();
     59 extern picl_errno_t env_platmod_sp_monitor();
     60 extern picl_errno_t env_platmod_handle_bus_if_change(uint8_t);
     61 extern picl_errno_t env_platmod_handle_latch_open();
     62 extern void env_platmod_handle_sensor_event(void *);
     63 extern int process_platmod_sp_state_change_notif(void *);
     64 extern int process_platmod_change_cpu_node_state(void *);
     65 extern int process_platmod_change_cpci_state(void *);
     66 extern int process_platmod_async_msg_notif(void *);
     67 extern void process_platmod_sp_heartbeat(uint8_t);
     68 extern picl_errno_t env_platmod_create_hotswap_prop();
     69 extern picl_errno_t env_create_property(int ptype, int pmode,
     70 	size_t psize, char *pname, int (*readfn)(ptree_rarg_t *, void *),
     71 	int (*writefn)(ptree_warg_t *, const void *),
     72 	picl_nodehdl_t nodeh, picl_prophdl_t *propp, void *vbuf);
     73 extern char *strtok_r(char *s1, const char *s2, char **lasts);
     74 
     75 /* external variables */
     76 extern int env_debug;
     77 
     78 static char sys_name[SYS_NMLN];
     79 static char chassisconf_name[SYS_NMLN];
     80 static boolean_t parse_config_file = B_FALSE;
     81 static int8_t alarm_check_interval = -1;
     82 static picl_nodehdl_t frutreeh = 0;
     83 static pthread_t polling_threadID;
     84 static boolean_t create_polling_thr = B_TRUE;
     85 
     86 /* globals */
     87 uint8_t cpu_geo_addr = 0;
     88 picl_nodehdl_t rooth = 0, chassis_nodehdl = 0, cpu_nodehdl = 0;
     89 picl_nodehdl_t platformh = 0, sysmgmth = 0, cpu_lnodehdl = 0;
     90 
     91 /*
     92  * envmond policy structure
     93  */
     94 typedef struct _policy {
     95 	uint8_t		interval;
     96 	char		*pname;
     97 	char		*argp;
     98 	struct _policy	*nextp;
     99 } env_policy_t;
    100 
    101 /*
    102  * read_policy_configuration - extract info. from the envmond.conf
    103  */
    104 static int
    105 env_read_policy_configuration(char *conffile, env_policy_t **policypp)
    106 {
    107 	FILE		*fp;
    108 	char		buf[RECORD_MAXSIZE];
    109 	char		*token, *lasts;
    110 	env_policy_t	*policyp;
    111 
    112 	if ((fp = fopen(conffile, "r")) == NULL) {
    113 		return (-1);
    114 	}
    115 	while (fgets(buf, sizeof (buf), fp) != NULL) {
    116 		if (buf[0] && (buf[0] == '#' || buf[0] == '\n')) {
    117 			continue;
    118 		}
    119 		token = (char *)strtok_r(buf, RECORD_WHITESPACE, &lasts);
    120 		if (token == NULL) {
    121 			continue;
    122 		}
    123 		policyp = (env_policy_t *)malloc(sizeof (env_policy_t));
    124 		if (policyp == NULL) {
    125 			goto errors;
    126 		}
    127 		policyp->interval = (uint8_t)strtoul(token, NULL, 0);
    128 		token = (char *)strtok_r(lasts, RECORD_WHITESPACE, &lasts);
    129 		if (token == NULL) {
    130 			free(policyp);
    131 		} else {
    132 			policyp->pname = strdup(token);
    133 			if (NULL == policyp->pname) {
    134 				goto errors;
    135 			}
    136 		}
    137 		if (lasts) {
    138 			policyp->argp = strdup(lasts);
    139 			if (policyp->argp == NULL) {
    140 				goto errors;
    141 			}
    142 		} else {
    143 			policyp->argp = NULL;
    144 		}
    145 		policyp->nextp = *policypp;
    146 		*policypp = policyp;
    147 	}
    148 	(void) fclose(fp);
    149 	return (0);
    150 
    151 errors:
    152 	(void) fclose(fp);
    153 	while (*policypp) {
    154 		policyp = *policypp;
    155 		*policypp = (*policypp)->nextp;
    156 		free(policyp->pname);
    157 		free(policyp->argp);
    158 		free(policyp);
    159 	}
    160 	return (-1);
    161 }
    162 
    163 /*
    164  * supports environmental policies
    165  */
    166 static void
    167 env_parse_config_file()
    168 {
    169 	char		conffile[MAXPATHLEN];
    170 	env_policy_t	*policyp, *tmp;
    171 	struct stat	st;
    172 
    173 	if (parse_config_file == B_FALSE) {
    174 		return;
    175 	}
    176 	(void) snprintf(conffile, sizeof (conffile), ENV_CONFIG_FILE,
    177 		sys_name);
    178 	bzero(&st, sizeof (st));
    179 	if (stat(conffile, &st) == -1) {
    180 		return;
    181 	}
    182 
    183 	policyp = NULL;
    184 	if (env_read_policy_configuration(conffile, &policyp) == -1) {
    185 		return;
    186 	}
    187 	assert(policyp);
    188 
    189 	while (policyp) {
    190 		tmp = policyp;
    191 		policyp = policyp->nextp;
    192 		if (strcmp(tmp->pname, SERVICE_PROCESSOR) == 0) {
    193 			alarm_check_interval = tmp->interval;
    194 			if (env_debug & DEBUG)
    195 				syslog(LOG_INFO, "Alarm Heartbeat frequency: "
    196 					"%d seconds", alarm_check_interval);
    197 		}
    198 		free(tmp->pname);
    199 		free(tmp->argp);
    200 		free(tmp);
    201 	}
    202 }
    203 
    204 /*
    205  * detects the presence of RTM for CPU board
    206  */
    207 static boolean_t
    208 is_rtm_present()
    209 {
    210 	sc_reqmsg_t	req_pkt;
    211 	sc_rspmsg_t	rsp_pkt;
    212 	uint8_t		size = 0;
    213 
    214 	req_pkt.data[0] = ENV_RTM_BUS_ID;
    215 	req_pkt.data[1] = ENV_RTM_SLAVE_ADDR;
    216 	req_pkt.data[2] = ENV_RTM_READ_SIZE;
    217 	size = ENV_RTM_PKT_LEN;
    218 
    219 	/* initialize the request packet */
    220 	(void) smc_init_smc_msg(&req_pkt, SMC_MASTER_RW_CMD,
    221 		DEFAULT_SEQN, size);
    222 
    223 	/* make a call to smc library to send cmd */
    224 	if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
    225 		POLL_TIMEOUT) != SMC_SUCCESS) {
    226 		return (B_FALSE);
    227 	}
    228 	return (B_TRUE);
    229 }
    230 
    231 /*
    232  * this routine does the following:
    233  * 1. initializes the CPU geo-addr
    234  * 2. gets the system name
    235  * 3. create the chassis type property
    236  * 4. creates the conf_file property
    237  */
    238 static picl_errno_t
    239 env_set_cpu_info()
    240 {
    241 	int rc = 0;
    242 	sc_reqmsg_t	req_pkt;
    243 	sc_rspmsg_t	rsp_pkt;
    244 	uint8_t		size = 0;
    245 	char 		conf_name[PICL_PROPNAMELEN_MAX];
    246 
    247 	/* get the geo_addr */
    248 	/* initialize the request packet */
    249 	(void) smc_init_smc_msg(&req_pkt, SMC_GET_GEOGRAPHICAL_ADDRESS,
    250 		DEFAULT_SEQN, size);
    251 
    252 	/* make a call to smc library to send cmd */
    253 	if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
    254 		POLL_TIMEOUT) != SMC_SUCCESS) {
    255 		return (PICL_FAILURE);
    256 	}
    257 	cpu_geo_addr = rsp_pkt.data[0];
    258 
    259 	/* get the system name */
    260 	if (sysinfo(SI_PLATFORM, sys_name, sizeof (sys_name)) == -1) {
    261 		return (PICL_FAILURE);
    262 	}
    263 	(void) strncpy(chassisconf_name, sys_name,
    264 		sizeof (chassisconf_name));
    265 
    266 	/* initialize the node handles */
    267 	if ((rc = ptree_get_root(&rooth)) != PICL_SUCCESS) {
    268 		return (rc);
    269 	}
    270 
    271 	if ((rc = ptree_get_node_by_path(FRUTREE_PATH, &frutreeh)) !=
    272 		PICL_SUCCESS) {
    273 		return (rc);
    274 	}
    275 
    276 	if ((rc = ptree_get_node_by_path(PICL_FRUTREE_CHASSIS,
    277 		&chassis_nodehdl)) != PICL_SUCCESS) {
    278 		return (rc);
    279 	}
    280 
    281 	/* create the chassis type property */
    282 	if ((rc = env_create_property(PICL_PTYPE_CHARSTRING,
    283 		PICL_READ, PICL_PROPNAMELEN_MAX, PICL_PROP_CHASSIS_TYPE,
    284 		NULLREAD, NULLWRITE, chassis_nodehdl, (picl_prophdl_t *)NULL,
    285 		chassisconf_name)) != PICL_SUCCESS) {
    286 		return (rc);
    287 	}
    288 
    289 	/*
    290 	 * create dummy prop to inform frutree plugin abt conf file
    291 	 * (rtm based or w/o rtm)
    292 	 * frutree plugin removes this prop after reading the value
    293 	 */
    294 	if (is_rtm_present() == B_TRUE) {
    295 		(void) snprintf(conf_name, sizeof (conf_name),
    296 			"%s.RTM.conf", chassisconf_name);
    297 	} else {
    298 		(void) snprintf(conf_name, sizeof (conf_name),
    299 			"%s.conf", chassisconf_name);
    300 	}
    301 
    302 	if ((rc = env_create_property(PICL_PTYPE_CHARSTRING,
    303 		PICL_READ, PICL_PROPNAMELEN_MAX, PICL_PROP_CONF_FILE, NULLREAD,
    304 		NULLWRITE, chassis_nodehdl, (picl_prophdl_t *)NULL,
    305 		conf_name)) != PICL_SUCCESS) {
    306 		return (rc);
    307 	}
    308 	return (PICL_SUCCESS);
    309 }
    310 
    311 /*
    312  * initialization
    313  */
    314 picl_errno_t
    315 env_init()
    316 {
    317 	picl_errno_t rc = PICL_SUCCESS;
    318 
    319 	if ((rc = env_set_cpu_info()) != PICL_SUCCESS) {
    320 		return (rc);
    321 	}
    322 
    323 	/* parse the configuration file */
    324 	env_parse_config_file();
    325 
    326 	/*
    327 	 * do any platform specific intialization if required
    328 	 * IMPORTANT: must post dr_incoming resource event on
    329 	 * chassis after doing all the reqd checks
    330 	 */
    331 	rc = env_platmod_init();
    332 	return (rc);
    333 }
    334 
    335 /*
    336  * sets smc global enables
    337  */
    338 static int
    339 env_set_smc_global_enables(boolean_t ipmi_enable)
    340 {
    341 	sc_reqmsg_t	req_pkt;
    342 	sc_rspmsg_t	rsp_pkt;
    343 	uint8_t		size = 0;
    344 
    345 	/* initialize the request packet */
    346 	(void) smc_init_smc_msg(&req_pkt, SMC_GET_GLOBAL_ENABLES,
    347 		DEFAULT_SEQN, size);
    348 
    349 	/* make a call to smc library to send cmd */
    350 	if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
    351 		POLL_TIMEOUT) != SMC_SUCCESS) {
    352 		return (-1);
    353 	}
    354 
    355 	req_pkt.data[0] = rsp_pkt.data[0];
    356 	req_pkt.data[1] = rsp_pkt.data[1];
    357 	if (ipmi_enable) {
    358 		req_pkt.data[1] |= ENV_IPMI_ENABLE_MASK;
    359 		req_pkt.data[1] &= ENV_SENSOR_ENABLE_MASK;
    360 	} else {
    361 		req_pkt.data[1] &= ENV_IPMI_DISABLE_MASK;
    362 		req_pkt.data[1] |= ENV_SENSOR_DISABLE_MASK;
    363 	}
    364 	size = ENV_SET_GLOBAL_PKT_LEN;
    365 	(void) smc_init_smc_msg(&req_pkt, SMC_SET_GLOBAL_ENABLES,
    366 		DEFAULT_SEQN, size);
    367 
    368 	/* make a call to smc library to send cmd */
    369 	if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
    370 		POLL_TIMEOUT) != SMC_SUCCESS) {
    371 		return (-1);
    372 	}
    373 	return (0);
    374 }
    375 
    376 /*
    377  * wrapper smc drv open
    378  */
    379 int
    380 env_open_smc(void)
    381 {
    382 	int	fd;
    383 	if ((fd = open(SMC_NODE, O_RDWR)) < 0) {
    384 		return (-1);
    385 	}
    386 	return (fd);
    387 }
    388 
    389 static picl_smc_event_t
    390 env_handle_smc_local_event(void *res_datap)
    391 {
    392 	picl_errno_t rc = PICL_SUCCESS;
    393 	uint8_t event = SMC_LOCAL_EVENT;
    394 	uint8_t event_data = BYTE_0(res_datap);
    395 
    396 	if (env_debug & EVENTS)
    397 		syslog(LOG_INFO, "Local Event Received, data %x\n", event_data);
    398 
    399 	switch (event_data) {
    400 		case SMC_LOCAL_EVENT_BRIDGE_IN_RESET :	/*FALLTHRU*/
    401 		case SMC_LOCAL_EVENT_BRIDGE_OUT_OF_RESET :
    402 			if ((rc = env_platmod_handle_bus_if_change(
    403 				event_data)) != PICL_SUCCESS) {
    404 				syslog(LOG_ERR, gettext("SUNW_envmond:Error"
    405 					" in handling bus interface change "
    406 					"event, error = %d"), rc);
    407 			}
    408 			break;
    409 		case SMC_LOCAL_EVENT_LATCH_OPENED:
    410 			syslog(LOG_INFO, gettext("LATCH OPEN DETECTED"));
    411 			if ((rc = env_platmod_handle_latch_open()) !=
    412 				PICL_SUCCESS) {
    413 				syslog(LOG_ERR, gettext("SUNW_envmond:Error"
    414 					" in handling latch open event, "
    415 					"error = %d"), rc);
    416 			}
    417 			break;
    418 		default:
    419 			break;
    420 	}
    421 	return (event);
    422 }
    423 
    424 static void
    425 env_handle_async_msg_event(void *res_datap)
    426 {
    427 	int rc = SMC_SUCCESS;
    428 	uint8_t event = BYTE_6(res_datap);
    429 
    430 	if (env_debug & EVENTS)
    431 		syslog(LOG_INFO, "Asynchronous Event %x Received, data %x\n",
    432 			event, BYTE_7(res_datap));
    433 	switch (event) {
    434 	/*
    435 	 * This message comes to CPU when the service processor is going offline
    436 	 * or online.
    437 	 */
    438 	case EVENT_MSG_AC_STATE_CHANGE:
    439 		if ((rc = process_platmod_sp_state_change_notif(res_datap)) !=
    440 			SMC_SUCCESS) {
    441 			syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
    442 				"service processor change of state event, "
    443 				"error = %d"), rc);
    444 		}
    445 		break;
    446 	/*
    447 	 * This message comes to CPU when service processor
    448 	 * requests the CPU to go online or offline (shutdown).
    449 	 */
    450 	case EVENT_MSG_CHANGE_CPU_NODE_STATE:
    451 		if ((rc = process_platmod_change_cpu_node_state(res_datap)) !=
    452 			SMC_SUCCESS) {
    453 			syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
    454 				"cpu change of state event, error = %d"), rc);
    455 		}
    456 		break;
    457 	/*
    458 	 * This message comes to CPU(Satellite) when the
    459 	 * other node (Host) is going online or offline.
    460 	 */
    461 	case EVENT_MSG_CHANGE_CPCI_STATE:
    462 		if ((rc = process_platmod_change_cpci_state(res_datap)) !=
    463 			SMC_SUCCESS) {
    464 			syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
    465 				"cpci change state event, error = %d"), rc);
    466 		}
    467 		break;
    468 	/*
    469 	 * This message comes from service processor to inform
    470 	 * change in states for other nodes
    471 	 */
    472 	case EVENT_MSG_ASYNC_EVENT_NOTIFICATION:
    473 		if ((rc = process_platmod_async_msg_notif(res_datap)) !=
    474 			SMC_SUCCESS) {
    475 			syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
    476 				"async event notification, error = %d"), rc);
    477 		}
    478 		break;
    479 	case MSG_GET_CPU_NODE_STATE:
    480 		/* respond to the service processor heartbeat */
    481 		process_platmod_sp_heartbeat(BYTE_5(res_datap));
    482 		break;
    483 	default:
    484 		event = NO_EVENT;
    485 		break;
    486 	}
    487 }
    488 
    489 /*ARGSUSED*/
    490 static picl_smc_event_t
    491 env_process_smc_event(int fd, void **datapp)
    492 {
    493 	sc_rspmsg_t		rsp_msg;
    494 	picl_smc_event_t	event;
    495 	void			*res_datap = NULL;
    496 
    497 	if (read(fd, (char *)&rsp_msg, SC_MSG_MAX_SIZE) < 0) {
    498 		return (NO_EVENT);
    499 	}
    500 
    501 	if (SC_MSG_CC(&rsp_msg) != 0) {
    502 		return (NO_EVENT);
    503 	}
    504 
    505 	res_datap = SC_MSG_DATA(&rsp_msg);
    506 	if (env_debug & EVENTS)
    507 		syslog(LOG_INFO, "Async Msg Cmd,data0,2 = %x,%x,%x\n",
    508 			SC_MSG_CMD(&rsp_msg), BYTE_0(res_datap),
    509 			BYTE_2(res_datap));
    510 
    511 	if (SC_MSG_CMD(&rsp_msg) == SMC_SMC_LOCAL_EVENT_NOTIF) {
    512 		event = env_handle_smc_local_event(res_datap);
    513 	} else {	/* it must be an IPMI event */
    514 		switch (BYTE_2(res_datap)) {
    515 		case 0x3:
    516 		case 0x4:
    517 			if (env_debug & DEBUG)
    518 				syslog(LOG_INFO, gettext("SUNW_envmond: "
    519 					" Sensor Event Received\n"));
    520 			/* sensor event */
    521 			switch (BYTE_3(res_datap)) {
    522 			case TEMPERATURE_SENSOR_TYPE:
    523 				event = TEMPERATURE_SENSOR_EVENT;
    524 				env_platmod_handle_sensor_event(res_datap);
    525 				break;
    526 			default:
    527 				syslog(LOG_ERR, gettext("SUNW_envmond:Unknown "
    528 				"sensor Event:%d\n"), BYTE_3(res_datap));
    529 				event = NO_EVENT;
    530 				break;
    531 			}
    532 		default:
    533 			env_handle_async_msg_event(res_datap);
    534 			break;
    535 		}
    536 	}
    537 	return (event);
    538 }
    539 
    540 /*
    541  * polls SMC driver for SMC events
    542  */
    543 /*ARGSUSED*/
    544 static void *
    545 env_polling_thread(void *args)
    546 {
    547 	int			poll_rc;
    548 	struct pollfd		poll_fds[1];
    549 	void			*datap;
    550 	int			smcfd;
    551 	struct strioctl		strio;
    552 	sc_cmdspec_t		set;
    553 
    554 	smcfd = env_open_smc();
    555 	if (smcfd == -1) {
    556 		syslog(LOG_ERR, gettext("SUNW_envmond:Error in polling, "
    557 			"Open of SMC drv failed"));
    558 		create_polling_thr = B_TRUE;
    559 		return (NULL);
    560 	}
    561 
    562 	set.args[0]	= SMC_SENSOR_EVENT_ENABLE_SET;
    563 	set.attribute	= SC_ATTR_SHARED;
    564 	strio.ic_cmd	= SCIOC_MSG_SPEC;
    565 	strio.ic_timout	= 0;
    566 	strio.ic_len	= ENV_SENSOR_EV_ENABLE_PKT_LEN;
    567 	strio.ic_dp	= (char *)&set;
    568 	if (ioctl(smcfd, I_STR, &strio) < 0) {
    569 		syslog(LOG_ERR, gettext("SUNW_envmond:Request for "
    570 			"Sensor events failed"));
    571 		(void) close(smcfd);
    572 		create_polling_thr = B_TRUE;
    573 		return (NULL);
    574 	}
    575 
    576 	/* request for async messages */
    577 	poll_fds[0].fd		= smcfd;
    578 	poll_fds[0].events	= POLLIN|POLLPRI;
    579 	poll_fds[0].revents	= 0;
    580 
    581 	set.attribute	= SC_ATTR_SHARED;
    582 	set.args[0]	= SMC_IPMI_RESPONSE_NOTIF;
    583 	set.args[1]	= SMC_SMC_LOCAL_EVENT_NOTIF;
    584 	strio.ic_cmd	= SCIOC_MSG_SPEC;
    585 	strio.ic_timout	= 0;
    586 	strio.ic_len	= ENV_IPMI_SMC_ENABLE_PKT_LEN;
    587 	strio.ic_dp	= (char *)&set;
    588 	if (ioctl(smcfd, I_STR, &strio) == -1) {
    589 		syslog(LOG_ERR, gettext("SUNW_envmond:Request for"
    590 			"Async messages failed"));
    591 		(void) close(smcfd);
    592 		create_polling_thr = B_TRUE;
    593 		return (NULL);
    594 	}
    595 
    596 	/* Now wait for SMC events to come */
    597 	for (;;) {
    598 		poll_rc = poll(poll_fds, 1, -1); /* poll forever */
    599 		if (poll_rc < 0) {
    600 			syslog(LOG_ERR, gettext("SUNW_envmond:Event "
    601 				"processing halted"));
    602 			break;
    603 		}
    604 		if (env_process_smc_event(smcfd, &datap) == NO_EVENT) {
    605 			syslog(LOG_ERR, gettext("SUNW_envmond:"
    606 				"wrong event data posted from SMC"));
    607 		}
    608 	}
    609 	(void) close(smcfd);
    610 	create_polling_thr = B_TRUE;
    611 	return (NULL);
    612 }
    613 
    614 /*
    615  * (to be)Called during chassis configuration. It does the following tasks.
    616  * Set global enables on SMC
    617  * Register for local(SMC) events and remote(IPMI) messages (State Change msgs)
    618  * creates sensor nodes
    619  * Initialize hotswap
    620  * Initiallize the interaction with service processor
    621  */
    622 static picl_errno_t
    623 env_start_services(void)
    624 {
    625 	int rc;
    626 	if (env_debug & DEBUG) {
    627 		syslog(LOG_INFO, "env_start_services begin");
    628 	}
    629 
    630 	/* set the SMC global enables */
    631 	if (env_set_smc_global_enables(B_TRUE) == -1) {
    632 		syslog(LOG_ERR, gettext("SUNW_envmond:Setting SMC "
    633 			"Globals failed"));
    634 		return (PICL_FAILURE);
    635 	}
    636 
    637 	/* start a worker thread to poll for SMC events */
    638 	if (create_polling_thr) {
    639 		rc = pthread_create(&polling_threadID, NULL,
    640 			&env_polling_thread, NULL);
    641 		if (rc != 0) {
    642 			syslog(LOG_ERR, gettext("SUNW_envmond:Error in "
    643 				"creating polling thread"));
    644 			return (PICL_FAILURE);
    645 		}
    646 		create_polling_thr = B_FALSE;
    647 	}
    648 
    649 	/* create the sensor nodes */
    650 	if ((rc = env_platmod_create_sensors()) != PICL_SUCCESS) {
    651 		syslog(LOG_ERR, gettext("SUNW_envmond:Error in creating sensor"
    652 			" nodes, error = %d"), rc);
    653 	}
    654 
    655 	/* intialize the hotswap framework */
    656 	if ((rc = env_platmod_setup_hotswap()) != PICL_SUCCESS) {
    657 		syslog(LOG_ERR, gettext("SUNW_envmond:Error in hotswap "
    658 			"initialization, error = %d"), rc);
    659 	}
    660 
    661 	if ((rc = env_platmod_create_hotswap_prop()) != PICL_SUCCESS) {
    662 		syslog(LOG_ERR, gettext("SUNW_envmond:Error in creating "
    663 			"hotswap prop, error = %d"), rc);
    664 	}
    665 
    666 	/* intialize interaction with service processor */
    667 	if ((rc = env_platmod_sp_monitor()) != PICL_SUCCESS) {
    668 		syslog(LOG_ERR, gettext("SUNW_envmond:Failed to interact with"
    669 			" service processor, error = %d"), rc);
    670 	}
    671 	return (PICL_SUCCESS);
    672 }
    673 
    674 static picl_errno_t
    675 env_handle_chassis_configuring_event(char *state)
    676 {
    677 	picl_errno_t rc = PICL_SUCCESS;
    678 	picl_prophdl_t proph;
    679 	picl_nodehdl_t rtm_lnodehdl = 0;
    680 	char *cpu_name = PICL_NODE_CPU;
    681 	char *rtm_name = PICL_NODE_RTM;
    682 	uint64_t status_time;
    683 
    684 	if (strcmp(state, PICLEVENTARGVAL_CONFIGURING) != 0) {
    685 		return (PICL_SUCCESS);
    686 	}
    687 
    688 	/* initialize cpu loc node handle */
    689 	if (cpu_lnodehdl == 0) {
    690 		if ((rc = ptree_find_node(chassis_nodehdl,
    691 			PICL_PROP_NAME,	PICL_PTYPE_CHARSTRING,
    692 			cpu_name, (strlen(cpu_name) + 1),
    693 			&cpu_lnodehdl)) != PICL_SUCCESS) {
    694 			syslog(LOG_ERR, gettext("SUNW_envmond: failed "
    695 			" to get CPU nodehdl, error = %d"), rc);
    696 			return (rc);
    697 		}
    698 	}
    699 
    700 	/* create geo-addr prop under CPU location */
    701 	if (ptree_get_prop_by_name(cpu_lnodehdl, PICL_PROP_GEO_ADDR,
    702 		&proph) == PICL_PROPNOTFOUND) {
    703 		if ((rc = env_create_property(PICL_PTYPE_UNSIGNED_INT,
    704 			PICL_READ, sizeof (cpu_geo_addr),
    705 			PICL_PROP_GEO_ADDR, NULLREAD, NULLWRITE,
    706 			cpu_lnodehdl, &proph,
    707 			(void *)&cpu_geo_addr)) != PICL_SUCCESS) {
    708 			return (rc);
    709 		}
    710 	}
    711 	if (ptree_get_prop_by_name(cpu_lnodehdl,
    712 		PICL_PROP_STATUS_TIME, &proph) != PICL_SUCCESS) {
    713 			status_time = (uint64_t)time(NULL);
    714 			(void) env_create_property(PICL_PTYPE_TIMESTAMP,
    715 				PICL_READ, sizeof (status_time),
    716 				PICL_PROP_STATUS_TIME, NULLREAD, NULLWRITE,
    717 				cpu_lnodehdl, &proph, &status_time);
    718 	}
    719 
    720 	/* create geo address property for RTM node (if present) */
    721 	(void) ptree_find_node(chassis_nodehdl,
    722 		PICL_PROP_NAME,	PICL_PTYPE_CHARSTRING, rtm_name,
    723 		(strlen(rtm_name) + 1), &rtm_lnodehdl);
    724 
    725 	if (rtm_lnodehdl == 0) {	/* RTM not present */
    726 		return (PICL_SUCCESS);
    727 	}
    728 
    729 	if (ptree_get_prop_by_name(rtm_lnodehdl, PICL_PROP_GEO_ADDR,
    730 		&proph) == PICL_PROPNOTFOUND) {
    731 		if ((rc = env_create_property(PICL_PTYPE_UNSIGNED_INT,
    732 			PICL_READ, sizeof (cpu_geo_addr), PICL_PROP_GEO_ADDR,
    733 			NULLREAD, NULLWRITE, rtm_lnodehdl, &proph,
    734 			&cpu_geo_addr)) != PICL_SUCCESS) {
    735 			syslog(LOG_ERR, gettext("SUNW_envmond:Failed "
    736 				"to create CPU geo-addr, error = %d"), rc);
    737 			return (rc);
    738 		}
    739 	}
    740 	if (ptree_get_prop_by_name(rtm_lnodehdl,
    741 		PICL_PROP_STATUS_TIME, &proph) != PICL_SUCCESS) {
    742 		status_time = (uint64_t)time(NULL);
    743 		(void) env_create_property(PICL_PTYPE_TIMESTAMP,
    744 			PICL_READ, sizeof (status_time), PICL_PROP_STATUS_TIME,
    745 			NULLREAD, NULLWRITE, rtm_lnodehdl, &proph,
    746 			&status_time);
    747 	}
    748 
    749 	/* start all the environment monitoring services */
    750 	if ((rc = env_start_services()) != PICL_SUCCESS) {
    751 		return (rc);
    752 	}
    753 	return (PICL_SUCCESS);
    754 }
    755 
    756 /*
    757  * routine to handle all the picl state and condition change events
    758  */
    759 void
    760 env_handle_event(const char *ename, const void *earg, size_t size)
    761 {
    762 	picl_nodehdl_t		nodeh = 0;
    763 	nvlist_t		*nvlp;
    764 	char			*value;
    765 	boolean_t		state_event;
    766 	char			result[PICL_PROPNAMELEN_MAX];
    767 
    768 	if (!ename) {
    769 		return;
    770 	}
    771 	if (strcmp(ename, PICLEVENT_STATE_CHANGE) == 0) {
    772 		state_event = B_TRUE;
    773 	} else if (strcmp(ename, PICLEVENT_CONDITION_CHANGE) == 0) {
    774 		state_event = B_FALSE;
    775 	} else {
    776 		return;
    777 	}
    778 
    779 	/* unpack the nvlist and get the information */
    780 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
    781 		return;
    782 	}
    783 	if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh) == -1) {
    784 		nvlist_free(nvlp);
    785 		return;
    786 	}
    787 	if (nvlist_lookup_string(nvlp, (state_event) ?
    788 		PICLEVENTARG_STATE :
    789 		PICLEVENTARG_CONDITION, &value) != 0) {
    790 		nvlist_free(nvlp);
    791 		return;
    792 	}
    793 
    794 	if (env_debug & PICLEVENTS) {
    795 		if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
    796 			result, sizeof (result)) != PICL_SUCCESS) {
    797 			syslog(LOG_ERR, " SUNW_envmond: error in getting"
    798 				" %s", PICL_PROP_NAME);
    799 			nvlist_free(nvlp);
    800 			return;
    801 		}
    802 		syslog(LOG_INFO, "SUNW_envmond: %s (%s) on %s",
    803 			ename, value, result);
    804 	}
    805 
    806 	if (chassis_nodehdl == 0 && state_event) {
    807 		if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
    808 			result, sizeof (result)) != PICL_SUCCESS) {
    809 			nvlist_free(nvlp);
    810 			return;
    811 		}
    812 		if (strcmp(result, PICL_NODE_CHASSIS) == 0) {
    813 			chassis_nodehdl = nodeh;
    814 		}
    815 	}
    816 	if (nodeh == chassis_nodehdl && state_event) {
    817 		(void) env_handle_chassis_configuring_event(value);
    818 	}
    819 	/* do any platform specific handling that is reqd */
    820 	env_platmod_handle_event(ename, earg, size);
    821 	nvlist_free(nvlp);
    822 }
    823