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