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 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * PICL plug-in that creates the FRU Hierarchy for the
29 * SUNW,Sun-Fire-880 (Daktari) platform
30 */
31
32#include <stdio.h>
33#include <string.h>
34#include <libintl.h>
35#include <libnvpair.h>
36#include <syslog.h>
37#include <picl.h>
38#include <picltree.h>
39#include <picldefs.h>
40
41/*
42 * Plugin registration entry points
43 */
44static void	picl_frutree_register(void);
45static void	picl_frutree_init(void);
46static void	picl_frutree_fini(void);
47static void	picl_frutree_evhandler(const char *ename, const void *earg,
48		    size_t size, void *cookie);
49
50#pragma	init(picl_frutree_register)
51
52/*
53 * Log message texts
54 */
55#define	CREATE_FRUTREE_FAIL	gettext("Failed to create frutree node\n")
56#define	CREATE_CHASSIS_FAIL	gettext("Failed to create chassis node\n")
57#define	IOBRD_INIT_FAIL		gettext("do_ioboard_init() failed\n")
58#define	RSCBRD_INIT_FAIL	gettext("do_rscboard_init() failed\n")
59#define	FCAL_INIT_FAIL		gettext("do_fcal_init() failed\n")
60#define	PS_INIT_FAIL		gettext("do_power_supplies_init() failed\n")
61#define	SYSBOARD_INIT_FAIL	gettext("do_motherboard_init() failed\n")
62
63/*
64 * Viewpoints property field used by SunMC
65 */
66#define	CHASSIS_VIEWPOINTS	gettext("front left right 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	IOBRD		0
79#define	RSC		1
80#define	FCAL0		2
81#define	FCAL1		3
82#define	FCALGBIC	4
83#define	PDB		5
84#define	PS0		6
85#define	PS1		7
86#define	PS2		8
87#define	SYSBRD		9
88#define	CPUMOD0		10
89#define	CPUMOD1		11
90#define	CPUMOD2		12
91#define	CPUMOD3		13
92#define	CPU0_DIMM0	14
93#define	DIMMS_PER_MOD	8
94#define	DIMMS_PER_SLOT	16
95
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-880_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@9,700000/ebus@1/i2c@1,2e/fru@4,aa", /* IO */
113	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6", /* RSC */
114	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a8", /* FCAL 0 */
115	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,ac", /* FCAL 1 */
116	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,aa", /* FCAL-GBIC */
117	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,ae", /* PDB */
118	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a0", /* PS 0 */
119	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a2", /* PS 1 */
120	"/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a4", /* PS 2 */
121	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a8", /* SYS BRD */
122	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a0", /* CPU MOD 0 */
123	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a2", /* CPU MOD 1 */
124	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@4,a4", /* CPU MOD 2 */
125	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@4,a6", /* CPU MOD 3 */
126	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a0", /* CPU0 DIMM0 */
127	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a2", /* CPU0 DIMM1 */
128	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a4", /* CPU0 DIMM2 */
129	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a6", /* CPU0 DIMM3 */
130	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a8", /* CPU0 DIMM4 */
131	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,aa", /* CPU0 DIMM5 */
132	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ac", /* CPU0 DIMM6 */
133	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ae", /* CPU0 DIMM7 */
134	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a0", /* CPU2 DIMM0 */
135	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a2", /* CPU2 DIMM1 */
136	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a4", /* CPU2 DIMM2 */
137	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a6", /* CPU2 DIMM3 */
138	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a8", /* CPU2 DIMM4 */
139	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,aa", /* CPU2 DIMM5 */
140	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ac", /* CPU2 DIMM6 */
141	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ae", /* CPU2 DIMM7 */
142	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a0", /* CPU1 DIMM0 */
143	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a2", /* CPU1 DIMM1 */
144	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a4", /* CPU1 DIMM2 */
145	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a6", /* CPU1 DIMM3 */
146	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a8", /* CPU1 DIMM4 */
147	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,aa", /* CPU1 DIMM5 */
148	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ac", /* CPU1 DIMM6 */
149	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ae", /* CPU1 DIMM7 */
150	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a0", /* CPU3 DIMM0 */
151	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a2", /* CPU3 DIMM1 */
152	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a4", /* CPU3 DIMM2 */
153	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a6", /* CPU3 DIMM3 */
154	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a8", /* CPU3 DIMM4 */
155	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,aa", /* CPU3 DIMM5 */
156	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ac", /* CPU3 DIMM6 */
157	"/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ae", /* CPU3 DIMM7 */
158	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a0", /* CPU4 DIMM0 */
159	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a2", /* CPU4 DIMM1 */
160	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a4", /* CPU4 DIMM2 */
161	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a6", /* CPU4 DIMM3 */
162	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a8", /* CPU4 DIMM4 */
163	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,aa", /* CPU4 DIMM5 */
164	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,ac", /* CPU4 DIMM6 */
165	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,ae", /* CPU4 DIMM7 */
166	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a0", /* CPU6 DIMM0 */
167	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a2", /* CPU6 DIMM1 */
168	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a4", /* CPU6 DIMM2 */
169	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a6", /* CPU6 DIMM3 */
170	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a8", /* CPU6 DIMM4 */
171	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,aa", /* CPU6 DIMM5 */
172	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,ac", /* CPU6 DIMM6 */
173	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,ae", /* CPU6 DIMM7 */
174	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a0", /* CPU5 DIMM0 */
175	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a2", /* CPU5 DIMM1 */
176	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a4", /* CPU5 DIMM2 */
177	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a6", /* CPU5 DIMM3 */
178	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a8", /* CPU5 DIMM4 */
179	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,aa", /* CPU5 DIMM5 */
180	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,ac", /* CPU5 DIMM6 */
181	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,ae", /* CPU5 DIMM7 */
182	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a0", /* CPU7 DIMM0 */
183	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a2", /* CPU7 DIMM1 */
184	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a4", /* CPU7 DIMM2 */
185	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a6", /* CPU7 DIMM3 */
186	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a8", /* CPU7 DIMM4 */
187	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,aa", /* CPU7 DIMM5 */
188	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,ac", /* CPU7 DIMM6 */
189	"/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,ae", /* CPU7 DIMM7 */
190	NULL};
191
192/*
193 * List of Labels for FRU locations (uses the #define's from above)
194 */
195static char *location_label[] = {
196	NULL,			/* IOBRD */
197	NULL,			/* RSC */
198	"0",			/* FCAL0 */
199	"1",			/* FCAL1 */
200	NULL,			/* FCALGBIC */
201	NULL,			/* PDB */
202	"0",			/* PS0 */
203	"1",			/* PS1 */
204	"2",			/* PS2 */
205	NULL,			/* SYSBRD */
206	"A",			/* CPUMOD0 */
207	"B",			/* CPUMOD1 */
208	"C",			/* CPUMOD2 */
209	"D",			/* CPUMOD3 */
210	"J2900",		/* CPU0 DIMM0 */
211	"J3100",		/* CPU0 DIMM1 */
212	"J2901",		/* CPU0 DIMM2 */
213	"J3101",		/* CPU0 DIMM3 */
214	"J3000",		/* CPU0 DIMM4 */
215	"J3200",		/* CPU0 DIMM5 */
216	"J3001",		/* CPU0 DIMM6 */
217	"J3201",		/* CPU0 DIMM7 */
218	"J7900",		/* CPU1 DIMM0 */
219	"J8100",		/* CPU1 DIMM1 */
220	"J7901",		/* CPU1 DIMM2 */
221	"J8101",		/* CPU1 DIMM3 */
222	"J8000",		/* CPU1 DIMM4 */
223	"J8200",		/* CPU1 DIMM5 */
224	"J8001",		/* CPU1 DIMM6 */
225	"J8201",		/* CPU1 DIMM7 */
226	"0",			/* CPU0 label */
227	"1",			/* CPU1 label */
228	NULL};
229
230/*
231 * List of all the FRU slots for power supplies (hotpluggable)
232 */
233static char *frutree_power_supply[] = {
234	"/frutree/chassis/power-dist-board/power-supply-slot?Slot=0",
235	"/frutree/chassis/power-dist-board/power-supply-slot?Slot=1",
236	"/frutree/chassis/power-dist-board/power-supply-slot?Slot=2",
237	NULL};
238
239/*
240 * List of all the FRU slots for CPU Memory modules (hotpluggable)
241 */
242static char *frutree_cpu_module[] = {
243	"/frutree/chassis/system-board/cpu-mem-slot?Slot=0",
244	"/frutree/chassis/system-board/cpu-mem-slot?Slot=1",
245	"/frutree/chassis/system-board/cpu-mem-slot?Slot=2",
246	"/frutree/chassis/system-board/cpu-mem-slot?Slot=3",
247	NULL};
248
249/* PICL handle for the root node of the "frutree" */
250static picl_nodehdl_t	frutreeh;
251
252static int	do_ioboard_init(picl_nodehdl_t);
253static int	do_rscboard_init(picl_nodehdl_t);
254static int	do_fcal_init(picl_nodehdl_t);
255static int	do_power_supplies_init(picl_nodehdl_t);
256static int	do_motherboard_init(picl_nodehdl_t);
257static int	do_cpu_module_init(picl_nodehdl_t, int);
258static int	do_dimms_init(picl_nodehdl_t, int, int);
259
260static int	add_ref_prop(picl_nodehdl_t, picl_nodehdl_t, char *);
261static int	add_slot_prop(picl_nodehdl_t, int);
262static int	add_label_prop(picl_nodehdl_t, char *);
263static int	add_void_fda_prop(picl_nodehdl_t);
264static int	add_viewpoints_prop(picl_nodehdl_t, char *);
265static int	add_all_nodes();
266static int	remove_all_nodes(picl_nodehdl_t);
267
268static int	add_hotplug_fru_device(void);
269static int	rem_hotplug_fru_device(void);
270static int	is_added_device(char *, char *);
271static int	is_removed_device(char *, char *);
272static int	add_power_supply(int);
273static int	remove_power_supply(int);
274static int	add_cpu_module(int);
275static int	remove_cpu_module(int);
276
277/*
278 * This function is executed as part of .init when the plugin is
279 * dlopen()ed
280 */
281static void
282picl_frutree_register()
283{
284	(void) picld_plugin_register(&my_reg_info);
285}
286
287/*
288 * This function is the init entry point of the plugin.
289 * It initializes the /frutree tree
290 */
291static void
292picl_frutree_init()
293{
294	int		err;
295
296	err = add_all_nodes();
297	if (err != PICL_SUCCESS) {
298		(void) remove_all_nodes(frutreeh);
299		return;
300	}
301
302	/* Register the event handler routine */
303	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
304	    picl_frutree_evhandler, NULL);
305	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
306	    picl_frutree_evhandler, NULL);
307}
308
309/*
310 * This function is the fini entry point of the plugin
311 */
312static void
313picl_frutree_fini(void)
314{
315	/* Unregister the event handler routine */
316	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
317	    picl_frutree_evhandler, NULL);
318	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
319	    picl_frutree_evhandler, NULL);
320
321	(void) remove_all_nodes(frutreeh);
322}
323
324/*
325 * This function is the event handler of this plug-in.
326 *
327 * It processes the following events:
328 *
329 *	PICLEVENT_SYSEVENT_DEVICE_ADDED
330 *	PICLEVENT_SYSEVENT_DEVICE_REMOVED
331 */
332/* ARGSUSED */
333static void
334picl_frutree_evhandler(const char *ename, const void *earg, size_t size,
335    void *cookie)
336{
337	if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) {
338		/* Check for and add any hotplugged device(s) */
339		(void) add_hotplug_fru_device();
340
341	} else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) {
342		/* Check for and remove any hotplugged device(s) */
343		(void) rem_hotplug_fru_device();
344	}
345}
346
347/* Initializes the FRU nodes for the IO board */
348static int
349do_ioboard_init(picl_nodehdl_t rooth)
350{
351	picl_nodehdl_t		iobrdh;
352	picl_nodehdl_t		tmph;
353	int			err;
354
355	/* Create the node for the IO board (if it exists) */
356	if (ptree_get_node_by_path(platform_frupath[IOBRD], &tmph) ==
357	    PICL_SUCCESS) {
358		err = ptree_create_node("io-board", "fru", &iobrdh);
359		if (err != PICL_SUCCESS)
360			return (err);
361
362		err = add_ref_prop(iobrdh, tmph, SEEPROM_SOURCE);
363		if (err != PICL_SUCCESS)
364			return (err);
365
366		err = add_void_fda_prop(iobrdh);
367		if (err != PICL_SUCCESS)
368			return (err);
369
370		err = ptree_add_node(rooth, iobrdh);
371		if (err != PICL_SUCCESS)
372			return (err);
373
374		err = add_ref_prop(tmph, iobrdh, FRU_PARENT);
375		if (err != PICL_SUCCESS)
376			return (err);
377	}
378	return (PICL_SUCCESS);
379}
380
381/* Initializes the FRU node for the RSC card */
382static int
383do_rscboard_init(picl_nodehdl_t rooth)
384{
385	picl_nodehdl_t		rscbrdh;
386	picl_nodehdl_t		tmph;
387	int			err;
388
389	/* Create the node for the RSC board (if it exists) */
390	if (ptree_get_node_by_path(platform_frupath[RSC], &tmph) ==
391	    PICL_SUCCESS) {
392		err = ptree_create_node("rsc-board", "fru", &rscbrdh);
393		if (err != PICL_SUCCESS)
394			return (err);
395
396		err = add_ref_prop(rscbrdh, tmph, SEEPROM_SOURCE);
397		if (err != PICL_SUCCESS)
398			return (err);
399
400		err = add_void_fda_prop(rscbrdh);
401		if (err != PICL_SUCCESS)
402			return (err);
403
404		err = ptree_add_node(rooth, rscbrdh);
405		if (err != PICL_SUCCESS)
406			return (err);
407
408		err = add_ref_prop(tmph, rscbrdh, FRU_PARENT);
409		if (err != PICL_SUCCESS)
410			return (err);
411	}
412	return (PICL_SUCCESS);
413}
414
415/* Initializes the FRU nodes for the FCAL backplanes and GBIC card */
416static int
417do_fcal_init(picl_nodehdl_t rooth)
418{
419	picl_nodehdl_t		fcalsloth;
420	picl_nodehdl_t		fcalmodh;
421	picl_nodehdl_t		fcalgbich;
422	picl_nodehdl_t		tmph;
423	int			i, err, slotnum;
424
425	for (i = FCAL0; i <= FCAL1; i++) {
426		/* Create the node for the FCAL backplane slot */
427		err = ptree_create_node("fcal-backplane-slot",
428		    "location", &fcalsloth);
429		if (err != PICL_SUCCESS)
430			return (err);
431
432		slotnum = i - FCAL0;
433		err = add_slot_prop(fcalsloth, slotnum);
434		if (err != PICL_SUCCESS)
435			return (err);
436
437		err = add_label_prop(fcalsloth, location_label[i]);
438		if (err != PICL_SUCCESS)
439			return (err);
440
441		err = ptree_add_node(rooth, fcalsloth);
442		if (err != PICL_SUCCESS)
443			return (err);
444
445		/* If the FCAL backplane exists, create a node for it */
446		if (ptree_get_node_by_path(platform_frupath[i], &tmph) ==
447		    PICL_SUCCESS) {
448			err = ptree_create_node("fcal-backplane", "fru",
449			    &fcalmodh);
450			if (err != PICL_SUCCESS)
451				return (err);
452
453			err = add_ref_prop(fcalmodh, tmph, SEEPROM_SOURCE);
454			if (err != PICL_SUCCESS)
455				return (err);
456
457			err = add_void_fda_prop(fcalmodh);
458			if (err != PICL_SUCCESS)
459				return (err);
460
461			err = ptree_add_node(fcalsloth, fcalmodh);
462			if (err != PICL_SUCCESS)
463				return (err);
464
465			err = add_ref_prop(tmph, fcalmodh, FRU_PARENT);
466			if (err != PICL_SUCCESS)
467				return (err);
468		}
469	}
470
471	/* If the FCAL GBIC board exists, create a node for it */
472	if (ptree_get_node_by_path(platform_frupath[FCALGBIC], &tmph) ==
473	    PICL_SUCCESS) {
474		err = ptree_create_node("fcal-gbic-board", "fru",
475		    &fcalgbich);
476		if (err != PICL_SUCCESS)
477			return (err);
478
479		err = add_ref_prop(fcalgbich, tmph, SEEPROM_SOURCE);
480		if (err != PICL_SUCCESS)
481			return (err);
482
483		err = add_void_fda_prop(fcalgbich);
484		if (err != PICL_SUCCESS)
485			return (err);
486
487		err = ptree_add_node(rooth, fcalgbich);
488		if (err != PICL_SUCCESS)
489			return (err);
490
491		err = add_ref_prop(tmph, fcalgbich, FRU_PARENT);
492		if (err != PICL_SUCCESS)
493			return (err);
494	}
495	return (PICL_SUCCESS);
496}
497
498/* Initializes the FRU nodes for the PDB and the power supplies */
499static int
500do_power_supplies_init(picl_nodehdl_t rooth)
501{
502	picl_nodehdl_t		powerbrdh;
503	picl_nodehdl_t		powersloth;
504	picl_nodehdl_t		powermodh;
505	picl_nodehdl_t		tmph;
506	int			i, err, slotnum;
507
508	/* Create the node for the PDB (if it exists) */
509	if (ptree_get_node_by_path(platform_frupath[PDB], &tmph) ==
510	    PICL_SUCCESS) {
511		err = ptree_create_node("power-dist-board", "fru", &powerbrdh);
512		if (err != PICL_SUCCESS)
513			return (err);
514
515		err = add_ref_prop(powerbrdh, tmph, SEEPROM_SOURCE);
516		if (err != PICL_SUCCESS)
517			return (err);
518
519		err = add_void_fda_prop(powerbrdh);
520		if (err != PICL_SUCCESS)
521			return (err);
522
523		err = ptree_add_node(rooth, powerbrdh);
524		if (err != PICL_SUCCESS)
525			return (err);
526
527		err = add_ref_prop(tmph, powerbrdh, FRU_PARENT);
528		if (err != PICL_SUCCESS)
529			return (err);
530
531		for (i = PS0; i <= PS2; i++) {
532			/* Create the node for the power supply slot */
533			err = ptree_create_node("power-supply-slot",
534			    "location", &powersloth);
535			if (err != PICL_SUCCESS)
536				return (err);
537
538			slotnum = i - PS0;
539			err = add_slot_prop(powersloth, slotnum);
540			if (err != PICL_SUCCESS)
541				return (err);
542
543			err = add_label_prop(powersloth, location_label[i]);
544			if (err != PICL_SUCCESS)
545				return (err);
546
547			err = ptree_add_node(powerbrdh, powersloth);
548			if (err != PICL_SUCCESS)
549				return (err);
550
551			/* If the PS exists, create a node for it */
552			if (ptree_get_node_by_path(platform_frupath[i],
553			    &tmph) == PICL_SUCCESS) {
554				err = ptree_create_node("power-supply",
555				    "fru", &powermodh);
556				if (err != PICL_SUCCESS)
557					return (err);
558
559				err = add_ref_prop(powermodh, tmph,
560				    SEEPROM_SOURCE);
561				if (err != PICL_SUCCESS)
562					return (err);
563
564				err = add_void_fda_prop(powermodh);
565				if (err != PICL_SUCCESS)
566					return (err);
567
568				err = ptree_add_node(powersloth, powermodh);
569				if (err != PICL_SUCCESS)
570					return (err);
571
572				err = add_ref_prop(tmph, powermodh, FRU_PARENT);
573				if (err != PICL_SUCCESS)
574					return (err);
575			}
576		}
577	}
578	return (PICL_SUCCESS);
579}
580
581/* Initializes the FRU nodes for the motherboard and CPU Memory modules */
582static int
583do_motherboard_init(picl_nodehdl_t rooth)
584{
585	picl_nodehdl_t		sysboardh;
586	picl_nodehdl_t		cpumemsloth;
587	picl_nodehdl_t		cpumemmodh;
588	picl_nodehdl_t		tmph;
589	int			i, err, slotnum;
590
591	/* Create the node for the system board (if it exists) */
592	if (ptree_get_node_by_path(platform_frupath[SYSBRD], &tmph) ==
593	    PICL_SUCCESS) {
594		err = ptree_create_node("system-board", "fru",
595		    &sysboardh);
596		if (err != PICL_SUCCESS)
597			return (err);
598
599		err = add_ref_prop(sysboardh, tmph, SEEPROM_SOURCE);
600		if (err != PICL_SUCCESS)
601			return (err);
602
603		err = add_void_fda_prop(sysboardh);
604		if (err != PICL_SUCCESS)
605			return (err);
606
607		err = ptree_add_node(rooth, sysboardh);
608		if (err != PICL_SUCCESS)
609			return (err);
610
611		err = add_ref_prop(tmph, sysboardh, FRU_PARENT);
612		if (err != PICL_SUCCESS)
613			return (err);
614
615		for (i = CPUMOD0; i <= CPUMOD3; i++) {
616			/* Create the node for the CPU Memory slot */
617			err = ptree_create_node("cpu-mem-slot", "location",
618			    &cpumemsloth);
619			if (err != PICL_SUCCESS)
620				return (err);
621
622			slotnum = i - CPUMOD0;
623			err = add_slot_prop(cpumemsloth, slotnum);
624			if (err != PICL_SUCCESS)
625				return (err);
626
627			err = add_label_prop(cpumemsloth, location_label[i]);
628			if (err != PICL_SUCCESS)
629				return (err);
630
631			err = ptree_add_node(sysboardh, cpumemsloth);
632			if (err != PICL_SUCCESS)
633				return (err);
634
635			/* If CPU Mem module exists, create a node for it */
636			if (ptree_get_node_by_path(platform_frupath[i],
637			    &tmph) == PICL_SUCCESS) {
638				err = ptree_create_node("cpu-mem-module",
639				    "fru", &cpumemmodh);
640				if (err != PICL_SUCCESS)
641					return (err);
642
643				err = add_ref_prop(cpumemmodh, tmph,
644				    SEEPROM_SOURCE);
645				if (err != PICL_SUCCESS)
646					return (err);
647
648				err = add_void_fda_prop(cpumemmodh);
649				if (err != PICL_SUCCESS)
650					return (err);
651
652				err = ptree_add_node(cpumemsloth, cpumemmodh);
653				if (err != PICL_SUCCESS)
654					return (err);
655
656				err = add_ref_prop(tmph, cpumemmodh,
657				    FRU_PARENT);
658				if (err != PICL_SUCCESS)
659					return (err);
660
661				err = do_cpu_module_init(cpumemmodh, slotnum);
662				if (err != PICL_SUCCESS)
663					return (err);
664			}
665		}
666	}
667	return (PICL_SUCCESS);
668}
669
670/* Creates the FRU nodes for the CPU Module and associated DIMMs */
671static int
672do_cpu_module_init(picl_nodehdl_t rooth, int slot)
673{
674	picl_nodehdl_t		cpumodh;
675	int			i, c, err;
676
677	for (i = 0; i <= 1; i++) {
678		err = ptree_create_node("cpu-module", "location",
679		    &cpumodh);
680		if (err != PICL_SUCCESS)
681			return (err);
682
683		err = add_slot_prop(cpumodh, i);
684		if (err != PICL_SUCCESS)
685			return (err);
686
687		c = CPU0_DIMM0 + DIMMS_PER_SLOT + i;
688
689		err = add_label_prop(cpumodh, location_label[c]);
690		if (err != PICL_SUCCESS)
691			return (err);
692
693		err = ptree_add_node(rooth, cpumodh);
694		if (err != PICL_SUCCESS)
695			return (err);
696
697		/* Create the nodes for the memory (if they exist) */
698		err = do_dimms_init(cpumodh, slot, i);
699		if (err != PICL_SUCCESS)
700			return (err);
701	}
702	return (PICL_SUCCESS);
703}
704
705/* Creates the FRU nodes for the DIMMs on a particular CPU Module */
706static int
707do_dimms_init(picl_nodehdl_t rooth, int slot, int module)
708{
709	picl_nodehdl_t		dimmsloth;
710	picl_nodehdl_t		dimmmodh;
711	picl_nodehdl_t		tmph;
712	int			i, c, l, err;
713
714	for (i = 0; i < DIMMS_PER_MOD; i++) {
715		/* Create the node for the memory slot */
716		err = ptree_create_node("dimm-slot", "location",
717		    &dimmsloth);
718		if (err != PICL_SUCCESS)
719			return (err);
720
721		err = add_slot_prop(dimmsloth, i);
722		if (err != PICL_SUCCESS)
723			return (err);
724
725		c = ((slot * DIMMS_PER_SLOT) +
726		    (module * DIMMS_PER_MOD) + i) + CPU0_DIMM0;
727
728		l = c - (DIMMS_PER_SLOT * slot);
729
730		err = add_label_prop(dimmsloth, location_label[l]);
731		if (err != PICL_SUCCESS)
732			return (err);
733
734		err = ptree_add_node(rooth, dimmsloth);
735		if (err != PICL_SUCCESS)
736			return (err);
737
738		/* If the memory module exists, create a node for it */
739		if (ptree_get_node_by_path(platform_frupath[c], &tmph) ==
740		    PICL_SUCCESS) {
741			err = ptree_create_node("dimm-module", "fru",
742			    &dimmmodh);
743			if (err != PICL_SUCCESS)
744				return (err);
745
746			err = add_ref_prop(dimmmodh, tmph, SEEPROM_SOURCE);
747			if (err != PICL_SUCCESS)
748				return (err);
749
750			err = add_void_fda_prop(dimmmodh);
751			if (err != PICL_SUCCESS)
752				return (err);
753
754			err = ptree_add_node(dimmsloth, dimmmodh);
755			if (err != PICL_SUCCESS)
756				return (err);
757
758			err = add_ref_prop(tmph, dimmmodh, FRU_PARENT);
759			if (err != PICL_SUCCESS)
760				return (err);
761		}
762	}
763	return (PICL_SUCCESS);
764}
765
766/* Creates a "reference" property between two PICL nodes */
767static int
768add_ref_prop(picl_nodehdl_t nodeh, picl_nodehdl_t tmph, char *str)
769{
770	picl_prophdl_t		proph;
771	ptree_propinfo_t	propinfo;
772	int			err;
773
774	if (str == NULL)
775		return (PICL_FAILURE);
776
777	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
778	    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t),
779	    str, NULL, NULL);
780	if (err != PICL_SUCCESS)
781		return (err);
782
783	err = ptree_create_and_add_prop(nodeh, &propinfo, &tmph, &proph);
784	if (err != PICL_SUCCESS)
785		return (err);
786
787	return (PICL_SUCCESS);
788}
789
790/* Creates a "slot" property for a given PICL node */
791static int
792add_slot_prop(picl_nodehdl_t nodeh, int slotnum)
793{
794	picl_prophdl_t		proph;
795	ptree_propinfo_t	propinfo;
796	int			err;
797
798	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
799	    PICL_PTYPE_INT, PICL_READ, 4, "Slot", NULL, NULL);
800	if (err != PICL_SUCCESS)
801		return (err);
802
803	err = ptree_create_and_add_prop(nodeh, &propinfo, &slotnum, &proph);
804	if (err != PICL_SUCCESS)
805		return (err);
806
807	return (PICL_SUCCESS);
808}
809
810/* Creates a "Label" property for a given PICL node */
811static int
812add_label_prop(picl_nodehdl_t nodeh, char *label)
813{
814	picl_prophdl_t		proph;
815	ptree_propinfo_t	propinfo;
816	int			err;
817
818	if (label == NULL)
819		return (PICL_FAILURE);
820
821	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
822	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(label)+1, "Label",
823	    NULL, NULL);
824	if (err != PICL_SUCCESS)
825		return (err);
826
827	err = ptree_create_and_add_prop(nodeh, &propinfo, label, &proph);
828	if (err != PICL_SUCCESS)
829		return (err);
830
831	return (PICL_SUCCESS);
832}
833
834/* Creates a "FRUDataAvailable" void property for the given PICL node */
835static int
836add_void_fda_prop(picl_nodehdl_t nodeh)
837{
838	picl_prophdl_t		proph;
839	ptree_propinfo_t	propinfo;
840	int			err;
841
842	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
843	    PICL_PTYPE_VOID, PICL_READ, 0, "FRUDataAvailable", NULL, NULL);
844	if (err != PICL_SUCCESS)
845		return (err);
846
847	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
848	if (err != PICL_SUCCESS)
849		return (err);
850
851	return (PICL_SUCCESS);
852}
853
854/* Creates a "ViewPoints" property -- used for chassis */
855static int
856add_viewpoints_prop(picl_nodehdl_t nodeh, char *string)
857{
858	picl_prophdl_t		proph;
859	ptree_propinfo_t	propinfo;
860	int			err;
861
862	if (string == NULL)
863		return (PICL_FAILURE);
864
865	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
866	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(string)+1, "ViewPoints",
867	    NULL, NULL);
868	if (err != PICL_SUCCESS)
869		return (err);
870
871	err = ptree_create_and_add_prop(nodeh, &propinfo, string, &proph);
872	if (err != PICL_SUCCESS)
873		return (err);
874
875	return (PICL_SUCCESS);
876}
877
878/* Creates and adds all of the frutree nodes */
879static int
880add_all_nodes()
881{
882	picl_nodehdl_t	rooth;
883	picl_nodehdl_t	chassish;
884	int		err;
885
886	/* Get the root node of the PICL tree */
887	err = ptree_get_root(&rooth);
888	if (err != PICL_SUCCESS) {
889		return (err);
890	}
891
892	/* Create and add the root node of the FRU subtree */
893	err = ptree_create_and_add_node(rooth, "frutree", "picl", &frutreeh);
894	if (err != PICL_SUCCESS) {
895		syslog(LOG_ERR, CREATE_FRUTREE_FAIL);
896		return (err);
897	}
898
899	/* Create and add the chassis node */
900	err = ptree_create_and_add_node(frutreeh, "chassis", "fru", &chassish);
901	if (err != PICL_SUCCESS) {
902		syslog(LOG_ERR, CREATE_CHASSIS_FAIL);
903		return (err);
904	}
905
906	/* Add ViewPoints prop to chassis node */
907	err = add_viewpoints_prop(chassish, CHASSIS_VIEWPOINTS);
908	if (err != PICL_SUCCESS)
909		return (err);
910
911	/* Initialize the FRU nodes for the IO board */
912	err = do_ioboard_init(chassish);
913	if (err != PICL_SUCCESS) {
914		syslog(LOG_ERR, IOBRD_INIT_FAIL);
915		return (err);
916	}
917
918	/* Initialize the FRU node for the RSC card */
919	err = do_rscboard_init(chassish);
920	if (err != PICL_SUCCESS) {
921		syslog(LOG_ERR, RSCBRD_INIT_FAIL);
922		return (err);
923	}
924
925	/* Initialize the FRU nodes for the FCAL backplanes and GBIC board */
926	err = do_fcal_init(chassish);
927	if (err != PICL_SUCCESS) {
928		syslog(LOG_ERR, FCAL_INIT_FAIL);
929		return (err);
930	}
931
932	/* Initialize the FRU nodes for the PDB and the power supplies */
933	err = do_power_supplies_init(chassish);
934	if (err != PICL_SUCCESS) {
935		syslog(LOG_ERR, PS_INIT_FAIL);
936		return (err);
937	}
938
939	/* Initialize the FRU nodes for the CPU Memory modules */
940	err = do_motherboard_init(chassish);
941	if (err != PICL_SUCCESS) {
942		syslog(LOG_ERR, SYSBOARD_INIT_FAIL);
943		return (err);
944	}
945
946	return (PICL_SUCCESS);
947}
948
949/* Deletes and destroys all PICL nodes for which rooth is a ancestor */
950static int
951remove_all_nodes(picl_nodehdl_t rooth)
952{
953	picl_nodehdl_t		chdh;
954	int			err, done = 0;
955
956	while (!done) {
957		err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
958		    sizeof (picl_nodehdl_t));
959		if (err != PICL_PROPNOTFOUND) {
960			(void) remove_all_nodes(chdh);
961		} else {
962			err = ptree_delete_node(rooth);
963			if (err != PICL_SUCCESS) {
964				return (err);
965			} else {
966				(void) ptree_destroy_node(rooth);
967			}
968			done = 1;
969		}
970	}
971	return (PICL_SUCCESS);
972}
973
974/* Searches the list of hotpluggable FRUs, adds the appropriate node(s) */
975static int
976add_hotplug_fru_device()
977{
978	int		i, err, slotnum;
979
980	/* Check for hotplugged power supplies */
981	for (i = PS0; i <= PS2; i++) {
982		/* Compare the /platform tree to the frutree */
983		slotnum = i - PS0;
984		err = is_added_device(platform_frupath[i],
985		    frutree_power_supply[slotnum]);
986		if (err != PICL_SUCCESS)
987			continue;
988
989		/* If they are different, then add a power supply */
990		err = add_power_supply(slotnum);
991		if (err != PICL_SUCCESS)
992			continue;
993	}
994
995	/* Check for hotplugged CPU Memory modules */
996	for (i = CPUMOD0; i <= CPUMOD3; i++) {
997		/* Compare the /platform tree to the frutree */
998		slotnum = i - CPUMOD0;
999		err = is_added_device(platform_frupath[i],
1000		    frutree_cpu_module[slotnum]);
1001		if (err != PICL_SUCCESS)
1002			continue;
1003
1004		/* If they are different, then add a CPU Mem module */
1005		err = add_cpu_module(slotnum);
1006		if (err != PICL_SUCCESS)
1007			continue;
1008	}
1009	return (PICL_SUCCESS);
1010}
1011
1012/* Searches the list of hotpluggable FRUs, removes the appropriate node(s) */
1013static int
1014rem_hotplug_fru_device()
1015{
1016	int		i, err, slotnum;
1017
1018	/* Check for hotplugged power supplies */
1019	for (i = PS0; i <= PS2; i++) {
1020		/* Compare the /platform tree to the frutree */
1021		slotnum = i - PS0;
1022		err = is_removed_device(platform_frupath[i],
1023		    frutree_power_supply[slotnum]);
1024		if (err != PICL_SUCCESS)
1025			continue;
1026
1027		/* If they are different, then remove a power supply */
1028		err = remove_power_supply(slotnum);
1029		if (err != PICL_SUCCESS)
1030			continue;
1031	}
1032
1033	/* Check for hotplugged CPU Memory modules */
1034	for (i = CPUMOD0; i <= CPUMOD3; i++) {
1035		/* Compare the /platform tree to the frutree */
1036		slotnum = i - CPUMOD0;
1037		err = is_removed_device(platform_frupath[i],
1038		    frutree_cpu_module[slotnum]);
1039		if (err != PICL_SUCCESS)
1040			continue;
1041
1042		/* If they are different, then remove a CPU Mem module */
1043		err = remove_cpu_module(slotnum);
1044		if (err != PICL_SUCCESS)
1045			continue;
1046	}
1047	return (PICL_SUCCESS);
1048}
1049
1050/*
1051 * Compare the /platform tree to the /frutree to determine if a
1052 * new device has been added
1053 */
1054static int
1055is_added_device(char *plat, char *fru)
1056{
1057	int		err;
1058	picl_nodehdl_t	plath, frusloth, frumodh;
1059
1060	/* Check for node in the /platform tree */
1061	err = ptree_get_node_by_path(plat, &plath);
1062	if (err != PICL_SUCCESS)
1063		return (err);
1064
1065	/*
1066	 * The node is in /platform, so find the corresponding slot in
1067	 * the frutree
1068	 */
1069	err = ptree_get_node_by_path(fru, &frusloth);
1070	if (err != PICL_SUCCESS)
1071		return (err);
1072
1073	/*
1074	 * If the slot in the frutree has a child, then return
1075	 * PICL_FAILURE.  This means that the /platform tree and
1076	 * the frutree are consistent and no action is necessary.
1077	 * Otherwise return PICL_SUCCESS to indicate that a node needs
1078	 * to be added to the frutree
1079	 */
1080	err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD,
1081	    &frumodh, sizeof (picl_nodehdl_t));
1082	if (err == PICL_SUCCESS)
1083		return (PICL_FAILURE);
1084
1085	return (PICL_SUCCESS);
1086}
1087
1088/*
1089 * Compare the /platform tree to the /frutree to determine if a
1090 * device has been removed
1091 */
1092static int
1093is_removed_device(char *plat, char *fru)
1094{
1095	int		err;
1096	picl_nodehdl_t	plath, frusloth, frumodh;
1097
1098
1099	/* Check for node in /platform tree */
1100	err = ptree_get_node_by_path(plat, &plath);
1101	if (err == PICL_SUCCESS)
1102		return (PICL_FAILURE);
1103
1104	/*
1105	 * The node is not in /platform, so find the corresponding slot in
1106	 * the frutree
1107	 */
1108	err = ptree_get_node_by_path(fru, &frusloth);
1109	if (err != PICL_SUCCESS)
1110		return (err);
1111
1112	/*
1113	 * If the slot in the frutree does not have a child, then return
1114	 * PICL_FAILURE.  This means that the /platform tree and
1115	 * the frutree are consistent and no action is necessary.
1116	 * Otherwise return PICL_SUCCESS to indicate that the needs
1117	 * to be removed from the frutree
1118	 */
1119	err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD,
1120	    &frumodh, sizeof (picl_nodehdl_t));
1121	if (err != PICL_SUCCESS)
1122		return (err);
1123
1124	return (PICL_SUCCESS);
1125}
1126
1127static int
1128remove_picl_node(picl_nodehdl_t nodeh)
1129{
1130	int err;
1131	err = ptree_delete_node(nodeh);
1132	if (err != PICL_SUCCESS)
1133		return (err);
1134	(void) ptree_destroy_node(nodeh);
1135	return (PICL_SUCCESS);
1136}
1137
1138/* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */
1139/*ARGSUSED2*/
1140static void
1141frudr_completion_handler(char *ename, void *earg, size_t size)
1142{
1143	picl_nodehdl_t	fruh;
1144
1145	if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
1146		/*
1147		 * now frudata has been notified that the node is to be
1148		 * removed, we can actually remove it
1149		 */
1150		fruh = 0;
1151		(void) nvlist_lookup_uint64(earg,
1152		    PICLEVENTARG_FRUHANDLE, &fruh);
1153		if (fruh != 0) {
1154			(void) remove_picl_node(fruh);
1155		}
1156	}
1157	nvlist_free(earg);
1158	free(earg);
1159	free(ename);
1160}
1161
1162/*
1163 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
1164 */
1165static void
1166post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
1167{
1168	nvlist_t	*nvl;
1169	char		*ev_name;
1170
1171	ev_name = strdup(ename);
1172	if (ev_name == NULL)
1173		return;
1174	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) {
1175		free(ev_name);
1176		return;
1177	}
1178	if (parenth != 0L &&
1179	    nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
1180		free(ev_name);
1181		nvlist_free(nvl);
1182		return;
1183	}
1184	if (fruh != 0L &&
1185	    nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
1186		free(ev_name);
1187		nvlist_free(nvl);
1188		return;
1189	}
1190	if (ptree_post_event(ev_name, nvl, sizeof (nvl),
1191	    frudr_completion_handler) != 0) {
1192		free(ev_name);
1193		nvlist_free(nvl);
1194	}
1195}
1196
1197/* Hotplug routine used to add a new power supply */
1198static int
1199add_power_supply(int slotnum)
1200{
1201	picl_nodehdl_t		powersloth;
1202	picl_nodehdl_t		powermodh;
1203	picl_nodehdl_t		tmph;
1204	int			i, err;
1205
1206	/* Find the node for the given power supply slot */
1207	if (ptree_get_node_by_path(frutree_power_supply[slotnum],
1208	    &powersloth) == PICL_SUCCESS) {
1209
1210		i = slotnum + PS0;
1211
1212		/* Make sure it's in /platform and create the frutree node */
1213		if (ptree_get_node_by_path(platform_frupath[i], &tmph) ==
1214		    PICL_SUCCESS) {
1215			err = ptree_create_node("power-supply", "fru",
1216			    &powermodh);
1217			if (err != PICL_SUCCESS)
1218				return (err);
1219
1220			err = add_ref_prop(powermodh, tmph, SEEPROM_SOURCE);
1221			if (err != PICL_SUCCESS)
1222				return (err);
1223
1224			err = add_void_fda_prop(powermodh);
1225			if (err != PICL_SUCCESS)
1226				return (err);
1227
1228			err = ptree_add_node(powersloth, powermodh);
1229			if (err != PICL_SUCCESS)
1230				return (err);
1231
1232			err = add_ref_prop(tmph, powermodh, FRU_PARENT);
1233			if (err != PICL_SUCCESS)
1234				return (err);
1235
1236			/* Post picl-fru-added event */
1237			post_frudr_event(PICL_FRU_ADDED, 0, powermodh);
1238		}
1239	}
1240	return (PICL_SUCCESS);
1241}
1242
1243/* Hotplug routine used to remove an existing power supply */
1244static int
1245remove_power_supply(int slotnum)
1246{
1247	picl_nodehdl_t		powersloth;
1248	picl_nodehdl_t		powermodh;
1249	int			err;
1250
1251	/* Find the node for the given power supply slot */
1252	if (ptree_get_node_by_path(frutree_power_supply[slotnum],
1253	    &powersloth) == PICL_SUCCESS) {
1254		/* Make sure it's got a child, then delete it */
1255		err = ptree_get_propval_by_name(powersloth, PICL_PROP_CHILD,
1256		    &powermodh, sizeof (picl_nodehdl_t));
1257		if (err != PICL_SUCCESS) {
1258			return (err);
1259		}
1260
1261		err = ptree_delete_node(powermodh);
1262		if (err != PICL_SUCCESS) {
1263			return (err);
1264		} else {
1265			(void) ptree_destroy_node(powermodh);
1266		}
1267
1268		/* Post picl-fru-removed event */
1269		post_frudr_event(PICL_FRU_REMOVED, 0, powermodh);
1270
1271	}
1272	return (PICL_SUCCESS);
1273}
1274
1275/* Hotplug routine used to add a new CPU Mem Module (with associated DIMMs) */
1276static int
1277add_cpu_module(int slotnum)
1278{
1279	picl_nodehdl_t		cpumemsloth;
1280	picl_nodehdl_t		cpumemmodh;
1281	picl_nodehdl_t		tmph;
1282	int			i, err;
1283
1284	/* Find the node for the given CPU Memory module slot */
1285	if (ptree_get_node_by_path(frutree_cpu_module[slotnum],
1286	    &cpumemsloth) == PICL_SUCCESS) {
1287
1288		i = slotnum + CPUMOD0;
1289
1290		/* Make sure it's in /platform and create the frutree nodes */
1291		if (ptree_get_node_by_path(platform_frupath[i], &tmph) ==
1292		    PICL_SUCCESS) {
1293			err = ptree_create_node("cpu-mem-module", "fru",
1294			    &cpumemmodh);
1295			if (err != PICL_SUCCESS)
1296				return (err);
1297
1298			err = add_ref_prop(cpumemmodh, tmph, SEEPROM_SOURCE);
1299			if (err != PICL_SUCCESS)
1300				return (err);
1301
1302			err = add_void_fda_prop(cpumemmodh);
1303			if (err != PICL_SUCCESS)
1304				return (err);
1305
1306			err = ptree_add_node(cpumemsloth, cpumemmodh);
1307			if (err != PICL_SUCCESS)
1308				return (err);
1309
1310			err = add_ref_prop(tmph, cpumemmodh, FRU_PARENT);
1311			if (err != PICL_SUCCESS)
1312				return (err);
1313		}
1314
1315		err = do_cpu_module_init(cpumemmodh, slotnum);
1316		if (err != PICL_SUCCESS)
1317			return (err);
1318	}
1319	return (PICL_SUCCESS);
1320}
1321
1322/* Hotplug routine used to remove an existing CPU Mem Module */
1323static int
1324remove_cpu_module(int slotnum)
1325{
1326	picl_nodehdl_t		cpumemsloth;
1327	picl_nodehdl_t		cpumemmodh;
1328	int			err;
1329
1330	/* Find the node for the given CPU Memory module slot */
1331	if (ptree_get_node_by_path(frutree_cpu_module[slotnum],
1332	    &cpumemsloth) == PICL_SUCCESS) {
1333		/* Make sure it's got a child, then delete it */
1334		err = ptree_get_propval_by_name(cpumemsloth, PICL_PROP_CHILD,
1335		    &cpumemmodh, sizeof (picl_nodehdl_t));
1336		if (err != PICL_SUCCESS) {
1337			return (err);
1338		}
1339
1340		err = remove_all_nodes(cpumemmodh);
1341		if (err != PICL_SUCCESS) {
1342			return (err);
1343		}
1344	}
1345	return (PICL_SUCCESS);
1346}
1347