xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/daktari/frutree/piclfrutree.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
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  */
44 static void	picl_frutree_register(void);
45 static void	picl_frutree_init(void);
46 static void	picl_frutree_fini(void);
47 static 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  */
100 static 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  */
111 static 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  */
195 static 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  */
233 static 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  */
242 static 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" */
250 static picl_nodehdl_t	frutreeh;
251 
252 static int	do_ioboard_init(picl_nodehdl_t);
253 static int	do_rscboard_init(picl_nodehdl_t);
254 static int	do_fcal_init(picl_nodehdl_t);
255 static int	do_power_supplies_init(picl_nodehdl_t);
256 static int	do_motherboard_init(picl_nodehdl_t);
257 static int	do_cpu_module_init(picl_nodehdl_t, int);
258 static int	do_dimms_init(picl_nodehdl_t, int, int);
259 
260 static int	add_ref_prop(picl_nodehdl_t, picl_nodehdl_t, char *);
261 static int	add_slot_prop(picl_nodehdl_t, int);
262 static int	add_label_prop(picl_nodehdl_t, char *);
263 static int	add_void_fda_prop(picl_nodehdl_t);
264 static int	add_viewpoints_prop(picl_nodehdl_t, char *);
265 static int	add_all_nodes();
266 static int	remove_all_nodes(picl_nodehdl_t);
267 
268 static int	add_hotplug_fru_device(void);
269 static int	rem_hotplug_fru_device(void);
270 static int	is_added_device(char *, char *);
271 static int	is_removed_device(char *, char *);
272 static int	add_power_supply(int);
273 static int	remove_power_supply(int);
274 static int	add_cpu_module(int);
275 static int	remove_cpu_module(int);
276 
277 /*
278  * This function is executed as part of .init when the plugin is
279  * dlopen()ed
280  */
281 static void
282 picl_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  */
291 static void
292 picl_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  */
312 static void
313 picl_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 */
333 static void
334 picl_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 */
348 static int
349 do_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 */
382 static int
383 do_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 */
416 static int
417 do_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 */
499 static int
500 do_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 */
582 static int
583 do_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 */
671 static int
672 do_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 */
706 static int
707 do_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 */
767 static int
768 add_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 */
791 static int
792 add_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 */
811 static int
812 add_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 */
835 static int
836 add_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 */
855 static int
856 add_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 */
879 static int
880 add_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 */
950 static int
951 remove_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) */
975 static int
976 add_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) */
1013 static int
1014 rem_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  */
1054 static int
1055 is_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  */
1092 static int
1093 is_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 
1127 static int
1128 remove_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*/
1140 static void
1141 frudr_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  */
1165 static void
1166 post_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 */
1198 static int
1199 add_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 */
1244 static int
1245 remove_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) */
1276 static int
1277 add_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 */
1323 static int
1324 remove_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