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 */
45static void	picl_frutree_register(void);
46static void	picl_frutree_init(void);
47static void	picl_frutree_fini(void);
48static 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 */
100static 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 */
111static 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 */
133static 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 */
141static 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" */
158static picl_nodehdl_t	frutreeh;
159
160static int	do_sysboard_init(picl_nodehdl_t, picl_nodehdl_t *);
161static int	do_cpus_init(picl_nodehdl_t);
162static int	do_mem_init(picl_nodehdl_t);
163static int	do_power_supplies_init(picl_nodehdl_t);
164static int	do_fcal_init(picl_nodehdl_t);
165static int	do_rscboard_init(picl_nodehdl_t);
166
167static int	add_ref_prop(picl_nodehdl_t, picl_nodehdl_t, char *);
168static int	add_slot_prop(picl_nodehdl_t, int);
169static int	add_label_prop(picl_nodehdl_t, char *);
170static int	add_void_fda_prop(picl_nodehdl_t);
171static int	add_viewpoints_prop(picl_nodehdl_t, char *);
172static int	add_all_nodes();
173static int	remove_all_nodes(picl_nodehdl_t);
174
175static int	add_hotplug_fru_device(void);
176static int	rem_hotplug_fru_device(void);
177static int	is_added_device(char *, char *);
178static int	is_removed_device(char *, char *);
179static int	add_power_supply(int);
180static int	remove_power_supply(int);
181
182/*
183 * This function is executed as part of .init when the plugin is
184 * dlopen()ed
185 */
186void
187picl_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 */
196void
197picl_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 */
217void
218picl_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 */
238static void
239picl_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 */
253static int
254do_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 */
287static int
288do_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 */
341static int
342do_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 */
396static int
397do_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 */
479static int
480do_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 */
513static int
514do_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 */
547static int
548add_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 */
571static int
572add_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 */
591static int
592add_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 */
615static int
616add_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 */
635static int
636add_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 */
659static int
660add_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 */
738static int
739remove_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 */
766static int
767add_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 */
792static int
793rem_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 */
818static int
819is_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 */
856static int
857is_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 */
892static int
893add_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 */
935static int
936remove_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