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