xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/littleneck/frutree/piclfrutree.c (revision 763f1f5f97e4c16840af2ced98915f0ed0f46616)
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 (c) 1999-2000 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  * PICL plug-in that creates the FRU Hierarchy for the
29  * SUNW,Sun-Fire-280R (Littleneck) platform
30  */
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <libintl.h>
35 #include <syslog.h>
36 #include <picl.h>
37 #include <picltree.h>
38 #include <picldefs.h>
39 
40 /*
41  * Plugin registration entry points
42  */
43 static void	picl_frutree_register(void);
44 static void	picl_frutree_init(void);
45 static void	picl_frutree_fini(void);
46 static void	picl_frutree_evhandler(const char *ename, const void *earg,
47 		    size_t size, void *cookie);
48 
49 #pragma	init(picl_frutree_register)
50 
51 /*
52  * Log message texts
53  */
54 #define	CREATE_FRUTREE_FAIL	gettext("Failed to create frutree node\n")
55 #define	CREATE_CHASSIS_FAIL	gettext("Failed to create chassis node\n")
56 #define	SYSBRD_INIT_FAIL	gettext("do_sysboard_init() failed\n")
57 #define	CPUS_INIT_FAIL		gettext("do_cpus_init() failed\n")
58 #define	DIMMS_INIT_FAIL		gettext("do_mem_init() failed\n")
59 #define	PS_INIT_FAIL		gettext("do_power_supplies_init() failed\n")
60 #define	FCAL_INIT_FAIL		gettext("do_fcal_init() failed\n")
61 #define	RSC_INIT_FAIL		gettext("do_rscboard_init() failed\n")
62 
63 /*
64  * ViewPoints property field used by SunMC
65  */
66 #define	CHASSIS_VIEWPOINTS	gettext("front top rear")
67 
68 /*
69  * Ref prop values
70  */
71 #define	SEEPROM_SOURCE		"_seeprom_source"
72 #define	FRU_PARENT		"_fru_parent"
73 
74 /*
75  * List of all the FRU locations in the platform_frupath[] array, and
76  * location_label[] array
77  */
78 #define	CPU0	0
79 #define	CPU1	1
80 #define	DIMM0	2
81 #define	DIMM1	3
82 #define	DIMM2	4
83 #define	DIMM3	5
84 #define	DIMM4	6
85 #define	DIMM5	7
86 #define	DIMM6	8
87 #define	DIMM7	9
88 #define	PDB	10
89 #define	PS0	11
90 #define	PS1	12
91 #define	FCAL	13
92 #define	RSC	14
93 #define	SYSBRD	15
94 
95 /*
96  * Local variables
97  */
98 static picld_plugin_reg_t  my_reg_info = {
99 	PICLD_PLUGIN_VERSION_1,
100 	PICLD_PLUGIN_NON_CRITICAL,
101 	"SUNW_Sun-Fire-280R_frutree",
102 	picl_frutree_init,
103 	picl_frutree_fini,
104 };
105 
106 /*
107  * List of all the FRUs in the /platform tree with SEEPROMs
108  */
109 static char *platform_frupath[] = {
110 	"/platform/pci@8,700000/ebus@5/i2c@1,30/cpu-fru@0,a0",
111 	"/platform/pci@8,700000/ebus@5/i2c@1,30/cpu-fru@0,a2",
112 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,a0",
113 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,a2",
114 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,a4",
115 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,a6",
116 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,a8",
117 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,aa",
118 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,ac",
119 	"/platform/pci@8,700000/ebus@5/i2c@1,2e/dimm-fru@1,ae",
120 	"/platform/pci@8,700000/ebus@5/i2c@1,30/power-distribution-board@0,aa",
121 	"/platform/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ac",
122 	"/platform/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ae",
123 	"/platform/pci@8,700000/ebus@5/i2c@1,30/fcal-backplane@0,a4",
124 	"/platform/pci@8,700000/ebus@5/i2c@1,30/remote-system-console@0,a6",
125 	"/platform/pci@8,700000/ebus@5/i2c@1,30/motherboard-fru@0,a8",
126 	NULL};
127 
128 /*
129  * List of all the FRU slots in the frutree that can be hotplugged
130  */
131 static char *frutree_power_supply[] = {
132 	"/frutree/chassis/power-dist-board/power-supply-slot?Slot=0",
133 	"/frutree/chassis/power-dist-board/power-supply-slot?Slot=1",
134 	NULL};
135 
136 /*
137  * List of Labels for FRU locations (uses the #define's from above)
138  */
139 static char *location_label[] = {
140 	"0",
141 	"1",
142 	"J0100",
143 	"J0101",
144 	"J0202",
145 	"J0203",
146 	"J0304",
147 	"J0305",
148 	"J0406",
149 	"J0407",
150 	NULL,			/* power distribution board placeholder */
151 	"0",
152 	"1",
153 	NULL};
154 
155 /* PICL handle for the root node of the "frutree" */
156 static picl_nodehdl_t	frutreeh;
157 
158 static int	do_sysboard_init(picl_nodehdl_t, picl_nodehdl_t *);
159 static int	do_cpus_init(picl_nodehdl_t);
160 static int	do_mem_init(picl_nodehdl_t);
161 static int	do_power_supplies_init(picl_nodehdl_t);
162 static int	do_fcal_init(picl_nodehdl_t);
163 static int	do_rscboard_init(picl_nodehdl_t);
164 
165 static int	add_ref_prop(picl_nodehdl_t, picl_nodehdl_t, char *);
166 static int	add_slot_prop(picl_nodehdl_t, int);
167 static int	add_label_prop(picl_nodehdl_t, char *);
168 static int	add_void_fda_prop(picl_nodehdl_t);
169 static int	add_viewpoints_prop(picl_nodehdl_t, char *);
170 static int	add_all_nodes();
171 static int	remove_all_nodes(picl_nodehdl_t);
172 
173 static int	add_hotplug_fru_device(void);
174 static int	rem_hotplug_fru_device(void);
175 static int	is_added_device(char *, char *);
176 static int	is_removed_device(char *, char *);
177 static int	add_power_supply(int);
178 static int	remove_power_supply(int);
179 
180 /*
181  * This function is executed as part of .init when the plugin is
182  * dlopen()ed
183  */
184 void
185 picl_frutree_register()
186 {
187 	(void) picld_plugin_register(&my_reg_info);
188 }
189 
190 /*
191  * This function is the init entry point of the plugin.
192  * It initializes the /frutree tree
193  */
194 void
195 picl_frutree_init()
196 {
197 	int		err;
198 
199 	err = add_all_nodes();
200 	if (err != PICL_SUCCESS) {
201 		(void) remove_all_nodes(frutreeh);
202 		return;
203 	}
204 
205 	/* Register the event handler routine */
206 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
207 	    picl_frutree_evhandler, NULL);
208 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
209 	    picl_frutree_evhandler, NULL);
210 }
211 
212 /*
213  * This function is the fini entry point of the plugin
214  */
215 void
216 picl_frutree_fini(void)
217 {
218 	/* Unregister the event handler routine */
219 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
220 	    picl_frutree_evhandler, NULL);
221 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
222 	    picl_frutree_evhandler, NULL);
223 
224 	(void) remove_all_nodes(frutreeh);
225 }
226 
227 /*
228  * This function is the event handler of this plug-in.
229  *
230  * It processes the following events:
231  *
232  *	PICLEVENT_SYSEVENT_DEVICE_ADDED
233  *	PICLEVENT_SYSEVENT_DEVICE_REMOVED
234  */
235 /* ARGSUSED */
236 static void
237 picl_frutree_evhandler(const char *ename, const void *earg, size_t size,
238     void *cookie)
239 {
240 	if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) {
241 		/* Check for and add any hotplugged device(s) */
242 		(void) add_hotplug_fru_device();
243 
244 	} else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) {
245 		/* Check for and remove any hotplugged device(s) */
246 		(void) rem_hotplug_fru_device();
247 	}
248 }
249 
250 /* Initialize the FRU node for the system board */
251 static int
252 do_sysboard_init(picl_nodehdl_t rooth, picl_nodehdl_t *childh)
253 {
254 	picl_nodehdl_t		tmph;
255 	int			err;
256 
257 	/* Create the node for the system board */
258 	if (ptree_get_node_by_path(platform_frupath[SYSBRD], &tmph) ==
259 	    PICL_SUCCESS) {
260 		err = ptree_create_node("system-board", "fru", childh);
261 		if (err != PICL_SUCCESS)
262 			return (err);
263 
264 		err = add_ref_prop(*childh, tmph, SEEPROM_SOURCE);
265 		if (err != PICL_SUCCESS)
266 			return (err);
267 
268 		err = add_void_fda_prop(*childh);
269 		if (err != PICL_SUCCESS)
270 			return (err);
271 
272 		err = ptree_add_node(rooth, *childh);
273 		if (err != PICL_SUCCESS)
274 			return (err);
275 
276 		err = add_ref_prop(tmph, *childh, FRU_PARENT);
277 		if (err != PICL_SUCCESS)
278 			return (err);
279 
280 	}
281 	return (PICL_SUCCESS);
282 }
283 
284 /* Initializes the FRU nodes for the CPU modules */
285 static int
286 do_cpus_init(picl_nodehdl_t rooth)
287 {
288 	picl_nodehdl_t		cpusloth;
289 	picl_nodehdl_t		cpumodh;
290 	picl_nodehdl_t		tmph;
291 	int			i, err;
292 
293 	for (i = CPU0; i <= CPU1; i++) {
294 		/* Create the node for the CPU slot */
295 		err = ptree_create_node("cpu-slot", "location", &cpusloth);
296 		if (err != PICL_SUCCESS)
297 			return (err);
298 
299 		err = add_slot_prop(cpusloth, i);
300 		if (err != PICL_SUCCESS)
301 			return (err);
302 
303 		err = add_label_prop(cpusloth, location_label[i]);
304 		if (err != PICL_SUCCESS)
305 			return (err);
306 
307 		err = ptree_add_node(rooth, cpusloth);
308 		if (err != PICL_SUCCESS)
309 			return (err);
310 
311 		/* If the CPU module exists, create a node for it */
312 		if (ptree_get_node_by_path(platform_frupath[i], &tmph) ==
313 		    PICL_SUCCESS) {
314 			err = ptree_create_node("cpu-module", "fru", &cpumodh);
315 			if (err != PICL_SUCCESS)
316 				return (err);
317 
318 			err = add_ref_prop(cpumodh, tmph, SEEPROM_SOURCE);
319 			if (err != PICL_SUCCESS)
320 				return (err);
321 
322 			err = add_void_fda_prop(cpumodh);
323 			if (err != PICL_SUCCESS)
324 				return (err);
325 
326 			err = ptree_add_node(cpusloth, cpumodh);
327 			if (err != PICL_SUCCESS)
328 				return (err);
329 
330 			err = add_ref_prop(tmph, cpumodh, FRU_PARENT);
331 			if (err != PICL_SUCCESS)
332 				return (err);
333 		}
334 	}
335 	return (PICL_SUCCESS);
336 }
337 
338 /* Initializes the FRU nodes for the memory modules */
339 static int
340 do_mem_init(picl_nodehdl_t rooth)
341 {
342 	picl_nodehdl_t		memsloth;
343 	picl_nodehdl_t		memmodh;
344 	picl_nodehdl_t		tmph;
345 	int			i, err, slotnum;
346 
347 	for (i = DIMM0; i <= DIMM7; i++) {
348 		/* Create the node for the memory slot */
349 		err = ptree_create_node("mem-slot", "location", &memsloth);
350 		if (err != PICL_SUCCESS)
351 			return (err);
352 
353 		slotnum = i - DIMM0;
354 		err = add_slot_prop(memsloth, slotnum);
355 		if (err != PICL_SUCCESS)
356 			return (err);
357 
358 		err = add_label_prop(memsloth, location_label[i]);
359 		if (err != PICL_SUCCESS)
360 			return (err);
361 
362 		err = ptree_add_node(rooth, memsloth);
363 		if (err != PICL_SUCCESS)
364 			return (err);
365 
366 		/* If the memory exists, create a node for it */
367 		if (ptree_get_node_by_path(platform_frupath[i], &tmph) ==
368 		    PICL_SUCCESS) {
369 			err = ptree_create_node("mem-module", "fru", &memmodh);
370 			if (err != PICL_SUCCESS)
371 				return (err);
372 
373 			err = add_ref_prop(memmodh, tmph, SEEPROM_SOURCE);
374 			if (err != PICL_SUCCESS)
375 				return (err);
376 
377 			err = add_void_fda_prop(memmodh);
378 			if (err != PICL_SUCCESS)
379 				return (err);
380 
381 			err = ptree_add_node(memsloth, memmodh);
382 			if (err != PICL_SUCCESS)
383 				return (err);
384 
385 			err = add_ref_prop(tmph, memmodh, FRU_PARENT);
386 			if (err != PICL_SUCCESS)
387 				return (err);
388 		}
389 	}
390 	return (PICL_SUCCESS);
391 }
392 
393 /* Initializes the FRU nodes for the PDB and the power supplies */
394 static int
395 do_power_supplies_init(picl_nodehdl_t rooth)
396 {
397 	picl_nodehdl_t		powerbrdh;
398 	picl_nodehdl_t		powersloth;
399 	picl_nodehdl_t		powermodh;
400 	picl_nodehdl_t		tmph;
401 	int			i, err, slotnum;
402 
403 	/* Create the node for the PDB (if it exists) */
404 	if (ptree_get_node_by_path(platform_frupath[PDB], &tmph) ==
405 	    PICL_SUCCESS) {
406 		err = ptree_create_node("power-dist-board", "fru", &powerbrdh);
407 		if (err != PICL_SUCCESS)
408 			return (err);
409 
410 		err = add_ref_prop(powerbrdh, tmph, SEEPROM_SOURCE);
411 		if (err != PICL_SUCCESS)
412 			return (err);
413 
414 		err = add_void_fda_prop(powerbrdh);
415 		if (err != PICL_SUCCESS)
416 			return (err);
417 
418 		err = ptree_add_node(rooth, powerbrdh);
419 		if (err != PICL_SUCCESS)
420 			return (err);
421 
422 		err = add_ref_prop(tmph, powerbrdh, FRU_PARENT);
423 		if (err != PICL_SUCCESS)
424 			return (err);
425 
426 		for (i = PS0; i <= PS1; i++) {
427 			/* Create the node for the power supply slot */
428 			err = ptree_create_node("power-supply-slot",
429 			    "location", &powersloth);
430 			if (err != PICL_SUCCESS)
431 				return (err);
432 
433 			slotnum = i - PS0;
434 			err = add_slot_prop(powersloth, slotnum);
435 			if (err != PICL_SUCCESS)
436 				return (err);
437 
438 			err = add_label_prop(powersloth, location_label[i]);
439 			if (err != PICL_SUCCESS)
440 				return (err);
441 
442 			err = ptree_add_node(powerbrdh, powersloth);
443 			if (err != PICL_SUCCESS)
444 				return (err);
445 
446 			/* If the PS exists, create a node for it */
447 			if (ptree_get_node_by_path(platform_frupath[i],
448 			    &tmph) == PICL_SUCCESS) {
449 				err = ptree_create_node("power-supply",
450 				    "fru", &powermodh);
451 				if (err != PICL_SUCCESS)
452 					return (err);
453 
454 				err = add_ref_prop(powermodh, tmph,
455 				    SEEPROM_SOURCE);
456 				if (err != PICL_SUCCESS)
457 					return (err);
458 
459 				err = add_void_fda_prop(powermodh);
460 				if (err != PICL_SUCCESS)
461 					return (err);
462 
463 				err = ptree_add_node(powersloth, powermodh);
464 				if (err != PICL_SUCCESS)
465 					return (err);
466 
467 				err = add_ref_prop(tmph, powermodh, FRU_PARENT);
468 				if (err != PICL_SUCCESS)
469 					return (err);
470 			}
471 		}
472 	}
473 	return (PICL_SUCCESS);
474 }
475 
476 /* Initializes the FRU nodes for the FCAL backplane */
477 static int
478 do_fcal_init(picl_nodehdl_t rooth)
479 {
480 	picl_nodehdl_t		fcalbrdh;
481 	picl_nodehdl_t		tmph;
482 	int			err;
483 
484 	/* Create the node for the FCAL backplane (if it exists) */
485 	if (ptree_get_node_by_path(platform_frupath[FCAL], &tmph) ==
486 	    PICL_SUCCESS) {
487 		err = ptree_create_node("fcal-backplane", "fru", &fcalbrdh);
488 		if (err != PICL_SUCCESS)
489 			return (err);
490 
491 		err = add_ref_prop(fcalbrdh, tmph, SEEPROM_SOURCE);
492 		if (err != PICL_SUCCESS)
493 			return (err);
494 
495 		err = add_void_fda_prop(fcalbrdh);
496 		if (err != PICL_SUCCESS)
497 			return (err);
498 
499 		err = ptree_add_node(rooth, fcalbrdh);
500 		if (err != PICL_SUCCESS)
501 			return (err);
502 
503 		err = add_ref_prop(tmph, fcalbrdh, FRU_PARENT);
504 		if (err != PICL_SUCCESS)
505 			return (err);
506 	}
507 	return (PICL_SUCCESS);
508 }
509 
510 /* Initializes the FRU node for the RSC card */
511 static int
512 do_rscboard_init(picl_nodehdl_t rooth)
513 {
514 	picl_nodehdl_t		rscbrdh;
515 	picl_nodehdl_t		tmph;
516 	int			err;
517 
518 	/* Create the node for the RSC board (if it exists) */
519 	if (ptree_get_node_by_path(platform_frupath[RSC], &tmph) ==
520 	    PICL_SUCCESS) {
521 		err = ptree_create_node("rsc-board", "fru", &rscbrdh);
522 		if (err != PICL_SUCCESS)
523 			return (err);
524 
525 		err = add_ref_prop(rscbrdh, tmph, SEEPROM_SOURCE);
526 		if (err != PICL_SUCCESS)
527 			return (err);
528 
529 		err = add_void_fda_prop(rscbrdh);
530 		if (err != PICL_SUCCESS)
531 			return (err);
532 
533 		err = ptree_add_node(rooth, rscbrdh);
534 		if (err != PICL_SUCCESS)
535 			return (err);
536 
537 		err = add_ref_prop(tmph, rscbrdh, FRU_PARENT);
538 		if (err != PICL_SUCCESS)
539 			return (err);
540 	}
541 	return (PICL_SUCCESS);
542 }
543 
544 /* Creates a "reference" property between two PICL nodes */
545 static int
546 add_ref_prop(picl_nodehdl_t nodeh, picl_nodehdl_t tmph, char *str)
547 {
548 	picl_prophdl_t		proph;
549 	ptree_propinfo_t	propinfo;
550 	int			err;
551 
552 	if (str == NULL)
553 		return (PICL_FAILURE);
554 
555 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
556 	    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t),
557 	    str, NULL, NULL);
558 	if (err != PICL_SUCCESS)
559 		return (err);
560 
561 	err = ptree_create_and_add_prop(nodeh, &propinfo, &tmph, &proph);
562 	if (err != PICL_SUCCESS)
563 		return (err);
564 
565 	return (PICL_SUCCESS);
566 }
567 
568 /* Creates a "Slot" property for a given PICL node */
569 static int
570 add_slot_prop(picl_nodehdl_t nodeh, int slotnum)
571 {
572 	picl_prophdl_t		proph;
573 	ptree_propinfo_t	propinfo;
574 	int			err;
575 
576 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
577 	    PICL_PTYPE_INT, PICL_READ, 4, "Slot", NULL, NULL);
578 	if (err != PICL_SUCCESS)
579 		return (err);
580 
581 	err = ptree_create_and_add_prop(nodeh, &propinfo, &slotnum, &proph);
582 	if (err != PICL_SUCCESS)
583 		return (err);
584 
585 	return (PICL_SUCCESS);
586 }
587 
588 /* Creates a "Label" property for a given PICL node */
589 static int
590 add_label_prop(picl_nodehdl_t nodeh, char *label)
591 {
592 	picl_prophdl_t		proph;
593 	ptree_propinfo_t	propinfo;
594 	int			err;
595 
596 	if (label == NULL)
597 		return (PICL_FAILURE);
598 
599 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
600 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(label)+1, "Label",
601 	    NULL, NULL);
602 	if (err != PICL_SUCCESS)
603 		return (err);
604 
605 	err = ptree_create_and_add_prop(nodeh, &propinfo, label, &proph);
606 	if (err != PICL_SUCCESS)
607 		return (err);
608 
609 	return (PICL_SUCCESS);
610 }
611 
612 /* Creates a "FRUDataAvailable" void property for the given PICL node */
613 static int
614 add_void_fda_prop(picl_nodehdl_t nodeh)
615 {
616 	picl_prophdl_t		proph;
617 	ptree_propinfo_t	propinfo;
618 	int			err;
619 
620 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
621 	    PICL_PTYPE_VOID, PICL_READ, 0, "FRUDataAvailable", NULL, NULL);
622 	if (err != PICL_SUCCESS)
623 		return (err);
624 
625 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
626 	if (err != PICL_SUCCESS)
627 		return (err);
628 
629 	return (PICL_SUCCESS);
630 }
631 
632 /* Creates a "ViewPoints" property -- used for chassis */
633 static int
634 add_viewpoints_prop(picl_nodehdl_t nodeh, char *string)
635 {
636 	picl_prophdl_t		proph;
637 	ptree_propinfo_t	propinfo;
638 	int			err;
639 
640 	if (string == NULL)
641 		return (PICL_FAILURE);
642 
643 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
644 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(string)+1, "ViewPoints",
645 	    NULL, NULL);
646 	if (err != PICL_SUCCESS)
647 		return (err);
648 
649 	err = ptree_create_and_add_prop(nodeh, &propinfo, string, &proph);
650 	if (err != PICL_SUCCESS)
651 		return (err);
652 
653 	return (PICL_SUCCESS);
654 }
655 
656 /* Creates and adds all of the frutree nodes */
657 static int
658 add_all_nodes()
659 {
660 	picl_nodehdl_t	rooth;
661 	picl_nodehdl_t	chassish;
662 	picl_nodehdl_t	sysboardh;
663 	int		err;
664 
665 	/* Get the root node of the PICL tree */
666 	err = ptree_get_root(&rooth);
667 	if (err != PICL_SUCCESS) {
668 		return (err);
669 	}
670 
671 	/* Create and add the root node of the FRU subtree */
672 	err = ptree_create_and_add_node(rooth, "frutree", "picl", &frutreeh);
673 	if (err != PICL_SUCCESS) {
674 		syslog(LOG_ERR, CREATE_FRUTREE_FAIL);
675 		return (err);
676 	}
677 
678 	/* Create and add the chassis node */
679 	err = ptree_create_and_add_node(frutreeh, "chassis", "fru", &chassish);
680 	if (err != PICL_SUCCESS) {
681 		syslog(LOG_ERR, CREATE_CHASSIS_FAIL);
682 		return (err);
683 	}
684 
685 	/* Add ViewPoints prop to chassis node */
686 	err = add_viewpoints_prop(chassish, CHASSIS_VIEWPOINTS);
687 	if (err != PICL_SUCCESS)
688 		return (err);
689 
690 	/* Initialize the FRU node for the system board */
691 	err = do_sysboard_init(chassish, &sysboardh);
692 	if (err != PICL_SUCCESS) {
693 		syslog(LOG_ERR, SYSBRD_INIT_FAIL);
694 		return (err);
695 	}
696 
697 	/* Initialize the FRU nodes for the CPU modules */
698 	err = do_cpus_init(sysboardh);
699 	if (err != PICL_SUCCESS) {
700 		syslog(LOG_ERR, CPUS_INIT_FAIL);
701 		return (err);
702 	}
703 
704 	/* Initialize the FRU nodes for the memory modules */
705 	err = do_mem_init(sysboardh);
706 	if (err != PICL_SUCCESS) {
707 		syslog(LOG_ERR, DIMMS_INIT_FAIL);
708 		return (err);
709 	}
710 
711 	/* Initialize the FRU nodes for the PDB and the power supplies */
712 	err = do_power_supplies_init(chassish);
713 	if (err != PICL_SUCCESS) {
714 		syslog(LOG_ERR, PS_INIT_FAIL);
715 		return (err);
716 	}
717 
718 	/* Initialize the FRU nodes for the FCAL backplane */
719 	err = do_fcal_init(chassish);
720 	if (err != PICL_SUCCESS) {
721 		syslog(LOG_ERR, FCAL_INIT_FAIL);
722 		return (err);
723 	}
724 
725 	/* Initialize the FRU node for the RSC card */
726 	err = do_rscboard_init(chassish);
727 	if (err != PICL_SUCCESS) {
728 		syslog(LOG_ERR, RSC_INIT_FAIL);
729 		return (err);
730 	}
731 
732 	return (PICL_SUCCESS);
733 }
734 
735 /* Deletes and destroys all PICL nodes for which rooth is a ancestor */
736 static int
737 remove_all_nodes(picl_nodehdl_t rooth)
738 {
739 	picl_nodehdl_t		chdh;
740 	int			err, done = 0;
741 
742 	while (!done) {
743 		err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
744 		    sizeof (picl_nodehdl_t));
745 		if (err != PICL_PROPNOTFOUND) {
746 			(void) remove_all_nodes(chdh);
747 		} else {
748 			err = ptree_delete_node(rooth);
749 			if (err != PICL_SUCCESS) {
750 				return (err);
751 			} else {
752 				(void) ptree_destroy_node(rooth);
753 			}
754 			done = 1;
755 		}
756 	}
757 	return (PICL_SUCCESS);
758 }
759 
760 /*
761  * Searches the list of hotpluggable FRUs for this platform and adds the
762  * appropriate node(s) to the frutree
763  */
764 static int
765 add_hotplug_fru_device()
766 {
767 	int		i, err, slotnum;
768 
769 	/* Check for hotplugged power supplies */
770 	for (i = PS0; i <= PS1; i++) {
771 		/* Compare the /platform tree to the frutree */
772 		slotnum = i - PS0;
773 		err = is_added_device(platform_frupath[i],
774 		    frutree_power_supply[slotnum]);
775 		if (err != PICL_SUCCESS)
776 			continue;
777 
778 		/* If they are different, then add a power supply */
779 		err = add_power_supply(slotnum);
780 		if (err != PICL_SUCCESS)
781 			continue;
782 	}
783 	return (PICL_SUCCESS);
784 }
785 
786 /*
787  * Searches the list of hotpluggable FRUs for this platform and removes the
788  * appropriate node(s) from the frutree
789  */
790 static int
791 rem_hotplug_fru_device()
792 {
793 	int		i, err, slotnum;
794 
795 	/* Check for hotplugged power supplies */
796 	for (i = PS0; i <= PS1; i++) {
797 		/* Compare the /platform tree to the frutree */
798 		slotnum = i - PS0;
799 		err = is_removed_device(platform_frupath[i],
800 		    frutree_power_supply[slotnum]);
801 		if (err != PICL_SUCCESS)
802 			continue;
803 
804 		/* If they are different, then remove a power supply */
805 		err = remove_power_supply(slotnum);
806 		if (err != PICL_SUCCESS)
807 			continue;
808 	}
809 	return (PICL_SUCCESS);
810 }
811 
812 /*
813  * Compare the /platform tree to the /frutree to determine if a
814  * new device has been added
815  */
816 static int
817 is_added_device(char *plat, char *fru)
818 {
819 	int		err;
820 	picl_nodehdl_t	plath, frusloth, frumodh;
821 
822 	/* Check for node in the /platform tree */
823 	err = ptree_get_node_by_path(plat, &plath);
824 	if (err != PICL_SUCCESS)
825 		return (err);
826 
827 	/*
828 	 * The node is in /platform, so find the corresponding slot in
829 	 * the frutree
830 	 */
831 	err = ptree_get_node_by_path(fru, &frusloth);
832 	if (err != PICL_SUCCESS)
833 		return (err);
834 
835 	/*
836 	 * If the slot in the frutree has a child, then return
837 	 * PICL_FAILURE.  This means that the /platform tree and
838 	 * the frutree are consistent and no action is necessary.
839 	 * Otherwise return PICL_SUCCESS to indicate that a node needs
840 	 * to be added to the frutree
841 	 */
842 	err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD,
843 	    &frumodh, sizeof (picl_nodehdl_t));
844 	if (err == PICL_SUCCESS)
845 		return (PICL_FAILURE);
846 
847 	return (PICL_SUCCESS);
848 }
849 
850 /*
851  * Compare the /platform tree to the /frutree to determine if a
852  * device has been removed
853  */
854 static int
855 is_removed_device(char *plat, char *fru)
856 {
857 	int		err;
858 	picl_nodehdl_t	plath, frusloth, frumodh;
859 
860 
861 	/* Check for node in /platform tree */
862 	err = ptree_get_node_by_path(plat, &plath);
863 	if (err == PICL_SUCCESS)
864 		return (PICL_FAILURE);
865 
866 	/*
867 	 * The node is not in /platform, so find the corresponding slot in
868 	 * the frutree
869 	 */
870 	err = ptree_get_node_by_path(fru, &frusloth);
871 	if (err != PICL_SUCCESS)
872 		return (err);
873 
874 	/*
875 	 * If the slot in the frutree does not have a child, then return
876 	 * PICL_FAILURE.  This means that the /platform tree and
877 	 * the frutree are consistent and no action is necessary.
878 	 * Otherwise return PICL_SUCCESS to indicate that the needs
879 	 * to be removed from the frutree
880 	 */
881 	err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD,
882 	    &frumodh, sizeof (picl_nodehdl_t));
883 	if (err != PICL_SUCCESS)
884 		return (PICL_FAILURE);
885 
886 	return (PICL_SUCCESS);
887 }
888 
889 /* Hotplug routine used to add a new power supply */
890 static int
891 add_power_supply(int slotnum)
892 {
893 	picl_nodehdl_t		powersloth;
894 	picl_nodehdl_t		powermodh;
895 	picl_nodehdl_t		tmph;
896 	int			i, err;
897 
898 	/* Find the node for the given power supply slot */
899 	if (ptree_get_node_by_path(frutree_power_supply[slotnum],
900 	    &powersloth) == PICL_SUCCESS) {
901 
902 		i = slotnum + PS0;
903 
904 		/* Make sure it's in /platform and create the frutree node */
905 		if (ptree_get_node_by_path(platform_frupath[i], &tmph) ==
906 		    PICL_SUCCESS) {
907 			err = ptree_create_node("power-supply", "fru",
908 			    &powermodh);
909 			if (err != PICL_SUCCESS)
910 				return (err);
911 
912 			err = add_ref_prop(powermodh, tmph, SEEPROM_SOURCE);
913 			if (err != PICL_SUCCESS)
914 				return (err);
915 
916 			err = add_void_fda_prop(powermodh);
917 			if (err != PICL_SUCCESS)
918 				return (err);
919 
920 			err = ptree_add_node(powersloth, powermodh);
921 			if (err != PICL_SUCCESS)
922 				return (err);
923 
924 			err = add_ref_prop(tmph, powermodh, FRU_PARENT);
925 			if (err != PICL_SUCCESS)
926 				return (err);
927 		}
928 	}
929 	return (PICL_SUCCESS);
930 }
931 
932 /* Hotplug routine used to remove an existing power supply */
933 static int
934 remove_power_supply(int slotnum)
935 {
936 	picl_nodehdl_t		powersloth;
937 	picl_nodehdl_t		powermodh;
938 	int			err;
939 
940 	/* Find the node for the given power supply slot */
941 	if (ptree_get_node_by_path(frutree_power_supply[slotnum],
942 	    &powersloth) == PICL_SUCCESS) {
943 		/* Make sure it's got a child, then delete it */
944 		err = ptree_get_propval_by_name(powersloth, PICL_PROP_CHILD,
945 		    &powermodh, sizeof (picl_nodehdl_t));
946 		if (err != PICL_SUCCESS) {
947 			return (err);
948 		}
949 
950 		err = ptree_delete_node(powermodh);
951 		if (err != PICL_SUCCESS) {
952 			return (err);
953 		} else {
954 			(void) ptree_destroy_node(powermodh);
955 		}
956 	}
957 	return (PICL_SUCCESS);
958 }
959