xref: /titanic_51/usr/src/cmd/picl/plugins/sun4u/blade/bsc/picllom.c (revision 23a1ccea6aac035f084a7a4cdc968687d1b02daf)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * This plugin creates PICL nodes and properties for objects handled through
28  * the blade support chip (BSC). The BSC Solaris land device driver exposes
29  * information to the plugin and other clients through an existing LOM
30  * (Lights Out Management) ioctl interface. The plugin only exercises
31  * a subset of the interface which is known to be supported by the bsc.
32  *
33  * All the nodes which may be accessible through the BSC are included below
34  * the SUNW,bscv node (class system-controller) in the /platform tree.
35  * This plugin interrogates the BSC to determine which of
36  * those nodes are actually available. Properties are added to such nodes and
37  * in the case of volatile properties like temperature, a call-back function
38  * is established for on-demand access to the current value.
39  *
40  * NOTE:
41  * Depends on PICL devtree plugin.
42  */
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <alloca.h>
49 #include <syslog.h>
50 #include <string.h>
51 #include <libintl.h>
52 #include <picl.h>
53 #include <picltree.h>
54 #include <errno.h>
55 #include <limits.h>
56 #include <ctype.h>
57 #include <sys/types.h>
58 #include <sys/obpdefs.h>
59 #include <sys/lom_io.h>
60 #include <sys/systeminfo.h>
61 #include <time.h>
62 #include <picldefs.h>
63 #include <picld_pluginutil.h>
64 #include "picllom.h"
65 
66 static	void		picllom_register(void);
67 static	void		picllom_init(void);
68 static	void		picllom_fini(void);
69 static	node_el_t	*create_node_el(picl_nodehdl_t nodeh);
70 static	void		delete_node_el(node_el_t *pel);
71 static	node_list_t	*create_node_list();
72 static	void		delete_node_list_contents(node_list_t *pnl);
73 static	void		delete_node_list(node_list_t *pnl);
74 static	void		add_node_to_list(picl_nodehdl_t nodeh,
75     node_list_t *listp);
76 static	void		get_node_list_by_class(picl_nodehdl_t nodeh,
77     const char *classname, node_list_t *listp);
78 static	int		get_lom_node(picl_nodehdl_t *lominfh);
79 static	int		get_lom_device_path(picl_nodehdl_t *lominfh);
80 static int		get_node_by_name_and_class(picl_nodehdl_t srchnodeh,
81     const char *nodename, const char *classname, picl_nodehdl_t *chdh);
82 static	int		add_regular_prop(picl_nodehdl_t nodeh, const char *name,
83     int type, int access, int size, const void *valbuf, picl_prophdl_t *prophp);
84 static	int		add_volatile_prop(picl_nodehdl_t nodeh, char *name,
85     int type, int access, int size, ptree_vol_rdfunc_t rdfunc,
86     ptree_vol_wrfunc_t wrfunc, picl_prophdl_t *prophp);
87 static	int		open_lom_rd(int *lom_fd);
88 static	int		get_lom_temp(int index, tempr_t *temp_p);
89 static	int		update_voltage_stats();
90 static	int		get_lom_volts_status(int index, int *voltsStatus_p);
91 static	int		get_lom_volts_shutdown(int index, int *voltsShutdown_p);
92 static	int		update_fan_stats();
93 static	int		get_lom_fan_speed(int index, int *fan_speed);
94 static	int		read_vol_temp(ptree_rarg_t *parg, void *buf);
95 static	int		read_vol_volts_status(ptree_rarg_t *parg, void *buf);
96 static	int		read_vol_volts_shutdown(ptree_rarg_t *parg, void *buf);
97 static	int		read_fan_speed(ptree_rarg_t *parg, void *buf);
98 static	int		read_fan_status(ptree_rarg_t *parg, void *buf);
99 static	int		lookup_led_status(int8_t state, const char **string);
100 static	int		read_led_status(ptree_rarg_t *parg, void *buf);
101 static	void		convert_node_name(char *ptr);
102 static	int		add_temp_sensors(int lom_fd, picl_nodehdl_t lominfh);
103 static	int		add_voltage_monitors(int lom_fd,
104     picl_nodehdl_t lominfh);
105 static	int		add_fan_nodes(int lom_fd, picl_nodehdl_t lominfh);
106 static	int		get_config_file(char *outfilename);
107 
108 #pragma	init(picllom_register)
109 
110 static picld_plugin_reg_t  my_reg_info = {
111 	PICLD_PLUGIN_VERSION_1,
112 	PICLD_PLUGIN_NON_CRITICAL,
113 	"SUNW_picllom",
114 	picllom_init,
115 	picllom_fini
116 };
117 
118 static const char str_OK[] = "OK";
119 static const char str_FAIL[] = "FAIL";
120 static const char str_On[] = "on";
121 static const char str_Off[] = "off";
122 static const char str_Enabled[] = "Enabled";
123 static const char str_Disabled[] = "Disabled";
124 static char lom_device_path[PATH_MAX];
125 static tempr_t high_warnings[MAX_TEMPS];
126 static tempr_t high_shutdowns[MAX_TEMPS];
127 static picl_prophdl_t temp_handles[MAX_TEMPS];
128 static	lom_fandata_t fandata;
129 static	picl_prophdl_t	fan_speed_handles[MAX_FANS];
130 static	picl_prophdl_t	fan_status_handles[MAX_FANS];
131 static	lom_volts_t	voltsdata;
132 static	picl_prophdl_t	volts_status_handles[MAX_VOLTS];
133 static	picl_prophdl_t	volts_shutdown_handles[MAX_VOLTS];
134 static	int		n_leds = 0;
135 static	int		max_state_size = 0;
136 static	picl_prophdl_t	*led_handles = NULL;
137 static	char		**led_labels = NULL;
138 static	lom2_info_t	info2data;
139 static	struct {
140 	int		size;
141 	char		*str_colour;
142 } colour_lkup[1 + LOM_LED_COLOUR_AMBER];
143 
144 static	struct {
145 	int8_t		state;
146 	char		*str_ledstate;
147 } ledstate_lkup[] = {
148 	{	LOM_LED_OFF			},
149 	{	LOM_LED_ON			},
150 	{	LOM_LED_BLINKING		},
151 };
152 
153 static node_el_t *
154 create_node_el(picl_nodehdl_t nodeh)
155 {
156 	node_el_t *ptr = malloc(sizeof (node_el_t));
157 
158 	if (ptr != NULL) {
159 		ptr->nodeh = nodeh;
160 		ptr->next = NULL;
161 	}
162 
163 	return (ptr);
164 }
165 
166 static void
167 delete_node_el(node_el_t *pel)
168 {
169 	free(pel);
170 }
171 
172 static node_list_t *
173 create_node_list()
174 {
175 	node_list_t *ptr = malloc(sizeof (node_list_t));
176 
177 	if (ptr != NULL) {
178 		ptr->head = NULL;
179 		ptr->tail = NULL;
180 	}
181 
182 	return (ptr);
183 }
184 
185 static void
186 delete_node_list_contents(node_list_t *pnl)
187 {
188 	node_el_t	*pel;
189 
190 	if (pnl == NULL)
191 		return;
192 
193 	while ((pel = pnl->head) != NULL) {
194 		pnl->head = pel->next;
195 		delete_node_el(pel);
196 	}
197 
198 	pnl->tail = NULL;
199 }
200 
201 static void
202 delete_node_list(node_list_t *pnl)
203 {
204 	delete_node_list_contents(pnl);
205 	free(pnl);
206 }
207 
208 /*
209  * Get a linking element and add handle to end of chain
210  */
211 static void
212 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp)
213 {
214 	node_el_t	*pel = create_node_el(nodeh);
215 
216 	if (pel != NULL) {
217 		if (listp->tail == NULL)
218 			listp->head = pel;
219 		else
220 			listp->tail->next = pel;
221 
222 		listp->tail = pel;
223 	}
224 }
225 
226 /*
227  * Get a list of nodes of the specified classname under nodeh.
228  * Once a node of the specified class is found, its children are not
229  * searched.
230  */
231 static void
232 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname,
233 	    node_list_t *listp)
234 {
235 	int		err;
236 	char		clname[PICL_CLASSNAMELEN_MAX+1];
237 	picl_nodehdl_t	chdh;
238 
239 	/*
240 	 * go through the children
241 	 */
242 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
243 	    sizeof (picl_nodehdl_t));
244 
245 	while (err == PICL_SUCCESS) {
246 		err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
247 		    clname, strlen(classname) + 1);
248 
249 		if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0))
250 			add_node_to_list(chdh, listp);
251 		else
252 			get_node_list_by_class(chdh, classname, listp);
253 
254 		err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
255 		    sizeof (picl_nodehdl_t));
256 	}
257 }
258 
259 static int
260 get_lom_node(picl_nodehdl_t *lominfh)
261 {
262 	int			err = PICL_SUCCESS;
263 	node_list_t		*listp;
264 
265 	listp = create_node_list();
266 
267 	if ((err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM,
268 	    lominfh)) != PICL_SUCCESS) {
269 		syslog(LOG_ERR, EM_MISSING_NODE,
270 		    PICL_NODE_ROOT PICL_NODE_PLATFORM);
271 		return (err);	/* no /platform ! */
272 	}
273 
274 	get_node_list_by_class(*lominfh, PICL_CLASS_SERVICE_PROCESSOR, listp);
275 
276 	if (listp->head == NULL) {
277 		*lominfh = 0;
278 		syslog(LOG_ERR, EM_MISSING_NODE, PICL_CLASS_SERVICE_PROCESSOR);
279 		err = PICL_NODENOTFOUND;
280 	} else {
281 		*lominfh = listp->head->nodeh;
282 
283 		if (listp->head != listp->tail)
284 			syslog(LOG_ERR, EM_LOM_DUPLICATE);
285 	}
286 
287 	delete_node_list(listp);
288 	return (err);
289 }
290 
291 static int
292 get_lom_device_path(picl_nodehdl_t *lominfh)
293 {
294 	int err = PICL_SUCCESS;
295 	char devfs_path[PATH_MAX];
296 	char devices_path[PATH_MAX];
297 
298 	err = ptree_get_propval_by_name(*lominfh, PICL_PROP_DEVFS_PATH,
299 	    devfs_path, sizeof (devfs_path));
300 
301 	/* Build up the full device path and set the global */
302 	strcpy(devices_path, "/devices");
303 	strcat(devices_path, devfs_path);
304 	strcat(devices_path, LOM_DEV_MINOR_NAME);
305 	strcpy(lom_device_path, devices_path);
306 
307 	return (err);
308 
309 }
310 
311 
312 
313 
314 /*
315  * Look for a node of specified name and class
316  * Confine search to nodes one level below that of supplied handle
317  */
318 static int
319 get_node_by_name_and_class(picl_nodehdl_t srchnodeh, const char *nodename,
320     const char *classname, picl_nodehdl_t *chdh)
321 {
322 	int			err;
323 	char			namebuf[PATH_MAX];
324 
325 	err = ptree_get_propval_by_name(srchnodeh, PICL_PROP_CHILD, chdh,
326 	    sizeof (picl_nodehdl_t));
327 
328 	while (err == PICL_SUCCESS) {
329 		err = ptree_get_propval_by_name(*chdh, PICL_PROP_NAME, namebuf,
330 		    sizeof (namebuf));
331 		if (err != PICL_SUCCESS)
332 			break;
333 		if (strcmp(namebuf, nodename) == 0) {
334 			err = ptree_get_propval_by_name(*chdh,
335 			    PICL_PROP_CLASSNAME, namebuf, sizeof (namebuf));
336 			if ((err == PICL_SUCCESS) &&
337 			    (strcmp(namebuf, classname) == 0))
338 				return (PICL_SUCCESS);
339 		}
340 		err = ptree_get_propval_by_name(*chdh, PICL_PROP_PEER, chdh,
341 		    sizeof (picl_nodehdl_t));
342 	}
343 
344 	return (err);
345 }
346 
347 /*
348  * Create and add the specified regular property
349  */
350 
351 static int
352 add_regular_prop(picl_nodehdl_t nodeh, const char *name, int type, int access,
353     int size, const void *valbuf, picl_prophdl_t *prophp)
354 {
355 	int			err;
356 	ptree_propinfo_t	propinfo;
357 	picl_prophdl_t		proph;
358 
359 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
360 	    type, access, size, (char *)name, NULL, NULL);
361 	if (err != PICL_SUCCESS)
362 		return (err);
363 
364 	err = ptree_create_and_add_prop(nodeh, &propinfo, (void *)valbuf,
365 	    &proph);
366 	if (err == PICL_SUCCESS && prophp)
367 		*prophp = proph;
368 	return (err);
369 }
370 
371 
372 /*
373  * Create and add the specified volatile property
374  */
375 static int
376 add_volatile_prop(picl_nodehdl_t nodeh, char *name, int type, int access,
377     int size, ptree_vol_rdfunc_t rdfunc, ptree_vol_wrfunc_t wrfunc,
378     picl_prophdl_t *prophp)
379 {
380 	int			err;
381 	ptree_propinfo_t	propinfo;
382 	picl_prophdl_t		proph;
383 
384 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
385 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
386 	if (err != PICL_SUCCESS)
387 		return (err);
388 
389 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
390 	if (err == PICL_SUCCESS && prophp)
391 		*prophp = proph;
392 	return (err);
393 }
394 
395 /*
396  * open LOM device to read
397  */
398 static int
399 open_lom_rd(int *lom_fd)
400 {
401 	*lom_fd = open(lom_device_path, O_RDONLY);
402 
403 	if (*lom_fd < 0)
404 		return (PICL_FAILURE);
405 
406 	return (PICL_SUCCESS);
407 }
408 
409 /*
410  * Function to open LOM and read temperature sensor values.
411  * The index to a specific sensor is supplied and that value returned.
412  */
413 static int
414 get_lom_temp(int index, tempr_t *temp_p)
415 {
416 	lom_temp_t	lom_temp;
417 	int		lom_fd;
418 	int		err;
419 	int		res;
420 
421 	err = open_lom_rd(&lom_fd);
422 
423 	if (err == PICL_SUCCESS) {
424 		res = ioctl(lom_fd, LOMIOCTEMP, &lom_temp);
425 		(void) close(lom_fd);
426 
427 		if (res == 0) {
428 			*temp_p = lom_temp.temp[index];
429 		} else {
430 			err = PICL_FAILURE;
431 		}
432 	}
433 
434 	return (err);
435 }
436 
437 /*
438  * Function to open LOM and read voltage monitor values.
439  * Called for each property, so only perform update if time has changed
440  */
441 static int
442 update_voltage_stats()
443 {
444 	static time_t	then = 0;
445 	int		lom_fd;
446 	int		err;
447 	int		res;
448 	time_t		now = time(NULL);
449 
450 	if (now == then)
451 		return (PICL_SUCCESS);
452 
453 	then = now;
454 	err = open_lom_rd(&lom_fd);
455 
456 	if (err == PICL_SUCCESS) {
457 		res = ioctl(lom_fd, LOMIOCVOLTS, &voltsdata);
458 		(void) close(lom_fd);
459 		if (res < 0) {
460 			err = PICL_FAILURE;
461 		}
462 	}
463 
464 	return (err);
465 }
466 
467 /*
468  * Function to open LOM and read voltage monitor values.
469  * The index to a specific voltage status is supplied and that value returned.
470  */
471 static int
472 get_lom_volts_status(int index, int *voltsStatus_p)
473 {
474 	int res;
475 
476 	if ((res = update_voltage_stats()) != PICL_SUCCESS)
477 		return (res);
478 
479 	*voltsStatus_p = voltsdata.status[index];
480 	return (PICL_SUCCESS);
481 }
482 
483 /*
484  * Function to open LOM and read voltage monitor values.
485  * The index to a specific shutdown flag is supplied and that value returned.
486  */
487 static int
488 get_lom_volts_shutdown(int index, int *voltsShutdown_p)
489 {
490 	int res;
491 
492 	if ((res = update_voltage_stats()) != PICL_SUCCESS)
493 		return (res);
494 
495 	*voltsShutdown_p = voltsdata.shutdown_enabled[index];
496 	return (PICL_SUCCESS);
497 }
498 
499 
500 
501 /*
502  * Function to open LOM and read fan values.
503  * Called for each property, so only perform update if time has changed
504  */
505 static int
506 update_fan_stats()
507 {
508 	static time_t	then = 0;
509 	int		lom_fd;
510 	int		err;
511 	int		res;
512 	time_t		now = time(NULL);
513 
514 	if (now == then)
515 		return (PICL_SUCCESS);
516 
517 	then = now;
518 	err = open_lom_rd(&lom_fd);
519 	if (err == PICL_SUCCESS) {
520 		res = ioctl(lom_fd, LOMIOCFANSTATE, &fandata);
521 		(void) close(lom_fd);
522 		if (res < 0) {
523 			err = PICL_FAILURE;
524 		}
525 	}
526 
527 	return (err);
528 }
529 
530 
531 
532 /*
533  * The index to a specific fan is supplied and its speed value returned.
534  */
535 static int
536 get_lom_fan_speed(int index, int *fan_speed)
537 {
538 	int res;
539 
540 	if ((res = update_fan_stats()) != PICL_SUCCESS)
541 		return (res);
542 
543 	*fan_speed = fandata.speed[index];
544 	return (PICL_SUCCESS);
545 }
546 
547 
548 /*
549  * Read function for volatile "Temperature" property via LOM
550  */
551 static int
552 read_vol_temp(ptree_rarg_t *parg, void *buf)
553 {
554 	tempr_t 	temp;
555 	picl_prophdl_t	proph;
556 	int		index;
557 
558 	/*
559 	 * get the sensor index from the displacement of the
560 	 * property handle and get its temperature.
561 	 */
562 	proph = parg->proph;
563 	for (index = 0; index < MAX_TEMPS; index++) {
564 		if (temp_handles[index] == proph)
565 			break;
566 	}
567 
568 	if (index == MAX_TEMPS) {
569 		/*
570 		 * Handle not found. As this is a plugin, stale handles
571 		 * cannot occur, so just fail.
572 		 */
573 		return (PICL_FAILURE);
574 	}
575 
576 	if (get_lom_temp(index, &temp) != PICL_SUCCESS)
577 			return (PICL_FAILURE);
578 	(void) memcpy(buf, (caddr_t)&temp, sizeof (tempr_t));
579 	return (PICL_SUCCESS);
580 }
581 
582 /*
583  * Read function for volatile "VoltageStatus" property via LOM
584  */
585 static int
586 read_vol_volts_status(ptree_rarg_t *parg, void *buf)
587 {
588 	int		voltsStatus;
589 	picl_prophdl_t	proph;
590 	int		index;
591 
592 	/*
593 	 * get the voltage monitor index from the displacement of the
594 	 * status property handle and get its status.
595 	 */
596 	proph = parg->proph;
597 
598 	for (index = 0; index < MAX_VOLTS; index++) {
599 		if (volts_status_handles[index] == proph)
600 			break;
601 	}
602 
603 	if (index == MAX_VOLTS)
604 		return (PICL_FAILURE);
605 
606 	if (get_lom_volts_status(index, &voltsStatus) != PICL_SUCCESS)
607 		return (PICL_FAILURE);
608 
609 	(void) strlcpy(buf, (voltsStatus == 0) ? str_OK : str_FAIL,
610 	    sizeof (str_FAIL));
611 	return (PICL_SUCCESS);
612 }
613 
614 /*
615  * Read function for volatile "VoltageShutdown" property via LOM
616  */
617 static int
618 read_vol_volts_shutdown(ptree_rarg_t *parg, void *buf)
619 {
620 	int		voltsShutdown;
621 	picl_prophdl_t	proph;
622 	int		index;
623 
624 	/*
625 	 * get the voltage monitor index from the displacement of the
626 	 * shutdown property handle and get its value.
627 	 */
628 	proph = parg->proph;
629 
630 	for (index = 0; index < MAX_VOLTS; index++) {
631 		if (volts_shutdown_handles[index] == proph)
632 			break;
633 	}
634 
635 	if (index == MAX_VOLTS)
636 		return (PICL_FAILURE);
637 
638 	if (get_lom_volts_shutdown(index, &voltsShutdown) != PICL_SUCCESS)
639 		return (PICL_FAILURE);
640 
641 	(void) strlcpy(buf, (voltsShutdown == 0) ? str_Disabled : str_Enabled,
642 	    sizeof (str_Disabled));
643 	return (PICL_SUCCESS);
644 }
645 
646 
647 /*
648  * Read function for volatile fan speed property via LOM
649  */
650 static int
651 read_fan_speed(ptree_rarg_t *parg, void *buf)
652 {
653 	int		fan_speed;
654 	picl_prophdl_t	proph;
655 	int		index;
656 
657 	/*
658 	 * get the relevant fan from the displacement of its property handle
659 	 */
660 	proph = parg->proph;
661 
662 	for (index = 0; index < MAX_FANS; index++) {
663 		if (fan_speed_handles[index] == proph)
664 			break;
665 	}
666 
667 	if (index == MAX_FANS)
668 		return (PICL_FAILURE);
669 
670 	if (get_lom_fan_speed(index, &fan_speed) != PICL_SUCCESS)
671 		return (PICL_FAILURE);
672 
673 	(void) memcpy(buf, (caddr_t)&fan_speed, sizeof (fan_speed));
674 	return (PICL_SUCCESS);
675 }
676 
677 /*
678  * look up function to convert led status into string
679  */
680 static int
681 lookup_led_status(int8_t state, const char **string)
682 {
683 	int	i;
684 	int	lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]);
685 
686 	for (i = 0; i < lim; i++) {
687 		if (ledstate_lkup[i].state == state) {
688 			*string = ledstate_lkup[i].str_ledstate;
689 			return (PICL_SUCCESS);
690 		}
691 	}
692 
693 	*string = "";
694 	switch (state) {
695 	case LOM_LED_ACCESS_ERROR:
696 		return (PICL_PROPVALUNAVAILABLE);
697 	case LOM_LED_NOT_IMPLEMENTED:
698 	/*FALLTHROUGH*/
699 	case LOM_LED_OUTOFRANGE:
700 	/*FALLTHROUGH*/
701 	default:
702 		return (PICL_FAILURE);
703 	}
704 }
705 
706 /*
707  * Read function for volatile led status property.
708  */
709 static int
710 read_led_status(ptree_rarg_t *parg, void *buf)
711 {
712 	lom_led_state_t	led_data;
713 	picl_prophdl_t	proph;
714 	int		index;
715 	int		lom_fd;
716 	int		res;
717 	const char	*string;
718 
719 	/*
720 	 * get the relevant led from the displacement of its property handle
721 	 */
722 	proph = parg->proph;
723 
724 	for (index = 0; index < n_leds; index++) {
725 		if (led_handles[index] == proph)
726 			break;
727 	}
728 
729 	if (index == n_leds)
730 		return (PICL_FAILURE);
731 
732 	res = open_lom_rd(&lom_fd);
733 	if (res != PICL_SUCCESS)
734 		return (res);
735 	/*
736 	 * The interface for reading LED status doesn't promise to maintain
737 	 * a constant mapping between LED index number and LED identity
738 	 * (as defined by its label). On the other hand, PICL does promise
739 	 * that whilst a handle remains valid the object it represents will
740 	 * remain constant. To reconcile these positions, we maintain
741 	 * tables of labels and handles linked by index value. We search
742 	 * for the handle with which we are presented and then locate its
743 	 * label. Then we request LED entries from the LOM and compare their
744 	 * labels with the one we seek. As an optimisation, we try the original
745 	 * index value first and then revert to a full search.
746 	 */
747 	(void) memset(&led_data, 0, sizeof (led_data));
748 	led_data.index = index;
749 	res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
750 
751 	if (res != 0 || led_data.state == LOM_LED_NOT_IMPLEMENTED ||
752 	    strcmp(led_data.label, led_labels[index]) != 0) {
753 		/*
754 		 * full scan required (bet it doesn't work!)
755 		 * first re-establish the range to scan
756 		 */
757 		int	i;
758 		int	n;
759 
760 		(void) memset(&led_data, 0, sizeof (led_data));
761 		led_data.index = -1;
762 		res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
763 
764 		if (res != 0) {
765 			(void) close(lom_fd);
766 			return (PICL_PROPVALUNAVAILABLE);
767 		}
768 
769 		if (led_data.state == LOM_LED_NOT_IMPLEMENTED ||
770 		    strcmp(led_data.label, led_labels[index]) != 0) {
771 			n = led_data.index;
772 			for (i = 0; i < n; i++) {
773 				(void) memset(&led_data, 0, sizeof (led_data));
774 				led_data.index = i;
775 				res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
776 
777 				if (res == 0 &&
778 				    led_data.state != LOM_LED_NOT_IMPLEMENTED ||
779 				    strcmp(led_data.label, led_labels[index]) ==
780 				    0) {
781 					break;
782 				}
783 			}
784 
785 			if (i == n) {
786 				(void) close(lom_fd);
787 				return (PICL_PROPVALUNAVAILABLE);
788 			}
789 		}
790 	}
791 
792 	/*
793 	 * if we get here, then we found the right LED.
794 	 */
795 	(void) close(lom_fd);
796 	res = lookup_led_status(led_data.state, &string);
797 	(void) strlcpy(buf, string, max_state_size);
798 	return (res);
799 }
800 
801 /*
802  * Read function for volatile fan status property.
803  * This is a synthesized property using speed and min speed properties
804  */
805 static int
806 read_fan_status(ptree_rarg_t *parg, void *buf)
807 {
808 	int		fan_speed;
809 	picl_prophdl_t	proph;
810 	int		index;
811 
812 	/*
813 	 * get the relevant fan from the displacement of its property handle
814 	 */
815 	proph = parg->proph;
816 
817 	for (index = 0; index < MAX_FANS; index++) {
818 		if (fan_status_handles[index] == proph)
819 			break;
820 	}
821 
822 	if (index == MAX_FANS)
823 		return (PICL_FAILURE);
824 
825 	if (get_lom_fan_speed(index, &fan_speed) != PICL_SUCCESS)
826 		return (PICL_FAILURE);
827 
828 	(void) strlcpy(buf,
829 	    fan_speed < fandata.minspeed[index] ? str_FAIL : str_OK,
830 	    sizeof (str_FAIL));
831 	return (PICL_SUCCESS);
832 }
833 
834 
835 
836 /*
837  * change to lower case and convert any spaces into hyphens
838  */
839 static void
840 convert_node_name(char *ptr)
841 {
842 	char ch;
843 
844 	for (ch = *ptr; ch != '\0'; ch = *++ptr) {
845 		if (isupper(ch)) {
846 			*ptr = tolower(ch);
847 		} else if (isspace(ch)) {
848 			*ptr = '-';
849 		}
850 	}
851 }
852 
853 static int
854 add_temp_sensors(int lom_fd, picl_nodehdl_t lominfh)
855 {
856 	lom_temp_t	lom_temp;
857 	int		res;
858 	int		i;
859 	int		err = PICL_SUCCESS;
860 	const char	*cptr;
861 
862 	res = ioctl(lom_fd, LOMIOCTEMP, &lom_temp);
863 
864 	if ((res == 0) && (lom_temp.num > 0)) {
865 		/*
866 		 * for each temperature location add a sensor node
867 		 */
868 		for (i = 0; i < lom_temp.num; i++) {
869 			picl_nodehdl_t	tempsensh;
870 			picl_prophdl_t proph;
871 
872 			high_warnings[i] = lom_temp.warning[i];
873 			high_shutdowns[i] = lom_temp.shutdown[i];
874 
875 			convert_node_name(lom_temp.name[i]);
876 
877 			err = ptree_create_node(lom_temp.name[i],
878 			    PICL_CLASS_TEMPERATURE_SENSOR, &tempsensh);
879 			if (err != PICL_SUCCESS)
880 				break;
881 
882 			err = add_volatile_prop(tempsensh,
883 			    PICL_PROP_TEMPERATURE, PICL_PTYPE_INT, PICL_READ,
884 			    sizeof (tempr_t), read_vol_temp, NULL,
885 			    &temp_handles[i]);
886 			if (err != PICL_SUCCESS)
887 				break;
888 
889 			if (high_warnings[i] != 0) {
890 				err = add_regular_prop(
891 				    tempsensh, PICL_PROP_HIGH_WARNING,
892 				    PICL_PTYPE_INT, PICL_READ,
893 				    sizeof (tempr_t), &high_warnings[i],
894 				    &proph);
895 				if (err != PICL_SUCCESS)
896 					break;
897 			}
898 
899 			if (high_shutdowns[i] != 0) {
900 				err = add_regular_prop(
901 				    tempsensh, PICL_PROP_HIGH_SHUTDOWN,
902 				    PICL_PTYPE_INT, PICL_READ,
903 				    sizeof (tempr_t), &high_shutdowns[i],
904 				    &proph);
905 				if (err != PICL_SUCCESS)
906 					break;
907 			}
908 
909 			/*
910 			 * for the benefit of prtdiag, add a label of
911 			 * either enclosure or die where appropriate
912 			 */
913 			if ((strcasestr(lom_temp.name[i], CPU_ENCLOSURE) !=
914 			    NULL) ||
915 			    (strcasestr(lom_temp.name[i], CPU_AMBIENT) !=
916 			    NULL)) {
917 				cptr = CPU_AMBIENT;
918 			} else if ((cptr = strcasestr(lom_temp.name[i],
919 			    CPU_DIE)) != NULL) {
920 				cptr = CPU_DIE;
921 			}
922 
923 			if (cptr != NULL) {
924 				err = add_regular_prop(
925 				    tempsensh, PICL_PROP_LABEL,
926 				    PICL_PTYPE_CHARSTRING, PICL_READ,
927 				    strlen(cptr) + 1, cptr, &proph);
928 
929 				if (err != PICL_SUCCESS) {
930 					break;
931 				}
932 			}
933 
934 			err = ptree_add_node(lominfh, tempsensh);
935 
936 			if (err != PICL_SUCCESS)
937 				break;
938 		}
939 
940 		if (err != PICL_SUCCESS) {
941 			syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
942 		}
943 	}
944 
945 	return (err);
946 }
947 
948 static int
949 add_voltage_monitors(int lom_fd, picl_nodehdl_t lominfh)
950 {
951 	int		res;
952 	int		i;
953 	int		err = PICL_SUCCESS;
954 	picl_prophdl_t	proph;
955 
956 	res = ioctl(lom_fd, LOMIOCVOLTS, &voltsdata);
957 
958 	if ((res == 0) && (voltsdata.num > 0)) {
959 		/*
960 		 * for each voltage monitor add a monitor node
961 		 */
962 		for (i = 0; i < voltsdata.num; i++) {
963 			picl_nodehdl_t	voltsmonh;
964 
965 			convert_node_name(voltsdata.name[i]);
966 
967 			err = ptree_create_node(voltsdata.name[i],
968 			    PICL_CLASS_VOLTAGE_INDICATOR, &voltsmonh);
969 			if (err != PICL_SUCCESS)
970 				break;
971 
972 			err = add_regular_prop(voltsmonh, PICL_PROP_LABEL,
973 			    PICL_PTYPE_CHARSTRING, PICL_READ,
974 			    strlen(voltsdata.name[i]) + 1,
975 			    voltsdata.name[i], &proph);
976 			if (err != PICL_SUCCESS)
977 				break;
978 
979 			err = add_volatile_prop(voltsmonh, PICL_VOLTS_SHUTDOWN,
980 			    PICL_PTYPE_CHARSTRING, PICL_READ,
981 			    sizeof (str_Disabled), read_vol_volts_shutdown,
982 			    NULL, &volts_shutdown_handles[i]);
983 			if (err != PICL_SUCCESS)
984 				break;
985 
986 			err = add_volatile_prop(voltsmonh, PICL_PROP_CONDITION,
987 			    PICL_PTYPE_CHARSTRING, PICL_READ,
988 			    sizeof (str_FAIL), read_vol_volts_status, NULL,
989 			    &volts_status_handles[i]);
990 			if (err != PICL_SUCCESS)
991 				break;
992 
993 			err = ptree_add_node(lominfh, voltsmonh);
994 
995 			if (err != PICL_SUCCESS)
996 				break;
997 		}
998 
999 		if (err != PICL_SUCCESS) {
1000 			syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
1001 		}
1002 	}
1003 
1004 	return (err);
1005 }
1006 
1007 static void
1008 add_led(const lom_led_state_t *led_state, picl_nodehdl_t lominfh)
1009 {
1010 	int		err;
1011 	picl_nodehdl_t	ledh;
1012 	picl_nodehdl_t	proph;
1013 
1014 	if (((unsigned char)led_state->state == LOM_LED_STATE_NOT_PRESENT) ||
1015 	    (led_state->label[0] == '\0')) {
1016 		return;
1017 	}
1018 
1019 	err = ptree_create_node(led_state->label, PICL_CLASS_LED, &ledh);
1020 	/*
1021 	 * the led may exist already, e.g. Fault
1022 	 */
1023 	if (err != PICL_SUCCESS)
1024 		return;
1025 
1026 	/*
1027 	 * Unlike LEDs derived from other interfaces, these are not
1028 	 * writable. Establish a read-only volatile property.
1029 	 */
1030 	err = add_volatile_prop(ledh, PICL_PROP_STATE, PICL_PTYPE_CHARSTRING,
1031 	    PICL_READ, max_state_size, read_led_status, NULL,
1032 	    &led_handles[led_state->index]);
1033 	if (err != PICL_SUCCESS)
1034 		return;
1035 
1036 	/*
1037 	 * if colour was defined for this LED, add a colour property
1038 	 */
1039 	if ((led_state->colour != LOM_LED_COLOUR_NONE) &&
1040 	    (led_state->colour != LOM_LED_COLOUR_ANY)) {
1041 		err = add_regular_prop(ledh, PICL_PROP_COLOR,
1042 		    PICL_PTYPE_CHARSTRING, PICL_READ,
1043 		    colour_lkup[led_state->index].size,
1044 		    colour_lkup[led_state->index].str_colour, &proph);
1045 	}
1046 	if (err != PICL_SUCCESS)
1047 		return;
1048 
1049 	err = add_regular_prop(ledh, PICL_PROP_LABEL,
1050 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(led_state->label) + 1,
1051 	    led_state->label, &proph);
1052 	if (err != PICL_SUCCESS)
1053 		return;
1054 
1055 	err = ptree_add_node(lominfh, ledh);
1056 
1057 	if (err != PICL_SUCCESS) {
1058 		syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
1059 	}
1060 }
1061 
1062 static void
1063 fixstate(uint8_t state, const char *string, int *max_len)
1064 {
1065 	int		i;
1066 	int		len;
1067 
1068 	for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]));
1069 	    i++) {
1070 		if (ledstate_lkup[i].state == state) {
1071 			if (ledstate_lkup[i].str_ledstate != NULL)
1072 				free(ledstate_lkup[i].str_ledstate);
1073 			ledstate_lkup[i].str_ledstate = strdup(string);
1074 			len = strlen(string);
1075 			if (len >= *max_len)
1076 				*max_len = len + 1;
1077 			break;
1078 		}
1079 	}
1080 }
1081 
1082 static void
1083 add_led_nodes(int lom_fd, picl_nodehdl_t lominfh)
1084 {
1085 	lom_led_state_t	led_data;
1086 	picl_nodehdl_t	ledh;
1087 	int		res;
1088 	int		i;
1089 
1090 	/*
1091 	 * If the led state enquiry ioctl is supported, an enquiry on
1092 	 * index -1 will return the state of the highest supported index
1093 	 * value.
1094 	 */
1095 	(void) memset(&led_data, 0, sizeof (led_data));
1096 	led_data.index = -1;
1097 	res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
1098 
1099 	if (res != 0)
1100 		return;
1101 
1102 	if (led_labels != NULL) {
1103 		for (i = 0; i < n_leds; i++) {
1104 			if (led_labels[i] != NULL) {
1105 				free(led_labels[i]);
1106 			}
1107 		}
1108 
1109 		free(led_labels);
1110 		led_labels = NULL;
1111 	}
1112 
1113 	if (led_handles != NULL) {
1114 		free(led_handles);
1115 	}
1116 
1117 	n_leds = 0;
1118 	led_handles = calloc(led_data.index + 1, sizeof (picl_nodehdl_t));
1119 	led_labels = calloc(led_data.index + 1, sizeof (char *));
1120 
1121 	if ((led_labels == NULL) || (led_handles == NULL)) {
1122 		if (led_labels != NULL)
1123 			free(led_labels);
1124 		if (led_handles != NULL)
1125 			free(led_handles);
1126 		led_labels = NULL;
1127 		led_handles = NULL;
1128 		syslog(LOG_ERR, EM_NO_LED_MEM);
1129 		return;
1130 	}
1131 
1132 	n_leds = led_data.index + 1;
1133 
1134 	/*
1135 	 * For each LED with a valid state, add a node
1136 	 * and because of the ludicrous API, stache a copy of its label too
1137 	 */
1138 	for (i = 0; i < n_leds; i++) {
1139 		(void) memset(&led_data, 0, sizeof (led_data));
1140 		led_data.index = i;
1141 		res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
1142 
1143 		if (res != 0)
1144 			continue;
1145 
1146 		if (led_data.state == LOM_LED_OUTOFRANGE ||
1147 		    led_data.state == LOM_LED_NOT_IMPLEMENTED)
1148 			continue;
1149 
1150 
1151 		led_labels[i] = strdup(led_data.label);
1152 		convert_node_name(led_data.label);
1153 
1154 		if (get_node_by_name_and_class(lominfh, led_data.label,
1155 		    "led", &ledh) != PICL_SUCCESS) {
1156 			/*
1157 			 * only add a new led node,
1158 			 * if it's not already in place
1159 			 */
1160 			add_led(&led_data, lominfh);
1161 		}
1162 	}
1163 }
1164 
1165 static int
1166 add_fan_nodes(int lom_fd, picl_nodehdl_t lominfh)
1167 {
1168 	int		res;
1169 	int		i;
1170 	int		err = PICL_SUCCESS;
1171 
1172 	res = ioctl(lom_fd, LOMIOCFANSTATE, &fandata);
1173 
1174 	if (res == 0) {
1175 		/*
1176 		 * fan data available through lom, remove any placeholder
1177 		 * fan-unit nodes, they will be superseded via lom.conf
1178 		 */
1179 		char	path[80];
1180 		int	slot;
1181 		picl_nodehdl_t	fan_unit_h;
1182 
1183 		for (slot = 0; slot < MAX_FANS; slot++) {
1184 			(void) snprintf(path, sizeof (path),
1185 			    "/frutree/chassis/fan-slot?Slot=%d/fan-unit", slot);
1186 			if (ptree_get_node_by_path(path, &fan_unit_h) !=
1187 			    PICL_SUCCESS)
1188 				continue;
1189 			if (ptree_delete_node(fan_unit_h) != PICL_SUCCESS)
1190 				continue;
1191 			(void) ptree_destroy_node(fan_unit_h);
1192 		}
1193 		/*
1194 		 * see if fan names can be obtained
1195 		 */
1196 		(void) memset(&info2data, 0, sizeof (info2data));
1197 		/*
1198 		 * if LOMIOCINFO2 not supported, names area
1199 		 * will remain empty
1200 		 */
1201 		(void) ioctl(lom_fd, LOMIOCINFO2, &info2data);
1202 
1203 		/*
1204 		 * for each fan which is present, add a fan node
1205 		 */
1206 		for (i = 0; i < MAX_FANS; i++) {
1207 			char fanname[80];
1208 			picl_nodehdl_t	fanh;
1209 			picl_nodehdl_t	proph;
1210 
1211 			if (fandata.fitted[i] == 0)
1212 				continue;
1213 
1214 			if (info2data.fan_names[i][0] == '\0') {
1215 				(void) snprintf(fanname, sizeof (fanname),
1216 				    "fan%d", i + 1);
1217 			} else {
1218 				(void) strlcpy(fanname, info2data.fan_names[i],
1219 				    sizeof (fanname));
1220 			}
1221 			convert_node_name(fanname);
1222 			err = ptree_create_node(fanname, PICL_CLASS_FAN, &fanh);
1223 			if (err != PICL_SUCCESS)
1224 				break;
1225 
1226 			err = add_volatile_prop(fanh, PICL_PROP_FAN_SPEED,
1227 			    PICL_PTYPE_INT, PICL_READ, sizeof (int),
1228 			    read_fan_speed, NULL, &fan_speed_handles[i]);
1229 			if (err != PICL_SUCCESS)
1230 				break;
1231 
1232 			err = add_regular_prop(fanh, PICL_PROP_LOW_WARNING,
1233 			    PICL_PTYPE_INT, PICL_READ, sizeof (int),
1234 			    &fandata.minspeed[i], &proph);
1235 			if (err != PICL_SUCCESS)
1236 				break;
1237 
1238 			err = add_regular_prop(fanh, PICL_PROP_FAN_SPEED_UNIT,
1239 			    PICL_PTYPE_CHARSTRING, PICL_READ, sizeof ("%"),
1240 			    "%", &proph);
1241 			if (err != PICL_SUCCESS)
1242 				break;
1243 
1244 			err = add_volatile_prop(fanh, PICL_PROP_CONDITION,
1245 			    PICL_PTYPE_CHARSTRING, PICL_READ,
1246 			    sizeof (str_FAIL), read_fan_status, NULL,
1247 			    &fan_status_handles[i]);
1248 			if (err != PICL_SUCCESS)
1249 				break;
1250 
1251 			/*
1252 			 * add a label for prtdiag
1253 			 */
1254 			err = add_regular_prop(fanh, PICL_PROP_LABEL,
1255 			    PICL_PTYPE_CHARSTRING, PICL_READ,
1256 			    strlen(fanname) + 1, fanname, &proph);
1257 			if (err != PICL_SUCCESS)
1258 				break;
1259 
1260 			err = ptree_add_node(lominfh, fanh);
1261 			if (err != PICL_SUCCESS)
1262 				break;
1263 		}
1264 
1265 		if (err != PICL_SUCCESS) {
1266 			syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
1267 		}
1268 	}
1269 
1270 	return (err);
1271 }
1272 
1273 static void
1274 setup_strings()
1275 {
1276 	/*
1277 	 * initialise led colours lookup
1278 	 */
1279 	int i;
1280 	int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]);
1281 
1282 	for (i = 0; i < lim; i++) {
1283 		if (colour_lkup[i].str_colour != NULL)
1284 			free(colour_lkup[i].str_colour);
1285 	}
1286 
1287 	colour_lkup[LOM_LED_COLOUR_ANY].str_colour = strdup(gettext("any"));
1288 	colour_lkup[LOM_LED_COLOUR_WHITE].str_colour = strdup(gettext("white"));
1289 	colour_lkup[LOM_LED_COLOUR_BLUE].str_colour = strdup(gettext("blue"));
1290 	colour_lkup[LOM_LED_COLOUR_GREEN].str_colour = strdup(gettext("green"));
1291 	colour_lkup[LOM_LED_COLOUR_AMBER].str_colour = strdup(gettext("amber"));
1292 
1293 	for (i = 0; i < lim; i++) {
1294 		if (colour_lkup[i].str_colour != NULL)
1295 			colour_lkup[i].size =
1296 			    1 + strlen(colour_lkup[i].str_colour);
1297 	}
1298 
1299 	/*
1300 	 * initialise led state lookup strings
1301 	 */
1302 	fixstate(LOM_LED_OFF, gettext("off"), &max_state_size);
1303 	fixstate(LOM_LED_ON, gettext("on"), &max_state_size);
1304 	fixstate(LOM_LED_BLINKING, gettext("blinking"), &max_state_size);
1305 }
1306 
1307 /*
1308  * The size of outfilename must be PATH_MAX
1309  */
1310 static int
1311 get_config_file(char *outfilename)
1312 {
1313 	char	nmbuf[SYS_NMLN];
1314 	char	pname[PATH_MAX];
1315 
1316 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
1317 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1318 		(void) strlcat(pname, LOM_CONFFILE_NAME, PATH_MAX);
1319 		if (access(pname, R_OK) == 0) {
1320 			(void) strlcpy(outfilename, pname, PATH_MAX);
1321 			return (0);
1322 		}
1323 	}
1324 
1325 	if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
1326 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1327 		(void) strlcat(pname, LOM_CONFFILE_NAME, PATH_MAX);
1328 		if (access(pname, R_OK) == 0) {
1329 			(void) strlcpy(outfilename, pname, PATH_MAX);
1330 			return (0);
1331 		}
1332 	}
1333 
1334 	(void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
1335 	    LOM_CONFFILE_NAME);
1336 
1337 	if (access(pname, R_OK) == 0) {
1338 		(void) strlcpy(outfilename, pname, PATH_MAX);
1339 		return (0);
1340 	}
1341 
1342 	return (-1);
1343 }
1344 
1345 
1346 
1347 /*
1348  * executed as part of .init when the plugin is dlopen()ed
1349  */
1350 static void
1351 picllom_register(void)
1352 {
1353 	(void) picld_plugin_register(&my_reg_info);
1354 }
1355 
1356 /*
1357  * Init entry point of the plugin
1358  * Creates the PICL nodes and properties in the physical and logical aspects.
1359  */
1360 static void
1361 picllom_init(void)
1362 {
1363 	picl_nodehdl_t		rooth;
1364 	picl_nodehdl_t		plfh;
1365 	picl_nodehdl_t		lominfh;
1366 	int			lom_fd;
1367 	char			fullfilename[PATH_MAX];
1368 
1369 	/*
1370 	 * Get platform node
1371 	 */
1372 	if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh)
1373 	    != PICL_SUCCESS) {
1374 		syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM);
1375 		syslog(LOG_ERR, EM_INIT_FAILED);
1376 		return;
1377 	}
1378 
1379 	/*
1380 	 * Get lom node
1381 	 */
1382 	if (get_lom_node(&lominfh) != PICL_SUCCESS) {
1383 		syslog(LOG_ERR, EM_LOM_NODE_MISSING);
1384 		syslog(LOG_ERR, EM_INIT_FAILED);
1385 		return;
1386 	}
1387 
1388 	/*
1389 	 * Retrive the device path to open
1390 	 */
1391 	if (get_lom_device_path(&lominfh) < 0) {
1392 		syslog(LOG_ERR, EM_INIT_FAILED);
1393 		return;
1394 	}
1395 
1396 	/*
1397 	 * Open LOM device and interrogate for devices it monitors
1398 	 */
1399 	if ((lom_fd = open(lom_device_path, O_RDONLY)) < 0) {
1400 		syslog(LOG_ERR, EM_SYS_ERR, lom_device_path, strerror(errno));
1401 		return;
1402 	}
1403 
1404 	setup_strings();
1405 	(void) add_temp_sensors(lom_fd, lominfh);
1406 	(void) add_voltage_monitors(lom_fd, lominfh);
1407 	(void) add_fan_nodes(lom_fd, lominfh);
1408 	add_led_nodes(lom_fd, lominfh);
1409 
1410 
1411 	if (get_config_file(fullfilename) < 0) {
1412 		(void) close(lom_fd);
1413 		syslog(LOG_ERR, EM_NO_CONFIG);
1414 		return;
1415 	}
1416 
1417 	if (ptree_get_root(&rooth) != PICL_SUCCESS) {
1418 		(void) close(lom_fd);
1419 		return;
1420 	}
1421 
1422 	if (picld_pluginutil_parse_config_file(rooth, fullfilename) !=
1423 	    PICL_SUCCESS)
1424 		syslog(LOG_ERR, EM_INIT_FAILED);
1425 
1426 	(void) close(lom_fd);
1427 }
1428 
1429 /*
1430  * fini entry point of the plugin
1431  */
1432 static void
1433 picllom_fini(void)
1434 {
1435 }
1436