xref: /titanic_44/usr/src/cmd/picl/plugins/sun4u/snowbird/envmond/picldr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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
env_read_policy_configuration(char * conffile,env_policy_t ** policypp)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
env_parse_config_file()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
is_rtm_present()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
env_set_cpu_info()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
env_init()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
env_set_smc_global_enables(boolean_t ipmi_enable)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
env_open_smc(void)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
env_handle_smc_local_event(void * res_datap)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
env_handle_async_msg_event(void * res_datap)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
env_process_smc_event(int fd,void ** datapp)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 *
env_polling_thread(void * args)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
env_start_services(void)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
env_handle_chassis_configuring_event(char * state)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
env_handle_event(const char * ename,const void * earg,size_t size)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