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