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