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