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
picl_frutree_register()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
picl_frutree_init()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
picl_frutree_fini(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
picl_frutree_evhandler(const char * ename,const void * earg,size_t size,void * cookie)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
do_ioboard_init(picl_nodehdl_t rooth)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
do_rscboard_init(picl_nodehdl_t rooth)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
do_fcal_init(picl_nodehdl_t rooth)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
do_power_supplies_init(picl_nodehdl_t rooth)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
do_centerplane_init(picl_nodehdl_t rooth)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
do_cpu_module_init(picl_nodehdl_t rooth,int slot)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
do_dimms_init(picl_nodehdl_t rooth,int slot,int module)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
add_ref_prop(picl_nodehdl_t nodeh,picl_nodehdl_t tmph,char * str)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
add_slot_prop(picl_nodehdl_t nodeh,int slotnum)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
add_label_prop(picl_nodehdl_t nodeh,char * label)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
add_void_fda_prop(picl_nodehdl_t nodeh)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
add_viewpoints_prop(picl_nodehdl_t nodeh,char * string)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
add_all_nodes()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
remove_all_nodes(picl_nodehdl_t rooth)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
add_hotplug_fru_device()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
rem_hotplug_fru_device()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
is_added_device(char * plat,char * fru)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
is_removed_device(char * plat,char * fru)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
remove_picl_node(picl_nodehdl_t nodeh)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
frudr_completion_handler(char * ename,void * earg,size_t size)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
post_frudr_event(char * ename,picl_nodehdl_t parenth,picl_nodehdl_t fruh)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
add_power_supply(int slotnum)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
remove_power_supply(int slotnum)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