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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This plugin-in creates the FRU Hierarchy for the
29 * SUNW,Netra-T12 platform and manages the environmental sensors
30 * on the platform.
31 */
32
33 #include <stdio.h>
34 #include <errno.h>
35 #include <syslog.h>
36 #include <strings.h>
37 #include <libintl.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <picl.h>
42 #include <picltree.h>
43 #include <sys/stat.h>
44 #include <libnvpair.h>
45 #include <sys/param.h>
46 #include <kstat.h>
47 #include <config_admin.h>
48 #include <sys/sbd_ioctl.h>
49 #include <sys/sgfrutree.h>
50 #include <sys/sgenv.h>
51 #include <sys/ioccom.h>
52 #include <sys/lw8.h>
53 #include <sys/sysevent/dr.h>
54 #include <pthread.h>
55 #include <sys/obpdefs.h>
56 #include "libdevice.h"
57 #include "picldefs.h"
58 #define NDEBUG
59 #include <assert.h>
60
61 /*
62 * Plugin registration entry points
63 */
64 static void piclfrutree_register(void);
65 static void piclfrutree_init(void);
66 static void piclfrutree_fini(void);
67 #pragma init(piclfrutree_register)
68
69 static picld_plugin_reg_t my_reg_info = {
70 PICLD_PLUGIN_VERSION_1,
71 PICLD_PLUGIN_CRITICAL,
72 "SUNW_Netra-T12_frutree",
73 piclfrutree_init,
74 piclfrutree_fini,
75 };
76
77 /*
78 * Log message texts
79 */
80 #define DEV_OPEN_FAIL gettext("piclfrutree_init: open of %s failed: %s")
81 #define ADD_NODES_FAIL gettext("piclfrutree_init: add_all_nodes failed: %d")
82 #define GET_ROOT_FAIL gettext("piclfrutree_init: ptree_get_root failed")
83 #define ADD_FRUTREE_FAIL gettext("piclfrutree_init: add frutree failed")
84 #define INVALID_PICL_CLASS gettext("add_subtree: invalid picl class 0x%x")
85 #define ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d")
86 #define GET_NEXT_BY_ROW_FAIL gettext("ptree_get_next_by_row %s failed: %d")
87 #define PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d")
88 #define GET_PROPVAL_FAIL gettext("ptree_get_propval failed: %d")
89 #define DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d")
90 #define DELETE_NODE_FAIL gettext("ptree_delete_node failed: %d")
91 #define ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d")
92 #define SGFRU_IOCTL_FAIL gettext("sgfru ioctl 0x%x handle 0x%llx failed: %s")
93 #define LED_IOCTL_FAIL gettext("led ioctl failed: %s")
94 #define MALLOC_FAIL gettext("piclfrutree: malloc failed")
95 #define NO_SC_FAIL gettext("piclfrutree: cannot find sc node")
96 #define NO_NODE_FAIL gettext("piclfrutree: cannot find node %s: %d")
97 #define KSTAT_FAIL gettext("piclfrutree: failure accessing kstats")
98 #define ADD_TBL_ENTRY_FAIL gettext("piclfrutree: cannot add entry to table")
99 #define PROP_LOOKUP_FAIL gettext("piclfrutree: cannot find %s property: %d")
100 #define EM_DI_INIT_FAIL gettext("frutree: di_init failed: %s")
101 #define EM_THREAD_CREATE_FAILED gettext("frutree: pthread_create failed: %s")
102 #define EM_MUTEX_FAIL gettext("frutree: pthread_mutex_lock returned: %s")
103 #define EM_POLL_FAIL gettext("frutree: poll() failed: %s")
104 #define DEVCTL_DEVICE_ACQUIRE_FAILED \
105 gettext("frutree: devctl_device_acquire() failed: %s")
106
107 /*
108 * PICL property values
109 */
110 #define PICL_PROPVAL_TRUE "true"
111 #define PICL_PROPVAL_SYSTEM "system"
112 #define PICL_PROPVAL_ON "ON"
113 #define PICL_PROPVAL_OFF "OFF"
114 #define PICL_PROPVAL_BLINKING "BLINKING"
115 #define PICL_PROPVAL_FLASHING "FLASHING"
116 #define PICL_PROPVAL_CHASSIS "chassis"
117 #define PICL_PROPVAL_AMBIENT "Ambient"
118 #define PICL_PROPVAL_DIE "Die"
119 #define PICL_PROPVAL_GREEN "green"
120 #define PICL_PROPVAL_AMBER "amber"
121 #define PICL_PROPVAL_OKAY "okay"
122 #define PICL_PROPVAL_FAILED "failed"
123 #define PICL_PROPVAL_WARNING "warning"
124 #define PICL_PROPVAL_DISABLED "disabled"
125 #define PICL_PROPVAL_UNKNOWN "unknown"
126 #define PICL_PROPVAL_SELF_REGULATING "self-regulating"
127 #define PICL_PROPVAL_PER_CENT "%"
128 #define PICL_PROP_BANK_STATUS "bank-status"
129
130 /*
131 * PICL property names
132 */
133 #define PICL_PROP_LOW_WARNING_THRESHOLD "LowWarningThreshold"
134
135 /*
136 * Local defines
137 */
138 #define MAX_LINE_SIZE 1024
139 #define MAX_TRIES 4
140 #define MAX_SPEED_UNIT_LEN 20
141 #define MAX_OPERATIONAL_STATUS_LEN 10
142 #define MAX_CONDITION_LEN 10
143 #define MAX_LABEL_LEN 256
144 #define MAX_STATE_LEN 10
145 #define MAX_STATE_SIZE 32
146 #define LED_PSEUDO_DEV "/devices/pseudo/lw8@0:lw8"
147 #define SC_DEV "/platform/ssm@0,0/pci@18,700000/bootbus-controller@4"
148 #define SC_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/bootbus-controller@3"
149 #define CPU_DEV "/platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0"
150 #define CPU_DEV2 "/platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0"
151 #define CPU_DEV3C0 "/platform/ssm@0,0/cmp@%x,0/cpu@0"
152 #define CPU_DEV3C1 "/platform/ssm@0,0/cmp@%x,0/cpu@1"
153 #define MEMORY_DEV "/platform/ssm@0,0/memory-controller@%x,400000"
154 #define IO_DEV "/platform/ssm@0,0/pci@%s"
155 #define DISK0_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@0,0"
156 #define DISK0_DEV "/platform" DISK0_BASE_PATH
157 #define DISK1_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@1,0"
158 #define DISK1_DEV "/platform" DISK1_BASE_PATH
159 #define DISK0_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@0,0"
160 #define DISK0_DEV_PCIX "/platform" DISK0_BASE_PATH_PCIX
161 #define DISK1_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@1,0"
162 #define DISK1_DEV_PCIX "/platform" DISK1_BASE_PATH_PCIX
163 #define TAPE_DEV "/platform/ssm@0,0/pci@18,600000/scsi@2/st@5,0"
164 #define TAPE_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/scsi@2/st@5,0"
165 #define DVD_DEV "/platform/ssm@0,0/pci@18,700000/ide@3/sd@0,0"
166 #define DVD_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/ide@2/sd@0,0"
167 #define CHASSIS_PATH "/frutree/chassis"
168 #define CHASSIS_LOC_PATH "/frutree/chassis/%s"
169 #define PROC_LOC_PATH "/frutree/chassis/SB%d/SB%d/P%d"
170 #define PROC_FRU_PATH "/frutree/chassis/SB%d/SB%d/P%d/P%d"
171 /*
172 * Calculate safari address to put in CPU_DEV/MEMORY_DEV string based on
173 * SBx/Py fru path name
174 */
175 #define SB_P_TO_SAFARI_ADDR(sbname, pname) \
176 ((pname[1] - '0') + (4 * (sbname[2] - '0')))
177 #define SAFARI_ADDR_TO_SB(value) (value >> 2)
178 #define SAFARI_ADDR_TO_P(value) (value & 3)
179 #define AP_ID_PREAMBLE "ssm0:N0."
180 #define AP_ID_PREAMBLE_LEN 8
181 #define LABEL_PREAMBLE "N0/"
182 #define LABEL_PREAMBLE_LEN 3
183 /*
184 * work out type of fru based on name
185 */
186 #define IS_ECACHE_NODE(name) (name[0] == 'E')
187 #define IS_DIMM_NODE(name) (name[0] == 'D' && name[1] != 'V')
188 #define IS_PROC_NODE(name) (name[0] == 'P' && name[1] != 'S')
189 #define IS_PSU_NODE(name) (name[0] == 'P' && name[1] == 'S')
190 #define IS_SB_NODE(name) (name[0] == 'S' && name[1] == 'B')
191 #define IS_IB_NODE(name) (name[0] == 'I')
192 #define IS_FT_NODE(name) (name[0] == 'F' && name[1] == 'T')
193 #define IS_FAN_NODE(name) (name[0] == 'F' && name[1] != 'T')
194 #define IS_RP_NODE(name) (name[0] == 'R')
195 /*
196 * rename sgfru driver's node_t to sgfrunode_t to avoid confusion
197 */
198 #define sgfrunode_t node_t
199
200 /*
201 * disk_led data
202 */
203 #define REMOK_LED "ok_to_remove"
204 #define FAULT_LED "fault"
205 #define POWER_LED "power"
206
207 /*
208 * 'struct lw8_disk' contains the per-disk metadata needed to
209 * manage the current state of one of the internal disks.
210 *
211 * 'lw8_disks[]' is an array that contains the metadata
212 * for N_DISKS disks.
213 *
214 * The d_fruname field of 'struct lw8_disk' is static.
215 * d_plat_path and d_devices_path are aliases for device-paths
216 * to the disk. They are logically static, as they are computed
217 * when the disk_leds_thread() thread does its initialization.
218 *
219 * d_state is the most interesting field, as it changes
220 * dynamically, based on whether the associated disk
221 * is currently Configured or Unconfigured (by DR). d_state
222 * is an optimization that minimizes per-disk actions such
223 * as setting of LEDs and updating the FRU Tree.
224 *
225 * A disk starts in a d_state of DISK_STATE_NOT_INIT
226 * and moves to DISK_STATE_READY when the disk is
227 * Configured (by DR) and it moves to DISK_STATE_NOT_READY
228 * when it is Unconfigured (by DR).
229 */
230 typedef enum {
231 DISK_STATE_NOT_INIT,
232 DISK_STATE_READY,
233 DISK_STATE_NOT_READY
234 } disk_state_t;
235
236 struct lw8_disk {
237 char *d_fruname; /* FRU name */
238 char *d_plat_path; /* /platform */
239 char *d_devices_path; /* /devices */
240 disk_state_t d_state;
241 };
242
243 #define N_DISKS 2
244 static struct lw8_disk lw8_disks[N_DISKS] = {
245 {"DISK0", NULL, NULL, DISK_STATE_NOT_INIT},
246 {"DISK1", NULL, NULL, DISK_STATE_NOT_INIT} };
247
248 /* Duration of inactivity within disk_leds_thread() */
249 #define THR_POLL_PERIOD 5000 /* milliseconds */
250
251 static volatile boolean_t disk_leds_thread_ack = B_FALSE;
252 static pthread_t ledsthr_tid;
253 static pthread_attr_t ledsthr_attr;
254 static boolean_t ledsthr_created = B_FALSE;
255 static uint_t ledsthr_poll_period =
256 THR_POLL_PERIOD;
257 static boolean_t g_mutex_init = B_FALSE;
258 static pthread_cond_t g_cv;
259 static pthread_cond_t g_cv_ack;
260 static pthread_mutex_t g_mutex;
261 static volatile boolean_t g_wait_now = B_FALSE;
262
263 static void disk_leds_init(void);
264 static void disk_leds_fini(void);
265 static void *disk_leds_thread(void *args);
266
267 /*
268 * Tables to convert sgenv information
269 */
270 static char *hpu_type_table[] = { "", "SSC", "SB", "RP", "FT",
271 "IB", "PS", "ID"};
272 static char *hpu_fru_type_table[] = { "", "SSC", "CPU", "RP", "FT",
273 "PCIB", "PS", "ID"};
274 static char *hpu_part_table[] = { "", "sbbc", "sdc",
275 "ar", "cbh", "dx", "cheetah", "1.5vdc", "3.3vdc",
276 "5vdc", "12vdc", "output", "current", "board", "sc-app",
277 "schizo", "fan", "input"};
278 static char *hpu_sensor_table[] = { "", "", "current",
279 "temp", "cooling", "1.5vdc", "1.8vdc", "3.3vdc", "5vdc",
280 "12vdc", "48vdc", NULL, "2.4vdc"};
281 static char *hpu_sensor_class_table[] = { "", "", PICL_CLASS_CURRENT_SENSOR,
282 PICL_CLASS_TEMPERATURE_SENSOR, PICL_CLASS_FAN,
283 PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR,
284 PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR,
285 PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_INDICATOR,
286 NULL, PICL_CLASS_VOLTAGE_SENSOR};
287 static char *hpu_sensor_prop_table[] = { "", "", PICL_PROP_CURRENT,
288 PICL_PROP_TEMPERATURE, PICL_PROP_FAN_SPEED, PICL_PROP_VOLTAGE,
289 PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE,
290 PICL_PROP_VOLTAGE, PICL_PROP_CONDITION, NULL, PICL_PROP_VOLTAGE};
291 static char *hpu_condition_table[] = {"unknown", "okay", "failing",
292 "failed", "unusable"};
293
294 /*
295 * variables set up in init
296 */
297 static picl_nodehdl_t frutreeh;
298 static picl_nodehdl_t sch = 0;
299 static int init_complete;
300 static int pcix_io = 0;
301
302 /*
303 * forward reference
304 */
305 static int add_all_nodes(void);
306 static int remove_subtree(picl_nodehdl_t parh);
307 static int add_subtree(picl_nodehdl_t parh, fru_hdl_t fruparent);
308 static int add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
309 picl_nodehdl_t *childp);
310 static int add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
311 picl_nodehdl_t *childp);
312 static int add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
313 picl_nodehdl_t *childp);
314 static int add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
315 picl_nodehdl_t *childp);
316 static int add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
317 picl_prophdl_t tblhdl);
318 static int add_env_nodes(picl_nodehdl_t nodeh, char *nodename,
319 picl_prophdl_t tblhdl);
320 static int add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
321 picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name);
322 static int add_intermediate_location(picl_nodehdl_t *nodep, char *labelp,
323 char *slot_name);
324 static int add_pci_location(picl_nodehdl_t childh, char *parent_addr,
325 char bus_addr, char *slot_name);
326 static picl_nodehdl_t find_child_by_name(picl_nodehdl_t parh, char *name);
327 static int create_dimm_references(picl_nodehdl_t parh, int dimm_id,
328 picl_nodehdl_t nodeh, picl_prophdl_t tblhdl);
329 static int create_cpu_references(char *pname, picl_nodehdl_t nodeh,
330 picl_prophdl_t tblhdl);
331 static void post_frudr_event(char *ename, picl_nodehdl_t parenth,
332 picl_nodehdl_t fruh);
333 static int remove_references(picl_prophdl_t refprop, char *class);
334 static int remove_picl_node(picl_nodehdl_t nodeh);
335 static sgfrunode_t *get_node_children(fru_hdl_t fruparent, int *num_childrenp);
336 static int add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name);
337 static int add_prop_void(picl_nodehdl_t nodeh, char *name);
338 static int add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name);
339 static int add_prop_int(picl_nodehdl_t nodeh, int value, char *name);
340 static int add_prop_float(picl_nodehdl_t nodeh, float value, char *name);
341 static int add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name);
342 static void frudr_evhandler(const char *ename, const void *earg,
343 size_t size, void *cookie);
344 static void frumemcfg_evhandler(const char *ename, const void *earg,
345 size_t size, void *cookie);
346 static int add_sensor_prop(picl_nodehdl_t nodeh, char *class);
347 static int add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl,
348 char *nodename, char *class, char *prop_class,
349 picl_prophdl_t tblhdl, picl_nodehdl_t *sensorhdlp);
350 static int create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp,
351 char *tbl_name);
352 static int create_table_entry(picl_prophdl_t tblhdl,
353 picl_nodehdl_t refhdl, char *class);
354 static int get_sensor_data(ptree_rarg_t *arg, void *result);
355 static int get_led(char *name, char *ptr, char *result);
356 static int get_led_data(ptree_rarg_t *arg, void *result);
357 static int set_led_data(ptree_warg_t *arg, const void *value);
358 static int get_cpu_status(ptree_rarg_t *arg, void *result);
359 static int add_board_status(picl_nodehdl_t nodeh, char *nodename);
360 static int get_board_status(ptree_rarg_t *arg, void *result);
361 static int get_op_status(ptree_rarg_t *arg, void *result);
362
363 #define sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2)
364 #define sprintf_buf3(buf, a1, a2, a3) \
365 (void) snprintf(buf, sizeof (buf), a1, a2, a3)
366 #define sprintf_buf4(buf, a1, a2, a3, a4) \
367 (void) snprintf(buf, sizeof (buf), a1, a2, a3, a4)
368 #define sprintf_buf5(buf, a1, a2, a3, a4, a5) \
369 (void) snprintf(buf, sizeof (buf), a1, a2, a3, a4, a5)
370 /*
371 * This function is executed as part of .init when the plugin is
372 * dlopen()ed
373 */
374 static void
piclfrutree_register(void)375 piclfrutree_register(void)
376 {
377 (void) picld_plugin_register(&my_reg_info);
378 }
379
380 /*
381 * This function is the init entry point of the plugin.
382 * It initializes the /frutree tree
383 */
384 static void
piclfrutree_init(void)385 piclfrutree_init(void)
386 {
387 int err;
388
389 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
390 frudr_evhandler, NULL);
391 (void) ptree_register_handler(PICLEVENT_MC_ADDED,
392 frumemcfg_evhandler, NULL);
393 (void) ptree_register_handler(PICLEVENT_MC_REMOVED,
394 frumemcfg_evhandler, NULL);
395 init_complete = 0;
396
397 err = add_all_nodes();
398 disk_leds_init();
399 init_complete = 1;
400 if (err != PICL_SUCCESS) {
401 syslog(LOG_ERR, ADD_NODES_FAIL, err);
402 piclfrutree_fini();
403 }
404 }
405
406 /*
407 * This function is the fini entry point of the plugin.
408 */
409 static void
piclfrutree_fini(void)410 piclfrutree_fini(void)
411 {
412 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
413 frudr_evhandler, NULL);
414 (void) ptree_unregister_handler(PICLEVENT_MC_ADDED,
415 frumemcfg_evhandler, NULL);
416 (void) ptree_unregister_handler(PICLEVENT_MC_REMOVED,
417 frumemcfg_evhandler, NULL);
418 (void) remove_subtree(frutreeh);
419 disk_leds_fini();
420 }
421
422 /*
423 * called from piclfrutree_init() to initialise picl frutree
424 */
425 static int
add_all_nodes(void)426 add_all_nodes(void)
427 {
428 int err;
429 picl_nodehdl_t rooth;
430
431 /* Get the root node of the PICL tree */
432 err = ptree_get_root(&rooth);
433 if (err != PICL_SUCCESS) {
434 syslog(LOG_ERR, GET_ROOT_FAIL);
435 return (err);
436 }
437
438 /* find sc node so we can create sensor nodes under it */
439
440 err = ptree_get_node_by_path(SC_DEV, &sch);
441 if (err != PICL_SUCCESS) {
442
443 /*
444 * There is a XMITS/PCI-X IO Board assembly implements
445 * a different path for the the bootbus controller.
446 */
447 err = ptree_get_node_by_path(SC_DEV_PCIX, &sch);
448 if (err == PICL_SUCCESS)
449 pcix_io = 1;
450 }
451
452 if (err != PICL_SUCCESS) {
453 syslog(LOG_ERR, NO_SC_FAIL);
454 return (err);
455 }
456
457 /* Create and add the root node of the FRU subtree */
458 err = ptree_create_and_add_node(rooth, PICL_NODE_FRUTREE,
459 PICL_CLASS_PICL, &frutreeh);
460 if (err != PICL_SUCCESS) {
461 syslog(LOG_ERR, ADD_FRUTREE_FAIL);
462 return (err);
463 }
464
465 /* Recursively query the SC and add frutree nodes */
466 return (add_subtree(frutreeh, ROOTPARENT));
467 }
468
469 /*
470 * Recursive routine to add picl nodes to the frutree. Called from
471 * add_all_nodes() for the whole frutree at initialisation, and from
472 * frudr_evhandler() for portions of the frutree on DR insert events
473 */
474 static int
add_subtree(picl_nodehdl_t parh,fru_hdl_t handle)475 add_subtree(picl_nodehdl_t parh, fru_hdl_t handle)
476 {
477 int err, i;
478 int num_children;
479 sgfrunode_t *cp, *fruchildren = NULL;
480 picl_nodehdl_t childh;
481
482 /* find children of the parent node */
483 fruchildren = get_node_children(handle, &num_children);
484 if (fruchildren == NULL)
485 return (PICL_FAILURE);
486
487 /* for each child, add a new picl node */
488 for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
489 /*
490 * Add the appropriate PICL class
491 */
492 childh = 0;
493 err = add_picl_node(parh, cp, &childh);
494 if (err == PICL_NOTNODE)
495 continue;
496 if (err != PICL_SUCCESS) {
497 free(fruchildren);
498 return (err);
499 }
500
501 /*
502 * Recursively call this function based on has_children hint
503 */
504 if (childh && cp->has_children) {
505 err = add_subtree(childh, cp->handle);
506 if (err != PICL_SUCCESS) {
507 free(fruchildren);
508 return (err);
509 }
510 }
511 }
512 free(fruchildren);
513 return (PICL_SUCCESS);
514 }
515
516 /*
517 * Recursive routine to remove picl nodes to the frutree. Called from
518 * piclfrutree_fini() for the whole frutree at termination, and from
519 * frudr_completion_handler() for portions of the frutree on DR remove events
520 */
521 static int
remove_subtree(picl_nodehdl_t parh)522 remove_subtree(picl_nodehdl_t parh)
523 {
524 picl_nodehdl_t chdh;
525
526 for (;;) {
527 if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh,
528 sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
529 if (remove_subtree(chdh) != PICL_SUCCESS)
530 return (PICL_FAILURE);
531 } else {
532 return (remove_picl_node(parh));
533 }
534 }
535 /* NOTREACHED */
536 }
537
538 /*
539 * Add fru and location nodes with SC_handle property
540 * (aka, container handle, for frus).
541 * Return picl_nodehdl of created node in *childp.
542 */
543 static int
add_picl_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)544 add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
545 picl_nodehdl_t *childp)
546 {
547 switch (sgfrunode->class) {
548 case PSEUDO_FRU_CLASS:
549 return (add_chassis_node(parh, sgfrunode, childp));
550
551 case FRU_CLASS:
552 return (add_fru_node(parh, sgfrunode, childp));
553
554 case LOCATION_CLASS:
555 return (add_location_node(parh, sgfrunode, childp));
556
557 default:
558 syslog(LOG_ERR, INVALID_PICL_CLASS, sgfrunode->class);
559 return (PICL_NOTNODE);
560 }
561 }
562
563 /*
564 * create chassis node
565 */
566 static int
add_chassis_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)567 add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
568 picl_nodehdl_t *childp)
569 {
570 int err;
571 uint64_t handle = (uint64_t)sgfrunode->handle;
572 picl_prophdl_t tblhdl;
573 picl_nodehdl_t nodeh;
574 picl_nodehdl_t devhdl;
575 picl_nodehdl_t childh;
576
577 err = ptree_create_and_add_node(parh, PICL_PROPVAL_CHASSIS,
578 PICL_CLASS_FRU, &childh);
579 if (err != PICL_SUCCESS) {
580 syslog(LOG_ERR, ADD_NODE_FAIL, PICL_PROPVAL_CHASSIS, err);
581 return (err);
582 }
583 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
584 if (err != PICL_SUCCESS)
585 return (err);
586
587 /*
588 * add devices table to chassis node (may need references
589 * to led devices)
590 */
591 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
592 if (err != PICL_SUCCESS)
593 return (err);
594
595 err = add_led_nodes(childh, "chassis", LOM_LED_POSITION_FRU, tblhdl);
596 if (err != PICL_SUCCESS)
597 return (err);
598
599 if (pcix_io)
600 err = ptree_get_node_by_path(DISK0_DEV_PCIX, &devhdl);
601 else
602 err = ptree_get_node_by_path(DISK0_DEV, &devhdl);
603
604 nodeh = childh;
605 if (err != PICL_SUCCESS) {
606 err = add_intermediate_location(&nodeh, "DISK0", "disk-slot");
607 } else {
608 err = add_intermediate_nodes(&nodeh, "DISK0", &tblhdl,
609 "disk-slot", NULL);
610 if (err != PICL_SUCCESS)
611 return (err);
612 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
613 if (err != PICL_SUCCESS)
614 return (err);
615 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
616 }
617 if (err != PICL_SUCCESS)
618 return (err);
619
620 if (pcix_io)
621 err = ptree_get_node_by_path(DISK1_DEV_PCIX, &devhdl);
622 else
623 err = ptree_get_node_by_path(DISK1_DEV, &devhdl);
624
625 nodeh = childh;
626 if (err != PICL_SUCCESS) {
627 err = add_intermediate_location(&nodeh, "DISK1", "disk-slot");
628 } else {
629 err = add_intermediate_nodes(&nodeh, "DISK1", &tblhdl,
630 "disk-slot", NULL);
631 if (err != PICL_SUCCESS)
632 return (err);
633 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
634 if (err != PICL_SUCCESS)
635 return (err);
636 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
637 }
638 if (err != PICL_SUCCESS)
639 return (err);
640
641 if (pcix_io)
642 err = ptree_get_node_by_path(TAPE_DEV_PCIX, &devhdl);
643 else
644 err = ptree_get_node_by_path(TAPE_DEV, &devhdl);
645
646 nodeh = childh;
647 if (err != PICL_SUCCESS) {
648 err = add_intermediate_location(&nodeh, "TAPE", "tape-slot");
649 } else {
650 err = add_intermediate_nodes(&nodeh, "TAPE", &tblhdl,
651 "tape-slot", NULL);
652 if (err != PICL_SUCCESS)
653 return (err);
654 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
655 if (err != PICL_SUCCESS)
656 return (err);
657 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_TAPE);
658 }
659 if (err != PICL_SUCCESS)
660 return (err);
661
662 if (pcix_io)
663 err = ptree_get_node_by_path(DVD_DEV_PCIX, &devhdl);
664 else
665 err = ptree_get_node_by_path(DVD_DEV, &devhdl);
666
667 nodeh = childh;
668 if (err != PICL_SUCCESS) {
669 err = add_intermediate_location(&nodeh, "DVD", "dvd-slot");
670 } else {
671 err = add_intermediate_nodes(&nodeh, "DVD", &tblhdl,
672 "dvd-slot", NULL);
673 if (err != PICL_SUCCESS)
674 return (err);
675 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
676 if (err != PICL_SUCCESS)
677 return (err);
678 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_CDROM);
679 }
680 if (err != PICL_SUCCESS)
681 return (err);
682
683 if (pcix_io) {
684 /*
685 * The XMITS/PCI-X IO Assembly is layed out a bit differently.
686 */
687 err = add_pci_location(childh, "19,600000", '1', "PCI0");
688 if (err != PICL_SUCCESS)
689 return (err);
690 err = add_pci_location(childh, "19,600000", '2', "PCI1");
691 if (err != PICL_SUCCESS)
692 return (err);
693 err = add_pci_location(childh, "19,700000", '1', "PCI2");
694 if (err != PICL_SUCCESS)
695 return (err);
696 err = add_pci_location(childh, "19,700000", '2', "PCI3");
697 if (err != PICL_SUCCESS)
698 return (err);
699 err = add_pci_location(childh, "18,600000", '1', "PCI4");
700 if (err != PICL_SUCCESS)
701 return (err);
702 err = add_pci_location(childh, "18,600000", '2', "PCI5");
703 if (err != PICL_SUCCESS)
704 return (err);
705 } else {
706 err = add_pci_location(childh, "18,700000", '1', "PCI0");
707 if (err != PICL_SUCCESS)
708 return (err);
709 err = add_pci_location(childh, "18,700000", '2', "PCI1");
710 if (err != PICL_SUCCESS)
711 return (err);
712 err = add_pci_location(childh, "19,700000", '1', "PCI2");
713 if (err != PICL_SUCCESS)
714 return (err);
715 err = add_pci_location(childh, "19,700000", '2', "PCI3");
716 if (err != PICL_SUCCESS)
717 return (err);
718 err = add_pci_location(childh, "19,700000", '3', "PCI4");
719 if (err != PICL_SUCCESS)
720 return (err);
721 err = add_pci_location(childh, "18,600000", '1', "PCI5");
722 if (err != PICL_SUCCESS)
723 return (err);
724 }
725 *childp = childh;
726 return (PICL_SUCCESS);
727 }
728
729 /*
730 * create fru node, based on sgfru node "sgfrunode" under parent parh. Return
731 * picl_nodehdl of created node in *childp.
732 */
733 static int
add_fru_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)734 add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
735 picl_nodehdl_t *childp)
736 {
737 int err;
738 picl_prophdl_t tblhdl;
739 picl_nodehdl_t childh;
740 uint64_t handle = (uint64_t)sgfrunode->handle;
741 char *nodename = sgfrunode->nodename;
742
743 /*
744 * if sgfrunode already there, then just carry on own the tree
745 */
746 childh = find_child_by_name(parh, nodename);
747 if (childh != 0) {
748 /*
749 * for frus other than dimms and ecaches, update environmental
750 * sensors and board status if necessary
751 */
752 if (IS_ECACHE_NODE(nodename)) {
753 *childp = childh;
754 return (PICL_SUCCESS);
755 }
756 if (IS_DIMM_NODE(nodename)) {
757 /*
758 * for dimms we just want status
759 */
760 err = add_board_status(childh, nodename);
761 if (err != PICL_SUCCESS)
762 return (err);
763 *childp = childh;
764 return (PICL_SUCCESS);
765 }
766 err = add_board_status(childh, nodename);
767 if (err != PICL_SUCCESS)
768 return (err);
769 err = ptree_get_propval_by_name(childh, PICL_PROP_DEVICES,
770 &tblhdl, sizeof (tblhdl));
771 if (err != PICL_SUCCESS)
772 return (err);
773 err = add_env_nodes(childh, nodename, tblhdl);
774 if (err != PICL_SUCCESS)
775 return (err);
776 *childp = childh;
777 return (PICL_SUCCESS);
778 }
779
780 /*
781 * create requested fru node
782 */
783 err = ptree_create_and_add_node(parh, nodename, PICL_CLASS_FRU,
784 &childh);
785 if (err != PICL_SUCCESS) {
786 syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err);
787 return (err);
788 }
789
790 /*
791 * if sgfru has sent us a valid handle, then there is fruid information.
792 * create the SC_handle, and FRUDateAvailable properties for FRUID.
793 */
794 if (handle != -1ULL) {
795 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
796 if (err != PICL_SUCCESS)
797 return (err);
798 err = add_prop_void(childh, PICL_PROP_FRUDATA_AVAIL);
799 if (err != PICL_SUCCESS)
800 return (err);
801 }
802
803 /*
804 * post fru added event to fru data plugin if this was due to
805 * a dr event - ie post-initialisation
806 */
807 if (init_complete)
808 post_frudr_event(PICL_FRU_ADDED, parh, 0);
809
810 /*
811 * Create empty Devices table - we'll add lines to it as we go along
812 */
813 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
814 if (err != PICL_SUCCESS)
815 return (err);
816
817 /*
818 * Ecache nodes don't have sensors - just set up FRUType
819 */
820 if (IS_ECACHE_NODE(nodename)) {
821 err = add_prop_charstring(childh, "EEPROM", PICL_PROP_FRU_TYPE);
822 if (err != PICL_SUCCESS)
823 return (err);
824 *childp = childh;
825 return (PICL_SUCCESS);
826 }
827
828 /*
829 * Dimm nodes don't have sensors - just set up FRUType and
830 * also reference properties to memory module nodes and OpStatus
831 */
832 if (IS_DIMM_NODE(nodename)) {
833 err = add_prop_charstring(childh, "DIMM", PICL_PROP_FRU_TYPE);
834 if (err != PICL_SUCCESS)
835 return (err);
836 err = create_dimm_references(parh, nodename[1] - '0',
837 childh, tblhdl);
838 if (err != PICL_SUCCESS)
839 return (err);
840 err = add_board_status(childh, nodename);
841 if (err != PICL_SUCCESS)
842 return (err);
843 *childp = childh;
844 return (PICL_SUCCESS);
845 }
846
847 /*
848 * not a Dimm or Ecache node - set up environmental info,
849 * board status and led info
850 */
851 err = add_env_nodes(childh, nodename, tblhdl);
852 if (err != PICL_SUCCESS)
853 return (err);
854
855 err = add_board_status(childh, nodename);
856 if (err != PICL_SUCCESS)
857 return (err);
858
859 err = add_led_nodes(childh, nodename, LOM_LED_POSITION_FRU, tblhdl);
860 if (err != PICL_SUCCESS)
861 return (err);
862
863 *childp = childh;
864 return (PICL_SUCCESS);
865 }
866
867 /*
868 * create location node, based on sgfru node "sgfrunode" under parent parh.
869 * Return picl_nodehdl of created node in *childp.
870 */
871 static int
add_location_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)872 add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
873 picl_nodehdl_t *childp)
874 {
875 int err;
876 uint64_t handle = (uint64_t)sgfrunode->handle;
877 char *labelp;
878 char label[MAX_LABEL_LEN];
879 char *ptr;
880 picl_prophdl_t tblhdl;
881 picl_nodehdl_t childh;
882
883 /*
884 * strip "N0/" off the label if present (hang-over from wildcat)
885 */
886 if (strncmp(sgfrunode->location_label, LABEL_PREAMBLE,
887 LABEL_PREAMBLE_LEN) == 0)
888 (void) strlcpy(label, &sgfrunode->location_label[
889 LABEL_PREAMBLE_LEN], sizeof (label));
890 else
891 (void) strlcpy(label, &sgfrunode->location_label[0],
892 sizeof (label));
893
894 /*
895 * some of the locations returned by sgfru are actually of the form
896 * XX/YY/ZZ - we need to create multiple levels in the picl tree for
897 * these.
898 */
899 labelp = label;
900 while ((ptr = strchr(labelp, '/')) != NULL) {
901 /*
902 * null end of this section of label
903 */
904 *ptr = '\0';
905
906 /*
907 * add intermediate nodes - parh will point to the created node
908 */
909 if (IS_PROC_NODE(labelp)) {
910 err = add_intermediate_nodes(&parh, labelp, &tblhdl,
911 "cpu", "PROC");
912 } else {
913 err = add_intermediate_nodes(&parh, labelp, &tblhdl,
914 NULL, NULL);
915 }
916 if (err != PICL_SUCCESS)
917 return (err);
918 /*
919 * if processor node, then create links to associated cpu node
920 * and OpStatus property
921 */
922 if (IS_PROC_NODE(labelp)) {
923 err = create_cpu_references(labelp, parh, tblhdl);
924 if (err != PICL_SUCCESS)
925 return (err);
926 err = add_board_status(parh, labelp);
927 if (err != PICL_SUCCESS)
928 return (err);
929 }
930 labelp = ptr + 1;
931
932 /*
933 * set back to "/"
934 */
935 *ptr = '/';
936 }
937
938 /*
939 * if node already there, then just carry on down the tree
940 */
941 childh = find_child_by_name(parh, labelp);
942 if (childh != 0) {
943 *childp = childh;
944 return (PICL_SUCCESS);
945 }
946
947 /*
948 * now just have the final level of the node left. First create it.
949 */
950 err = ptree_create_and_add_node(parh, labelp, PICL_CLASS_LOCATION,
951 &childh);
952 if (err != PICL_SUCCESS) {
953 syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
954 return (err);
955 }
956
957 /*
958 * if sgfru has sent us a valid handle, then there is fruid information.
959 * create the SC_handle property for FRUID.
960 */
961 if (handle != -1ULL) {
962 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
963 if (err != PICL_SUCCESS)
964 return (err);
965 }
966
967 /* create label property for location class */
968 err = add_prop_charstring(childh, labelp, PICL_PROP_LABEL);
969 if (err != PICL_SUCCESS)
970 return (err);
971
972 /* create SlotType property where appropriate */
973 if (IS_ECACHE_NODE(sgfrunode->nodename)) {
974 err = add_prop_charstring(childh,
975 "ecache", PICL_PROP_SLOT_TYPE);
976 /*
977 * For Ecache, don't need to add environmental info
978 * so return here
979 */
980 *childp = childh;
981 return (err);
982 } else if (IS_DIMM_NODE(sgfrunode->nodename)) {
983 err = add_prop_charstring(childh, "memory-module",
984 PICL_PROP_SLOT_TYPE);
985 /*
986 * For Dimm, don't need to add environmental info
987 * so return here
988 */
989 *childp = childh;
990 return (err);
991 } else if (IS_SB_NODE(sgfrunode->nodename)) {
992 err = add_prop_charstring(childh, "system-board",
993 PICL_PROP_SLOT_TYPE);
994 } else if (IS_PSU_NODE(sgfrunode->nodename)) {
995 err = add_prop_charstring(childh, "power-supply",
996 PICL_PROP_SLOT_TYPE);
997 } else if (IS_FT_NODE(sgfrunode->nodename)) {
998 err = add_prop_charstring(childh, "fan-tray",
999 PICL_PROP_SLOT_TYPE);
1000 }
1001 if (err != PICL_SUCCESS)
1002 return (err);
1003
1004 /*
1005 * add devices table to location node (may need
1006 * references to led devices)
1007 */
1008 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
1009 if (err != PICL_SUCCESS)
1010 return (err);
1011
1012 err = add_led_nodes(childh, labelp, LOM_LED_POSITION_LOCATION, tblhdl);
1013 if (err != PICL_SUCCESS)
1014 return (err);
1015 *childp = childh;
1016 return (PICL_SUCCESS);
1017 }
1018
1019 /*
1020 * remove an individual picl node - called from remove_subtree()
1021 * also removes any sensor nodes pointed at by Devices table
1022 */
1023 static int
remove_picl_node(picl_nodehdl_t nodeh)1024 remove_picl_node(picl_nodehdl_t nodeh)
1025 {
1026 int err;
1027 picl_prophdl_t tblhdl;
1028 picl_prophdl_t nextprop;
1029 picl_prophdl_t refprop;
1030 char class[PICL_CLASSNAMELEN_MAX];
1031
1032 /*
1033 * first scan Devices table so we can find any sensor nodes
1034 * we need to delete as well
1035 */
1036 err = ptree_get_propval_by_name(nodeh, PICL_PROP_DEVICES,
1037 &tblhdl, sizeof (tblhdl));
1038
1039 /*
1040 * If Devices table present, then read first column.
1041 * Devices table may be empty so don't treat this as an error
1042 */
1043 if (err == PICL_SUCCESS &&
1044 ptree_get_next_by_row(tblhdl, &nextprop) == PICL_SUCCESS) {
1045 /* find second column */
1046 err = ptree_get_next_by_row(nextprop, &nextprop);
1047 if (err != PICL_SUCCESS) {
1048 syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL,
1049 PICL_PROP_DEVICES, err);
1050 return (err);
1051 }
1052
1053 /*
1054 * walk down second column (ref ptr)
1055 * deleting the referenced nodes
1056 */
1057 while (err == PICL_SUCCESS) {
1058 err = ptree_get_propval(nextprop, &refprop,
1059 sizeof (refprop));
1060 if (err != PICL_SUCCESS) {
1061 syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
1062 return (err);
1063 }
1064
1065 /*
1066 * don't delete memory-module nodes
1067 * or cpu nodes (they weren't created
1068 * by this plugin)
1069 */
1070 err = ptree_get_propval_by_name(refprop,
1071 PICL_PROP_CLASSNAME, class, sizeof (class));
1072 if (err == PICL_STALEHANDLE) {
1073 /*
1074 * if another plugin has already deleted the
1075 * node for us then that is ok
1076 */
1077 err = ptree_get_next_by_col(nextprop,
1078 &nextprop);
1079 continue;
1080 }
1081 if (err != PICL_SUCCESS) {
1082 syslog(LOG_ERR, PROP_LOOKUP_FAIL,
1083 PICL_PROP_CLASSNAME, err);
1084 return (err);
1085 }
1086 if (strcmp(class, PICL_CLASS_MEMORY_MODULE) == 0 ||
1087 strcmp(class, PICL_CLASS_CPU) == 0) {
1088 /*
1089 * but - do need to remove _fru_parent
1090 * property and Environment table (for cpu)
1091 */
1092 err = remove_references(refprop, class);
1093 if (err != PICL_SUCCESS)
1094 return (err);
1095 } else {
1096 /*
1097 * sensor node - need to delete it
1098 */
1099 err = ptree_delete_node(refprop);
1100 if (err != PICL_SUCCESS) {
1101 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1102 return (err);
1103 }
1104 (void) ptree_destroy_node(refprop);
1105 }
1106 err = ptree_get_next_by_col(nextprop, &nextprop);
1107 }
1108 }
1109
1110 /*
1111 * now we can remove the frutree node
1112 */
1113 err = ptree_delete_node(nodeh);
1114 if (err != PICL_SUCCESS) {
1115 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1116 return (err);
1117 }
1118 (void) ptree_destroy_node(nodeh);
1119 return (PICL_SUCCESS);
1120 }
1121
1122 static int
add_child_pci_references(picl_nodehdl_t nodeh,picl_prophdl_t tblhdl,picl_nodehdl_t devnodeh)1123 add_child_pci_references(picl_nodehdl_t nodeh, picl_prophdl_t tblhdl,
1124 picl_nodehdl_t devnodeh)
1125 {
1126 int err = PICL_SUCCESS;
1127 picl_nodehdl_t childnodeh;
1128 char class[PICL_CLASSNAMELEN_MAX];
1129
1130 if (ptree_get_propval_by_name(devnodeh, PICL_PROP_CHILD, &childnodeh,
1131 sizeof (childnodeh)) != PICL_SUCCESS) {
1132 return (PICL_SUCCESS);
1133 }
1134 for (;;) {
1135 err = ptree_get_propval_by_name(childnodeh,
1136 PICL_PROP_CLASSNAME, class, sizeof (class));
1137 if (err != PICL_SUCCESS)
1138 break;
1139 err = add_prop_ref(childnodeh, nodeh, PICL_REFPROP_FRU_PARENT);
1140 if (err != PICL_SUCCESS)
1141 break;
1142 err = create_table_entry(tblhdl, childnodeh, class);
1143 if (err != PICL_SUCCESS)
1144 break;
1145 err = add_child_pci_references(nodeh, tblhdl, childnodeh);
1146 if (err != PICL_SUCCESS)
1147 break;
1148 err = ptree_get_propval_by_name(childnodeh,
1149 PICL_PROP_PEER, &childnodeh, sizeof (picl_nodehdl_t));
1150 if (err != PICL_SUCCESS) {
1151 err = PICL_SUCCESS;
1152 break;
1153 }
1154 }
1155 return (err);
1156 }
1157
1158 static int
add_pci_location(picl_nodehdl_t childh,char * parent_addr,char bus_addr,char * slot_name)1159 add_pci_location(picl_nodehdl_t childh, char *parent_addr, char bus_addr,
1160 char *slot_name)
1161 {
1162 int err;
1163 int got_one = 0;
1164 picl_nodehdl_t nodeh;
1165 picl_nodehdl_t devnodeh;
1166 picl_nodehdl_t devhdl;
1167 char addr[MAXPATHLEN];
1168 char parent_path[MAXPATHLEN];
1169 picl_prophdl_t tblhdl;
1170 char class[PICL_CLASSNAMELEN_MAX];
1171
1172 /*
1173 * search for any device nodes whose BUS_ADDR or UNIT_ADDRESS
1174 * are appropriate for this pci slot
1175 */
1176 sprintf_buf2(parent_path, IO_DEV, parent_addr);
1177 if (ptree_get_node_by_path(parent_path, &devhdl) == PICL_SUCCESS &&
1178 ptree_get_propval_by_name(devhdl, PICL_PROP_CHILD, &devnodeh,
1179 sizeof (devnodeh)) == PICL_SUCCESS) {
1180 while (!got_one) {
1181 err = ptree_get_propval_by_name(devnodeh,
1182 PICL_PROP_BUS_ADDR, addr, sizeof (addr));
1183 if (err == PICL_SUCCESS && addr[0] == bus_addr &&
1184 (addr[1] == ',' || addr[1] == '\0')) {
1185 got_one = 1;
1186 break;
1187 }
1188 err = ptree_get_propval_by_name(devnodeh,
1189 PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr));
1190 if (err == PICL_SUCCESS && addr[0] == bus_addr &&
1191 (addr[1] == ',' || addr[1] == '\0')) {
1192 got_one = 1;
1193 break;
1194 }
1195 err = ptree_get_propval_by_name(devnodeh,
1196 PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
1197 if (err != PICL_SUCCESS)
1198 break;
1199 }
1200 }
1201 nodeh = childh;
1202 if (got_one == 0) {
1203 /*
1204 * no devnodes for this slot. Create location node but
1205 * no fru node (empty slot)
1206 */
1207 return (add_intermediate_location(&nodeh, slot_name, "pci"));
1208 }
1209
1210 /*
1211 * we've got the first devnode for this slot. Create the fru node
1212 * then walk along other nodes looking for further devnodes
1213 */
1214 err = add_intermediate_nodes(&nodeh, slot_name, &tblhdl, "pci", NULL);
1215 if (err != PICL_SUCCESS)
1216 return (err);
1217
1218 for (;;) {
1219 if (((err = ptree_get_propval_by_name(devnodeh,
1220 PICL_PROP_BUS_ADDR, addr, sizeof (addr))) ==
1221 PICL_SUCCESS && addr[0] == bus_addr &&
1222 (addr[1] == ',' || addr[1] == '\0')) ||
1223 ((err = ptree_get_propval_by_name(devnodeh,
1224 PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr))) ==
1225 PICL_SUCCESS && addr[0] == bus_addr &&
1226 (addr[1] == ',' || addr[1] == '\0'))) {
1227 err = ptree_get_propval_by_name(devnodeh,
1228 PICL_PROP_CLASSNAME, class, sizeof (class));
1229 if (err != PICL_SUCCESS)
1230 break;
1231 err = add_prop_ref(devnodeh, nodeh,
1232 PICL_REFPROP_FRU_PARENT);
1233 if (err != PICL_SUCCESS)
1234 break;
1235 err = create_table_entry(tblhdl, devnodeh, class);
1236 if (err != PICL_SUCCESS)
1237 break;
1238 err = add_child_pci_references(nodeh, tblhdl, devnodeh);
1239 if (err != PICL_SUCCESS)
1240 break;
1241 }
1242 err = ptree_get_propval_by_name(devnodeh,
1243 PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
1244 if (err != PICL_SUCCESS) {
1245 err = PICL_SUCCESS;
1246 break;
1247 }
1248 }
1249 return (err);
1250 }
1251
1252 /*
1253 * add intermediate location into frutree (ie a location that we know
1254 * exists but sgfru doesn't)
1255 */
1256 static int
add_intermediate_location(picl_nodehdl_t * nodep,char * labelp,char * slot_name)1257 add_intermediate_location(picl_nodehdl_t *nodep, char *labelp, char *slot_name)
1258 {
1259 int err;
1260 picl_nodehdl_t intermediate;
1261 picl_prophdl_t tblhdl;
1262 char parent_name[PICL_PROPNAMELEN_MAX];
1263
1264 err = ptree_create_and_add_node(*nodep, labelp, PICL_CLASS_LOCATION,
1265 &intermediate);
1266 if (err != PICL_SUCCESS) {
1267 syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
1268 return (err);
1269 }
1270
1271 /*
1272 * create label property for location class
1273 */
1274 err = add_prop_charstring(intermediate, labelp, PICL_PROP_LABEL);
1275 if (err != PICL_SUCCESS)
1276 return (err);
1277
1278 /*
1279 * add devices table to location node (may need references to led
1280 * devices)
1281 */
1282 err = create_table(intermediate, &tblhdl, PICL_PROP_DEVICES);
1283 if (err != PICL_SUCCESS)
1284 return (err);
1285
1286 /*
1287 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
1288 */
1289 err = ptree_get_propval_by_name(*nodep, PICL_PROP_NAME, parent_name,
1290 sizeof (parent_name));
1291 if (err != PICL_SUCCESS)
1292 return (err);
1293 if (strcmp(labelp, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0)
1294 err = add_led_nodes(intermediate, "FAN8",
1295 LOM_LED_POSITION_LOCATION, tblhdl);
1296 else if (strcmp(labelp, "FAN1") == 0 && strcmp(parent_name, "IB6") == 0)
1297 err = add_led_nodes(intermediate, "FAN9",
1298 LOM_LED_POSITION_LOCATION, tblhdl);
1299 else
1300 err = add_led_nodes(intermediate, labelp,
1301 LOM_LED_POSITION_LOCATION, tblhdl);
1302 if (err != PICL_SUCCESS)
1303 return (err);
1304
1305 if (slot_name) {
1306 err = add_prop_charstring(intermediate, slot_name,
1307 PICL_PROP_SLOT_TYPE);
1308 if (err != PICL_SUCCESS)
1309 return (err);
1310 }
1311 *nodep = intermediate;
1312 return (PICL_SUCCESS);
1313 }
1314
1315 /*
1316 * adds an intermediate location/fru pair into frutree
1317 */
1318 static int
add_intermediate_nodes(picl_nodehdl_t * nodep,char * labelp,picl_prophdl_t * tblhdlp,char * slot_name,char * fru_name)1319 add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
1320 picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name)
1321 {
1322 int err;
1323 picl_nodehdl_t intermediate;
1324 picl_nodehdl_t intermediate2;
1325
1326 /*
1327 * create intermediate location node (unless it has already been
1328 * created)
1329 */
1330 intermediate = find_child_by_name(*nodep, labelp);
1331 if (intermediate == 0) {
1332 intermediate = *nodep;
1333 err = add_intermediate_location(&intermediate, labelp,
1334 slot_name);
1335 if (err != PICL_SUCCESS) {
1336 return (err);
1337 }
1338 }
1339
1340 /*
1341 * create intermediate fru node (unless it has already been
1342 * created)
1343 */
1344 intermediate2 = find_child_by_name(intermediate, labelp);
1345 if (intermediate2 == 0) {
1346 /*
1347 * need to create intermediate fru node node
1348 */
1349 err = ptree_create_and_add_node(intermediate, labelp,
1350 PICL_CLASS_FRU, &intermediate2);
1351 if (err != PICL_SUCCESS) {
1352 syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
1353 return (err);
1354 }
1355
1356 /*
1357 * Create empty Devices table
1358 */
1359 err = create_table(intermediate2, tblhdlp, PICL_PROP_DEVICES);
1360 if (err != PICL_SUCCESS)
1361 return (err);
1362
1363 if (fru_name) {
1364 err = add_prop_charstring(intermediate2, fru_name,
1365 PICL_PROP_FRU_TYPE);
1366 if (err != PICL_SUCCESS)
1367 return (err);
1368 }
1369 } else {
1370 err = ptree_get_propval_by_name(intermediate2,
1371 PICL_PROP_DEVICES, tblhdlp, sizeof (*tblhdlp));
1372 if (err != PICL_SUCCESS)
1373 return (err);
1374 }
1375 *nodep = intermediate2;
1376 return (PICL_SUCCESS);
1377 }
1378
1379 /*
1380 * need to remove _fru_parent property and Environment table (for cpu)
1381 */
1382 static int
remove_references(picl_prophdl_t refprop,char * class)1383 remove_references(picl_prophdl_t refprop, char *class)
1384 {
1385 picl_prophdl_t platprop;
1386 int err;
1387
1388 err = ptree_get_prop_by_name(refprop, PICL_REFPROP_FRU_PARENT,
1389 &platprop);
1390 if (err != PICL_SUCCESS) {
1391 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1392 return (err);
1393 }
1394 err = ptree_delete_prop(platprop);
1395 if (err != PICL_SUCCESS) {
1396 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1397 return (err);
1398 }
1399 (void) ptree_destroy_prop(platprop);
1400 if (strcmp(class, PICL_CLASS_CPU) == 0) {
1401 err = ptree_get_prop_by_name(refprop, PICL_PROP_ENV, &platprop);
1402 if (err != PICL_SUCCESS) {
1403 /*
1404 * multi-core cpu is setup with only one cpu having
1405 * env table so ignore PICL_PROPNOTFOUND error.
1406 */
1407 if (err == PICL_PROPNOTFOUND) {
1408 return (PICL_SUCCESS);
1409 }
1410 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_ENV, err);
1411 return (err);
1412 }
1413 err = ptree_delete_prop(platprop);
1414 if (err != PICL_SUCCESS) {
1415 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1416 return (err);
1417 }
1418 (void) ptree_destroy_prop(platprop);
1419 }
1420 return (PICL_SUCCESS);
1421 }
1422
1423 /*
1424 * subroutine for various functions. Finds immediate child of parh with
1425 * requested name if present. Otherwise returns NULL.
1426 */
1427 static picl_nodehdl_t
find_child_by_name(picl_nodehdl_t parh,char * name)1428 find_child_by_name(picl_nodehdl_t parh, char *name)
1429 {
1430 picl_nodehdl_t nodeh;
1431 int err;
1432 char nodename[PICL_PROPNAMELEN_MAX];
1433
1434 err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD,
1435 &nodeh, sizeof (picl_nodehdl_t));
1436 if (err != PICL_SUCCESS)
1437 return (0);
1438 for (;;) {
1439 err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename,
1440 sizeof (nodename));
1441 if (err != PICL_SUCCESS)
1442 return (0);
1443 if (strcmp(name, nodename) == 0) {
1444 return (nodeh);
1445 }
1446 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
1447 &nodeh, sizeof (picl_nodehdl_t));
1448 if (err != PICL_SUCCESS)
1449 return (0);
1450 }
1451 }
1452
1453 static int
create_dimm_references(picl_nodehdl_t parh,int dimm_id,picl_nodehdl_t nodeh,picl_prophdl_t tblhdl)1454 create_dimm_references(picl_nodehdl_t parh, int dimm_id,
1455 picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
1456 {
1457 int err;
1458 picl_nodehdl_t memctlhdl = 0;
1459 picl_nodehdl_t memgrphdl;
1460 picl_nodehdl_t memhdl;
1461 char name[MAXPATHLEN];
1462 char sbname[PICL_PROPNAMELEN_MAX];
1463 char pname[PICL_PROPNAMELEN_MAX];
1464 char bname[PICL_PROPNAMELEN_MAX];
1465 picl_nodehdl_t parentfruh;
1466 picl_nodehdl_t parentloch;
1467 int id;
1468
1469 /*
1470 * create reference properties for memory nodes
1471 * - first find names of ancestor frus - ie "SBx/Py/Bz"
1472 */
1473 err = ptree_get_propval_by_name(parh, PICL_PROP_PARENT, &parentfruh,
1474 sizeof (picl_nodehdl_t));
1475 if (err != PICL_SUCCESS) {
1476 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1477 return (err);
1478 }
1479 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME,
1480 bname, sizeof (bname));
1481 if (err != PICL_SUCCESS) {
1482 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
1483 return (err);
1484 }
1485 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT,
1486 &parentloch, sizeof (picl_nodehdl_t));
1487 if (err != PICL_SUCCESS) {
1488 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1489 return (err);
1490 }
1491 err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
1492 &parentfruh, sizeof (picl_nodehdl_t));
1493 if (err != PICL_SUCCESS) {
1494 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1495 return (err);
1496 }
1497 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME,
1498 pname, sizeof (pname));
1499 if (err != PICL_SUCCESS) {
1500 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
1501 return (err);
1502 }
1503
1504 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT,
1505 &parentloch, sizeof (picl_nodehdl_t));
1506 if (err != PICL_SUCCESS) {
1507 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1508 return (err);
1509 }
1510 err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
1511 &parentfruh, sizeof (picl_nodehdl_t));
1512 if (err != PICL_SUCCESS) {
1513 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1514 return (err);
1515 }
1516 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname,
1517 sizeof (sbname));
1518 if (err != PICL_SUCCESS) {
1519 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
1520 return (err);
1521 }
1522
1523 /*
1524 * ok - we've now got name of system board node in sbname and
1525 * name of processor node in pname.
1526 * Now find corresponding memory-controller node if present
1527 */
1528 sprintf_buf2(name, MEMORY_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
1529 err = ptree_get_node_by_path(name, &memctlhdl);
1530 if (err != PICL_SUCCESS)
1531 return (PICL_SUCCESS);
1532
1533 /*
1534 * now find corresponding memory-module-group node if present
1535 */
1536 err = ptree_get_propval_by_name(memctlhdl, PICL_PROP_CHILD, &memgrphdl,
1537 sizeof (picl_nodehdl_t));
1538 if (err != PICL_SUCCESS)
1539 return (PICL_SUCCESS);
1540
1541 /*
1542 * check if this is the right bank - if not move on to sibling
1543 */
1544 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID,
1545 &id, sizeof (int));
1546 if (err != PICL_SUCCESS)
1547 return (PICL_SUCCESS);
1548 if (bname[1] != id + '0') {
1549 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_PEER,
1550 &memgrphdl, sizeof (picl_nodehdl_t));
1551 if (err != PICL_SUCCESS)
1552 return (PICL_SUCCESS);
1553 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID,
1554 &id, sizeof (int));
1555 if (err != PICL_SUCCESS)
1556 return (PICL_SUCCESS);
1557 if (bname[1] != id + '0')
1558 return (PICL_SUCCESS);
1559 }
1560
1561 /*
1562 * now find corresponding memory-module node if present
1563 */
1564 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_CHILD, &memhdl,
1565 sizeof (picl_nodehdl_t));
1566 if (err != PICL_SUCCESS)
1567 return (PICL_SUCCESS);
1568
1569 /*
1570 * for each DIMM set up links with matching memory-module node
1571 */
1572 for (;;) {
1573 err = ptree_get_propval_by_name(memhdl, PICL_PROP_ID,
1574 &id, sizeof (int));
1575 if (err == PICL_SUCCESS && dimm_id == id) {
1576 err = add_prop_ref(memhdl, nodeh,
1577 PICL_REFPROP_FRU_PARENT);
1578 if (err != PICL_SUCCESS)
1579 return (err);
1580 err = create_table_entry(tblhdl, memhdl,
1581 PICL_CLASS_MEMORY_MODULE);
1582 if (err != PICL_SUCCESS)
1583 return (err);
1584 }
1585 err = ptree_get_propval_by_name(memhdl, PICL_PROP_PEER,
1586 &memhdl, sizeof (picl_nodehdl_t));
1587 if (err != PICL_SUCCESS)
1588 break;
1589 }
1590 return (PICL_SUCCESS);
1591 }
1592
1593 static int
create_cpu_references(char * pname,picl_nodehdl_t nodeh,picl_prophdl_t tblhdl)1594 create_cpu_references(char *pname, picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
1595 {
1596 int err;
1597 picl_nodehdl_t sensorhdl;
1598 picl_nodehdl_t parentloch;
1599 picl_nodehdl_t parentfruh;
1600 picl_nodehdl_t cpuhdl;
1601 picl_nodehdl_t cpuhdl1;
1602 picl_prophdl_t envtblhdl;
1603 picl_prophdl_t prophdl;
1604 char name[MAXPATHLEN];
1605 char sbname[PICL_PROPNAMELEN_MAX];
1606
1607 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
1608 &parentloch, sizeof (picl_nodehdl_t));
1609 if (err != PICL_SUCCESS) {
1610 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1611 return (err);
1612 }
1613 err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
1614 &parentfruh, sizeof (picl_nodehdl_t));
1615 if (err != PICL_SUCCESS) {
1616 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
1617 return (err);
1618 }
1619 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname,
1620 sizeof (sbname));
1621 if (err != PICL_SUCCESS) {
1622 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
1623 return (err);
1624 }
1625
1626 /*
1627 * Find corresponding cpu node if present. Note, this code will
1628 * attempt to find a corresponding cpu node, by searching for devices
1629 * of the types /platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0,
1630 * /platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0 or
1631 * /platform/ssm@0,0/cmp@%x,0/cpu@0 or 1. If we can not find
1632 * any such device, we return PICL_SUCCESS such that we
1633 * continue the construction of the remaining part of the
1634 * tree. We first check for UltraSPARC-III. If we do not
1635 * find such a device we check for UltraSPARC-III+. If
1636 * we are unsuccesful again we try one of the jaguar cores
1637 * /platform/ssm@0,0/cmp@%x,0/cpu@. If we do not find the
1638 * first one, there's no point in continuing and we just
1639 * return PICL_SUCCESS. Similarly if we find one core
1640 * but not the other, something must be wrong, so we
1641 * again just return PICL_SUCCESS without creating any
1642 * references.
1643 */
1644 sprintf_buf2(name, CPU_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
1645
1646 err = ptree_get_node_by_path(name, &cpuhdl);
1647
1648 if (err != PICL_SUCCESS) {
1649 sprintf_buf2(name, CPU_DEV2,
1650 SB_P_TO_SAFARI_ADDR(sbname, pname));
1651 err = ptree_get_node_by_path(name, &cpuhdl);
1652 if (err != PICL_SUCCESS) {
1653 /* check for jaguar cores */
1654 sprintf_buf2(name, CPU_DEV3C1,
1655 SB_P_TO_SAFARI_ADDR(sbname, pname));
1656 err = ptree_get_node_by_path(name, &cpuhdl1);
1657 if (err != PICL_SUCCESS)
1658 return (PICL_SUCCESS);
1659 /* add fru parent reference for the second core */
1660 err = ptree_get_prop_by_name(cpuhdl1,
1661 PICL_REFPROP_FRU_PARENT, &prophdl);
1662 if (err != PICL_SUCCESS) {
1663 err = add_prop_ref(cpuhdl1, nodeh,
1664 PICL_REFPROP_FRU_PARENT);
1665 if (err != PICL_SUCCESS)
1666 return (err);
1667 err = create_table_entry(tblhdl, cpuhdl1,
1668 PICL_CLASS_CPU);
1669 if (err != PICL_SUCCESS)
1670 return (err);
1671 }
1672 sprintf_buf2(name, CPU_DEV3C0,
1673 SB_P_TO_SAFARI_ADDR(sbname, pname));
1674 err = ptree_get_node_by_path(name, &cpuhdl);
1675 if (err != PICL_SUCCESS)
1676 return (PICL_SUCCESS);
1677
1678 }
1679 }
1680
1681 /*
1682 * now create reference properties
1683 */
1684 err = ptree_get_prop_by_name(cpuhdl, PICL_REFPROP_FRU_PARENT, &prophdl);
1685 if (err != PICL_SUCCESS) {
1686 err = add_prop_ref(cpuhdl, nodeh, PICL_REFPROP_FRU_PARENT);
1687 if (err != PICL_SUCCESS)
1688 return (err);
1689 err = create_table_entry(tblhdl, cpuhdl, PICL_CLASS_CPU);
1690 if (err != PICL_SUCCESS)
1691 return (err);
1692 }
1693
1694 /*
1695 * create Environment table on cpu node - with Die and Ambient
1696 * temperature sensors if present. If already there, delete and start
1697 * again
1698 */
1699 err = ptree_get_prop_by_name(cpuhdl, PICL_PROP_ENV, &prophdl);
1700 if (err == PICL_SUCCESS) {
1701 err = ptree_delete_prop(prophdl);
1702 if (err != PICL_SUCCESS)
1703 return (err);
1704 (void) ptree_destroy_prop(prophdl);
1705 }
1706 err = create_table(cpuhdl, &envtblhdl, PICL_PROP_ENV);
1707 if (err != PICL_SUCCESS)
1708 return (err);
1709
1710 if (pcix_io)
1711 sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV_PCIX, sbname,
1712 (pname[1] - '0'));
1713 else
1714 sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV, sbname,
1715 (pname[1] - '0'));
1716
1717 err = ptree_get_node_by_path(name, &sensorhdl);
1718 if (err == PICL_SUCCESS) {
1719 err = create_table_entry(envtblhdl, sensorhdl,
1720 PICL_CLASS_TEMPERATURE_SENSOR);
1721 if (err != PICL_SUCCESS)
1722 return (err);
1723 }
1724
1725 if (pcix_io)
1726 sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV_PCIX, sbname,
1727 (pname[1] - '0'));
1728 else
1729 sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV, sbname,
1730 (pname[1] - '0'));
1731
1732 err = ptree_get_node_by_path(name, &sensorhdl);
1733 if (err == PICL_SUCCESS) {
1734 return (create_table_entry(envtblhdl, sensorhdl,
1735 PICL_CLASS_TEMPERATURE_SENSOR));
1736 }
1737 return (PICL_SUCCESS);
1738 }
1739
1740 /*
1741 * subroutine of add_subtree - get a list of children of a parent node
1742 */
1743 static sgfrunode_t *
get_node_children(fru_hdl_t fruparent,int * num_childrenp)1744 get_node_children(fru_hdl_t fruparent, int *num_childrenp)
1745 {
1746 int max_children, i;
1747 sgfrunode_t *fruchildren = NULL;
1748 child_info_t child_info;
1749 int frufd;
1750
1751 /*
1752 * Open the sgfru pseudo dev
1753 */
1754 if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, 0)) == -1) {
1755 syslog(LOG_ERR, DEV_OPEN_FAIL, FRU_PSEUDO_DEV, strerror(errno));
1756 return (NULL);
1757 }
1758 for (i = 1; i <= MAX_TRIES; i++) {
1759 max_children = i * MAX_NODE_CHILDREN;
1760 if ((fruchildren = calloc(max_children,
1761 sizeof (sgfrunode_t))) == NULL) {
1762 (void) close(frufd);
1763 syslog(LOG_ERR, MALLOC_FAIL);
1764 return (NULL);
1765 }
1766 child_info.fru_hdl = fruparent;
1767 child_info.fru_cnt = max_children;
1768 child_info.frus = (void *)fruchildren;
1769 if (ioctl(frufd, SGFRU_GETCHILDLIST, &child_info) == 0) {
1770 /*
1771 * got them - return success
1772 */
1773 (void) close(frufd);
1774 *num_childrenp = child_info.fru_cnt;
1775 return (fruchildren);
1776 }
1777 free(fruchildren);
1778
1779 /*
1780 * if ENOMEM, need to calloc more space - so go round loop again
1781 * otherwise fail
1782 */
1783 if (errno != ENOMEM) {
1784 (void) close(frufd);
1785 syslog(LOG_ERR, SGFRU_IOCTL_FAIL, SGFRU_GETCHILDLIST,
1786 fruparent, strerror(errno));
1787 return (NULL);
1788 }
1789 }
1790 (void) close(frufd);
1791 syslog(LOG_ERR, MALLOC_FAIL);
1792 return (NULL);
1793 }
1794
1795 /* Creates an unsigned longlong property for a given PICL node */
1796 static int
add_prop_ull(picl_nodehdl_t nodeh,uint64_t handle,char * name)1797 add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name)
1798 {
1799 picl_prophdl_t proph;
1800 ptree_propinfo_t propinfo;
1801 int err;
1802
1803 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1804 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (unsigned long long),
1805 PICL_PROP_SC_HANDLE, NULL, NULL);
1806 if (err != PICL_SUCCESS) {
1807 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
1808 return (err);
1809 }
1810 err = ptree_create_and_add_prop(nodeh, &propinfo, &handle, &proph);
1811 if (err != PICL_SUCCESS) {
1812 syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
1813 return (err);
1814 }
1815 return (PICL_SUCCESS);
1816 }
1817
1818 /* Creates a void property for a given PICL node */
1819 static int
add_prop_void(picl_nodehdl_t nodeh,char * name)1820 add_prop_void(picl_nodehdl_t nodeh, char *name)
1821 {
1822 picl_prophdl_t proph;
1823 ptree_propinfo_t propinfo;
1824 int err;
1825
1826 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1827 PICL_PTYPE_VOID, PICL_READ, 0, PICL_PROP_FRUDATA_AVAIL, NULL, NULL);
1828 if (err != PICL_SUCCESS) {
1829 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
1830 return (err);
1831 }
1832 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
1833 if (err != PICL_SUCCESS) {
1834 syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
1835 return (err);
1836 }
1837 return (PICL_SUCCESS);
1838 }
1839
1840 /* Creates a reference property for a given PICL node */
1841 static int
add_prop_ref(picl_nodehdl_t nodeh,picl_nodehdl_t value,char * name)1842 add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name)
1843 {
1844 picl_prophdl_t proph;
1845 ptree_propinfo_t propinfo;
1846 int err;
1847
1848 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1849 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name,
1850 NULL, NULL);
1851 if (err != PICL_SUCCESS) {
1852 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
1853 return (err);
1854 }
1855 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
1856 if (err != PICL_SUCCESS) {
1857 syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
1858 return (err);
1859 }
1860 return (PICL_SUCCESS);
1861 }
1862
1863 /* Creates an integer property for a given PICL node */
1864 static int
add_prop_int(picl_nodehdl_t nodeh,int value,char * name)1865 add_prop_int(picl_nodehdl_t nodeh, int value, char *name)
1866 {
1867 picl_prophdl_t proph;
1868 ptree_propinfo_t propinfo;
1869 int err;
1870
1871 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1872 PICL_PTYPE_INT, PICL_READ, sizeof (int), name, NULL, NULL);
1873 if (err != PICL_SUCCESS) {
1874 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
1875 return (err);
1876 }
1877 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
1878 if (err != PICL_SUCCESS) {
1879 syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
1880 return (err);
1881 }
1882 return (PICL_SUCCESS);
1883 }
1884
1885 /* Creates an integer property for a given PICL node */
1886 static int
add_prop_float(picl_nodehdl_t nodeh,float value,char * name)1887 add_prop_float(picl_nodehdl_t nodeh, float value, char *name)
1888 {
1889 picl_prophdl_t proph;
1890 ptree_propinfo_t propinfo;
1891 int err;
1892
1893 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1894 PICL_PTYPE_FLOAT, PICL_READ, sizeof (float), name, NULL, NULL);
1895 if (err != PICL_SUCCESS) {
1896 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
1897 return (err);
1898 }
1899 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
1900 if (err != PICL_SUCCESS) {
1901 syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
1902 return (err);
1903 }
1904 return (PICL_SUCCESS);
1905 }
1906
1907 /* Creates a charstring property for a given PICL node */
1908 static int
add_prop_charstring(picl_nodehdl_t nodeh,char * value,char * name)1909 add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name)
1910 {
1911 picl_prophdl_t proph;
1912 ptree_propinfo_t propinfo;
1913 int err;
1914
1915 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1916 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(value) + 1,
1917 name, NULL, NULL);
1918 if (err != PICL_SUCCESS) {
1919 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
1920 return (err);
1921 }
1922 err = ptree_create_and_add_prop(nodeh, &propinfo, value, &proph);
1923 if (err != PICL_SUCCESS) {
1924 syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
1925 return (err);
1926 }
1927 return (PICL_SUCCESS);
1928 }
1929
1930 /* create an entry in the specified table */
1931 static int
create_table_entry(picl_prophdl_t tblhdl,picl_nodehdl_t refhdl,char * class)1932 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
1933 {
1934 int err;
1935 ptree_propinfo_t prop;
1936 picl_prophdl_t prophdl[2];
1937
1938 /* first column is class */
1939 prop.version = PTREE_PROPINFO_VERSION;
1940 prop.piclinfo.type = PICL_PTYPE_CHARSTRING;
1941 prop.piclinfo.accessmode = PICL_READ;
1942 prop.piclinfo.size = PICL_CLASSNAMELEN_MAX;
1943 prop.read = NULL;
1944 prop.write = NULL;
1945 (void) strlcpy(prop.piclinfo.name, PICL_PROP_CLASS,
1946 sizeof (prop.piclinfo.name));
1947 err = ptree_create_prop(&prop, class, &prophdl[0]);
1948 if (err != PICL_SUCCESS) {
1949 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
1950 return (err);
1951 }
1952
1953 /* second column is refernce property */
1954 prop.version = PTREE_PROPINFO_VERSION;
1955 prop.piclinfo.type = PICL_PTYPE_REFERENCE;
1956 prop.piclinfo.accessmode = PICL_READ;
1957 prop.piclinfo.size = sizeof (picl_nodehdl_t);
1958 prop.read = NULL;
1959 prop.write = NULL;
1960 sprintf_buf2(prop.piclinfo.name, "_%s_", class);
1961 err = ptree_create_prop(&prop, &refhdl, &prophdl[1]);
1962 if (err != PICL_SUCCESS) {
1963 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
1964 return (err);
1965 }
1966
1967 /* add row to table */
1968 err = ptree_add_row_to_table(tblhdl, 2, prophdl);
1969 if (err != PICL_SUCCESS)
1970 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
1971 return (err);
1972 }
1973
1974 /* create an empty table property */
1975 static int
create_table(picl_nodehdl_t fruhdl,picl_prophdl_t * tblhdlp,char * tbl_name)1976 create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
1977 {
1978 int err;
1979 ptree_propinfo_t prop;
1980 picl_prophdl_t tblprophdl;
1981
1982 err = ptree_create_table(tblhdlp);
1983 if (err != PICL_SUCCESS) {
1984 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
1985 return (err);
1986 }
1987 prop.version = PTREE_PROPINFO_VERSION;
1988 prop.piclinfo.type = PICL_PTYPE_TABLE;
1989 prop.piclinfo.accessmode = PICL_READ;
1990 prop.piclinfo.size = sizeof (picl_prophdl_t);
1991 prop.read = NULL;
1992 prop.write = NULL;
1993 (void) strlcpy(prop.piclinfo.name, tbl_name,
1994 sizeof (prop.piclinfo.name));
1995 err = ptree_create_and_add_prop(fruhdl, &prop, tblhdlp, &tblprophdl);
1996 if (err != PICL_SUCCESS)
1997 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
1998 return (err);
1999 }
2000
2001 static void
frudr_add_subtree(picl_nodehdl_t parh)2002 frudr_add_subtree(picl_nodehdl_t parh)
2003 {
2004 fru_hdl_t sgfruhdl;
2005 if (ptree_get_propval_by_name(parh, PICL_PROP_SC_HANDLE,
2006 &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
2007 return;
2008 }
2009 (void) add_subtree(parh, sgfruhdl);
2010 }
2011
2012 /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */
2013 /*ARGSUSED*/
2014 static void
frudr_completion_handler(char * ename,void * earg,size_t size)2015 frudr_completion_handler(char *ename, void *earg, size_t size)
2016 {
2017 picl_nodehdl_t fruh;
2018 picl_nodehdl_t parh;
2019
2020 if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
2021 /*
2022 * now frudata has been notified that the node is to be
2023 * removed, we can actually remove it
2024 */
2025 fruh = 0;
2026 (void) nvlist_lookup_uint64(earg,
2027 PICLEVENTARG_FRUHANDLE, &fruh);
2028 if (fruh != 0) {
2029 (void) remove_subtree(fruh);
2030
2031 /*
2032 * Now repopulate the frutree with current data.
2033 */
2034 parh = 0;
2035 (void) nvlist_lookup_uint64(earg,
2036 PICLEVENTARG_PARENTHANDLE, &parh);
2037 if (parh != 0) {
2038 frudr_add_subtree(parh);
2039 }
2040 }
2041 }
2042 nvlist_free(earg);
2043 free(earg);
2044 free(ename);
2045 }
2046
2047 /*
2048 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
2049 */
2050 static void
post_frudr_event(char * ename,picl_nodehdl_t parenth,picl_nodehdl_t fruh)2051 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
2052 {
2053 nvlist_t *nvl;
2054 char *ev_name;
2055
2056 ev_name = strdup(ename);
2057 if (ev_name == NULL)
2058 return;
2059 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) {
2060 free(ev_name);
2061 return;
2062 }
2063 if (parenth != 0L &&
2064 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
2065 free(ev_name);
2066 nvlist_free(nvl);
2067 return;
2068 }
2069 if (fruh != 0L &&
2070 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
2071 free(ev_name);
2072 nvlist_free(nvl);
2073 return;
2074 }
2075 if (ptree_post_event(ev_name, nvl, sizeof (nvl),
2076 frudr_completion_handler) != 0) {
2077 free(ev_name);
2078 nvlist_free(nvl);
2079 }
2080 }
2081
2082 /*
2083 * updates the picl node 'loc' with the new fru handle (PICL_PROP_SC_HANDLE)
2084 * (helper function for frudr_evhandler, when a stale fru handle is
2085 * detected)
2086 */
2087 static void
update_fru_hdl(picl_nodehdl_t loc,fru_hdl_t newsgfruhdl)2088 update_fru_hdl(picl_nodehdl_t loc, fru_hdl_t newsgfruhdl)
2089 {
2090 picl_prophdl_t schproph;
2091 int err;
2092
2093 err = ptree_get_prop_by_name(loc, PICL_PROP_SC_HANDLE, &schproph);
2094 if (err == PICL_SUCCESS) {
2095 if (ptree_delete_prop(schproph) == PICL_SUCCESS) {
2096 (void) ptree_destroy_prop(schproph);
2097 }
2098 }
2099 (void) add_prop_ull(loc, (uint64_t)newsgfruhdl, PICL_PROP_SC_HANDLE);
2100 }
2101
2102 /*
2103 * Get the fru handle of loc by iterating through the parent's children.
2104 * Sets fruhdl and returns PICL_SUCCESS unless an error is encountered.
2105 */
2106 static int
get_fruhdl_from_parent(picl_nodehdl_t loc,fru_hdl_t * fruhdl)2107 get_fruhdl_from_parent(picl_nodehdl_t loc, fru_hdl_t *fruhdl)
2108 {
2109 picl_nodehdl_t parlocnodeh;
2110 fru_hdl_t parsgfruhdl;
2111 sgfrunode_t *cp;
2112 sgfrunode_t *fruchildren;
2113 char nodename[PICL_PROPNAMELEN_MAX];
2114 int err;
2115 int num_children;
2116 int i;
2117
2118 err = ptree_get_propval_by_name(loc, PICL_PROP_NAME, (void *)nodename,
2119 PICL_PROPNAMELEN_MAX);
2120 if (err != PICL_SUCCESS)
2121 return (err);
2122 err = ptree_get_propval_by_name(loc, PICL_PROP_PARENT, &parlocnodeh,
2123 sizeof (picl_nodehdl_t));
2124 if (err != PICL_SUCCESS)
2125 return (err);
2126 if ((err = ptree_get_propval_by_name(parlocnodeh, PICL_PROP_SC_HANDLE,
2127 &parsgfruhdl, sizeof (parsgfruhdl))) != PICL_SUCCESS)
2128 return (err);
2129 /* find children of the parent node */
2130 fruchildren = get_node_children(parsgfruhdl, &num_children);
2131 if (fruchildren == NULL)
2132 return (PICL_FAILURE);
2133 for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
2134 /* find the child we're interested in */
2135 if (strcmp(cp->nodename, nodename) == 0) {
2136 *fruhdl = cp->handle;
2137 free(fruchildren);
2138 return (PICL_SUCCESS);
2139 }
2140 }
2141 free(fruchildren);
2142 return (PICL_FAILURE);
2143 }
2144
2145 /*
2146 * handle EC_DR picl events
2147 */
2148 /*ARGSUSED*/
2149 static void
frudr_evhandler(const char * ename,const void * earg,size_t size,void * cookie)2150 frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
2151 {
2152 nvlist_t *nvlp;
2153 char *dtype;
2154 char *ap_id;
2155 char *hint;
2156 char path[MAXPATHLEN];
2157 picl_nodehdl_t fruh;
2158 picl_nodehdl_t locnodeh;
2159 fru_hdl_t sgfruhdl;
2160 fru_hdl_t sgfruhdl_from_parent;
2161
2162 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0)
2163 return;
2164
2165 if (nvlist_unpack((char *)earg, size, &nvlp, 0))
2166 return;
2167
2168 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
2169 nvlist_free(nvlp);
2170 return;
2171 }
2172
2173 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
2174 nvlist_free(nvlp);
2175 return;
2176 }
2177
2178 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
2179 nvlist_free(nvlp);
2180 return;
2181 }
2182
2183 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
2184 nvlist_free(nvlp);
2185 return;
2186 }
2187
2188 if (strncmp(ap_id, AP_ID_PREAMBLE, AP_ID_PREAMBLE_LEN) != 0) {
2189 nvlist_free(nvlp);
2190 return;
2191 }
2192
2193 /*
2194 * OK - so this is an EC_DR event - let's handle it.
2195 */
2196 sprintf_buf2(path, CHASSIS_LOC_PATH, &ap_id[AP_ID_PREAMBLE_LEN]);
2197
2198 /*
2199 * special case - SSC arrival means that SSC has been reset - we
2200 * need to flush the cached sgfru handles
2201 */
2202 if (strcmp(&ap_id[AP_ID_PREAMBLE_LEN], "SSC1") == 0) {
2203 picl_nodehdl_t chdh;
2204 picl_nodehdl_t peerh;
2205 picl_nodehdl_t parh;
2206 int got_peer;
2207 char label[MAX_LABEL_LEN];
2208 int err;
2209 sgfrunode_t *sgfruchassisp = NULL;
2210 int num_children;
2211 picl_prophdl_t schproph;
2212
2213 /* find existing chassis node */
2214 if (ptree_get_node_by_path(CHASSIS_PATH, &parh) !=
2215 PICL_SUCCESS) {
2216 nvlist_free(nvlp);
2217 return;
2218 }
2219
2220 /* find new chassis sgfru node */
2221 sgfruchassisp = get_node_children(ROOTPARENT, &num_children);
2222 if (sgfruchassisp == NULL || num_children != 1) {
2223 nvlist_free(nvlp);
2224 return;
2225 }
2226
2227 /* update chassis SC_HANDLE property */
2228 err = ptree_get_prop_by_name(parh, PICL_PROP_SC_HANDLE,
2229 &schproph);
2230 if (err != PICL_SUCCESS) {
2231 nvlist_free(nvlp);
2232 return;
2233 }
2234 err = ptree_delete_prop(schproph);
2235 if (err != PICL_SUCCESS) {
2236 nvlist_free(nvlp);
2237 return;
2238 }
2239 (void) ptree_destroy_prop(schproph);
2240 err = add_prop_ull(parh, sgfruchassisp->handle,
2241 PICL_PROP_SC_HANDLE);
2242 if (err != PICL_SUCCESS) {
2243 nvlist_free(nvlp);
2244 return;
2245 }
2246
2247 /*
2248 * remove all subtrees except DISK, TAPE, DVD and PCI subtrees
2249 */
2250 if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh,
2251 sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
2252 for (;;) {
2253 if (ptree_get_propval_by_name(chdh,
2254 PICL_PROP_PEER, &peerh,
2255 sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
2256 got_peer = 0;
2257 else
2258 got_peer = 1;
2259 err = ptree_get_propval_by_name(chdh,
2260 PICL_PROP_LABEL, label, sizeof (label));
2261 if (err == PICL_SUCCESS) {
2262 if (strncmp(label, "DISK",
2263 strlen("DISK")) != 0 &&
2264 strncmp(label, "TAPE",
2265 strlen("TAPE")) != 0 &&
2266 strncmp(label, "PCI",
2267 strlen("PCI")) != 0 &&
2268 strncmp(label, "DVD",
2269 strlen("DVD")) != 0) {
2270 (void) remove_subtree(chdh);
2271 }
2272 }
2273 if (got_peer == 0)
2274 break;
2275 chdh = peerh;
2276 }
2277 }
2278
2279 /* add new subtrees */
2280 (void) add_subtree(parh, sgfruchassisp->handle);
2281 free(sgfruchassisp);
2282
2283 nvlist_free(nvlp);
2284 return;
2285 }
2286
2287 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
2288 nvlist_free(nvlp);
2289 return;
2290 }
2291 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_SC_HANDLE,
2292 &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
2293 nvlist_free(nvlp);
2294 return;
2295 }
2296
2297 /*
2298 * now either add or delete the fru node as appropriate. If no
2299 * hint, treat as insert - add_subtree will update the tree if
2300 * necessary.
2301 */
2302 if (strcmp(hint, DR_HINT_REMOVE) == 0) {
2303 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD,
2304 &fruh, sizeof (picl_nodehdl_t)) != PICL_PROPNOTFOUND) {
2305 /*
2306 * fru was there - but has gone away
2307 */
2308 post_frudr_event(PICL_FRU_REMOVED, locnodeh, fruh);
2309 }
2310 } else {
2311 /*
2312 * fru has been inserted (or may need to update)
2313 *
2314 * sgfruhdl may be stale due to hotplugging. We check this
2315 * by getting the fru_hdl_t from the parent's children
2316 * and compare it to the cached value in sgfruhdl. If we
2317 * have a stale handle, we update the cached value and
2318 * use it in the call to add_subtree.
2319 */
2320 if (get_fruhdl_from_parent(locnodeh, &sgfruhdl_from_parent) ==
2321 PICL_SUCCESS) {
2322 if (sgfruhdl != sgfruhdl_from_parent) {
2323 update_fru_hdl(locnodeh, sgfruhdl_from_parent);
2324 sgfruhdl = sgfruhdl_from_parent;
2325 }
2326 }
2327
2328 (void) add_subtree(locnodeh, sgfruhdl);
2329 }
2330 nvlist_free(nvlp);
2331 }
2332
2333 /*
2334 * handle memcfg picl events - need to update reference properties
2335 */
2336 /*ARGSUSED*/
2337 static void
frumemcfg_evhandler(const char * ename,const void * earg,size_t size,void * cookie)2338 frumemcfg_evhandler(const char *ename, const void *earg, size_t size,
2339 void *cookie)
2340 {
2341 picl_nodehdl_t nodeh;
2342 picl_nodehdl_t lochdl;
2343 picl_nodehdl_t fruhdl;
2344 picl_nodehdl_t memgrphdl;
2345 picl_nodehdl_t memhdl;
2346 picl_prophdl_t tblhdl;
2347 picl_prophdl_t tblproph;
2348 nvlist_t *nvlp;
2349 char addr[MAXPATHLEN];
2350 char bname[PICL_PROPNAMELEN_MAX];
2351 picl_nodehdl_t banklochdl;
2352 picl_nodehdl_t bankfruhdl;
2353 char label[MAX_LABEL_LEN];
2354 int err;
2355 int id;
2356 char *ptr;
2357 int value;
2358 char buf[MAX_LINE_SIZE];
2359
2360 if (strcmp(ename, PICLEVENT_MC_ADDED) != 0 &&
2361 strcmp(ename, PICLEVENT_MC_REMOVED) != 0)
2362 return;
2363
2364 /*
2365 * find corresponding frutree dimm nodes
2366 */
2367 if (nvlist_unpack((char *)earg, size, &nvlp, 0))
2368 return;
2369 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh)) {
2370 nvlist_free(nvlp);
2371 return;
2372 }
2373 nvlist_free(nvlp);
2374 err = ptree_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, addr,
2375 sizeof (addr));
2376 if (err != PICL_SUCCESS)
2377 return;
2378 ptr = strchr(addr, ',');
2379 if (ptr == NULL)
2380 return;
2381 *ptr = '\0';
2382 value = strtol(addr, NULL, 16);
2383 sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value),
2384 SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value),
2385 SAFARI_ADDR_TO_P(value));
2386 err = ptree_get_node_by_path(buf, &fruhdl);
2387 if (err != PICL_SUCCESS)
2388 return;
2389 err = ptree_get_propval_by_name(fruhdl, PICL_PROP_CHILD,
2390 &banklochdl, sizeof (banklochdl));
2391 if (err != PICL_SUCCESS)
2392 return;
2393
2394 /*
2395 * walk through the DIMM locations
2396 */
2397 for (;;) {
2398 err = ptree_get_propval_by_name(banklochdl, PICL_PROP_CHILD,
2399 &bankfruhdl, sizeof (bankfruhdl));
2400 if (err != PICL_SUCCESS)
2401 goto next_bank;
2402 err = ptree_get_propval_by_name(bankfruhdl, PICL_PROP_CHILD,
2403 &lochdl, sizeof (lochdl));
2404 if (err != PICL_SUCCESS)
2405 goto next_bank;
2406 for (;;) {
2407 err = ptree_get_propval_by_name(lochdl, PICL_PROP_CHILD,
2408 &fruhdl, sizeof (fruhdl));
2409 if (err != PICL_SUCCESS)
2410 goto next_dimm;
2411
2412 /*
2413 * this is a frutree dimm node corresponding to the
2414 * memory controller that has been added/deleted
2415 * - so create/delete reference properties
2416 */
2417 if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
2418 /*
2419 * find bank name
2420 */
2421 err = ptree_get_propval_by_name(fruhdl,
2422 PICL_PROP_DEVICES, &tblhdl,
2423 sizeof (tblhdl));
2424 if (err != PICL_SUCCESS)
2425 goto next_dimm;
2426 err = ptree_get_propval_by_name(lochdl,
2427 PICL_PROP_LABEL, label, sizeof (label));
2428 if (err != PICL_SUCCESS)
2429 goto next_dimm;
2430
2431 err = ptree_get_propval_by_name(bankfruhdl,
2432 PICL_PROP_NAME, bname, sizeof (bname));
2433 if (err != PICL_SUCCESS)
2434 goto next_dimm;
2435
2436 /*
2437 * find memory group node
2438 */
2439 err = ptree_get_propval_by_name(nodeh,
2440 PICL_PROP_CHILD, &memgrphdl,
2441 sizeof (memgrphdl));
2442 if (err != PICL_SUCCESS)
2443 goto next_dimm;
2444
2445 /*
2446 * check if this is the right bank - if not
2447 * move on to sibling
2448 */
2449 err = ptree_get_propval_by_name(memgrphdl,
2450 PICL_PROP_ID, &id, sizeof (id));
2451 if (err != PICL_SUCCESS)
2452 goto next_dimm;
2453 if (bname[1] != id + '0') {
2454 err =
2455 ptree_get_propval_by_name(memgrphdl,
2456 PICL_PROP_PEER, &memgrphdl,
2457 sizeof (memgrphdl));
2458 if (err != PICL_SUCCESS)
2459 goto next_dimm;
2460 err =
2461 ptree_get_propval_by_name(memgrphdl,
2462 PICL_PROP_ID, &id, sizeof (id));
2463 if (err != PICL_SUCCESS)
2464 goto next_dimm;
2465 if (bname[1] != id + '0')
2466 goto next_dimm;
2467 }
2468
2469 /*
2470 * got the right bank - now create appropriate
2471 * link
2472 */
2473 err = ptree_get_propval_by_name(memgrphdl,
2474 PICL_PROP_CHILD, &memhdl,
2475 sizeof (memhdl));
2476 if (err != PICL_SUCCESS)
2477 goto next_dimm;
2478 for (;;) {
2479 err = ptree_get_propval_by_name(memhdl,
2480 PICL_PROP_ID, &id, sizeof (id));
2481 if (err != PICL_SUCCESS)
2482 goto next_dimm;
2483 if (label[1] == ('0' + id)) {
2484 err = add_prop_ref(memhdl,
2485 fruhdl,
2486 PICL_REFPROP_FRU_PARENT);
2487 if (err != PICL_SUCCESS)
2488 return;
2489 err = create_table_entry(tblhdl,
2490 memhdl,
2491 PICL_CLASS_MEMORY_MODULE);
2492 if (err != PICL_SUCCESS)
2493 return;
2494 }
2495 err = ptree_get_propval_by_name(memhdl,
2496 PICL_PROP_PEER,
2497 &memhdl, sizeof (memhdl));
2498 if (err == PICL_PROPNOTFOUND)
2499 break;
2500 if (err != PICL_SUCCESS)
2501 return;
2502 }
2503 } else if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0) {
2504 /*
2505 * XXX - no mechanism for deleting row - so
2506 * delete whole tabel and start again
2507 */
2508 err = ptree_get_prop_by_name(fruhdl,
2509 PICL_PROP_DEVICES, &tblproph);
2510 if (err == PICL_SUCCESS) {
2511 err = ptree_delete_prop(tblproph);
2512 if (err != PICL_SUCCESS)
2513 return;
2514 (void) ptree_destroy_prop(tblproph);
2515 }
2516 err = create_table(fruhdl, &tblhdl,
2517 PICL_PROP_DEVICES);
2518 if (err != PICL_SUCCESS)
2519 return;
2520 }
2521 next_dimm:
2522 err = ptree_get_propval_by_name(lochdl,
2523 PICL_PROP_PEER, &lochdl, sizeof (lochdl));
2524 if (err == PICL_PROPNOTFOUND)
2525 break;
2526 if (err != PICL_SUCCESS)
2527 return;
2528 }
2529 next_bank:
2530 err = ptree_get_propval_by_name(banklochdl,
2531 PICL_PROP_PEER, &banklochdl, sizeof (banklochdl));
2532 if (err == PICL_PROPNOTFOUND)
2533 break;
2534 if (err != PICL_SUCCESS)
2535 return;
2536 }
2537 /*
2538 * We don't get an event to say that cpu nodes have been added/
2539 * deleted (in fact as things stand they are never deleted). However
2540 * we know that all cpus must be configured before the MC_ADDED event
2541 * we are handling here. So if the cpu links haven't been set up yet
2542 * then we do it now.
2543 */
2544 if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
2545 sprintf_buf4(buf, PROC_LOC_PATH, SAFARI_ADDR_TO_SB(value),
2546 SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value));
2547 err = ptree_get_node_by_path(buf, &lochdl);
2548 if (err != PICL_SUCCESS)
2549 return;
2550 sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value),
2551 SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value),
2552 SAFARI_ADDR_TO_P(value));
2553 err = ptree_get_node_by_path(buf, &fruhdl);
2554 if (err != PICL_SUCCESS)
2555 return;
2556 sprintf_buf2(buf, "P%d", SAFARI_ADDR_TO_P(value));
2557 err = ptree_get_propval_by_name(fruhdl,
2558 PICL_PROP_DEVICES, &tblhdl, sizeof (tblhdl));
2559 if (err != PICL_SUCCESS)
2560 return;
2561 (void) create_cpu_references(buf, fruhdl, tblhdl);
2562 }
2563 }
2564
2565 /*
2566 * subroutine for add_env_nodes(), and add_led_node(). Adds a sensor
2567 * node under the sc node in the platform tree, of name "nodename" and
2568 * class "class". Also add UnitAddress property (always 0 as the nodenames
2569 * are unique anyway). Add reference property back to parent fru/location node
2570 * in frutree and a Devices table entry pointing to this node from the
2571 * parent fru/location node in frutree.
2572 */
2573 static int
add_sensor_node(picl_nodehdl_t fruhdl,picl_nodehdl_t lochdl,char * nodename,char * class,char * prop_class,picl_prophdl_t tblhdl,picl_nodehdl_t * sensorhdlp)2574 add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl, char *nodename,
2575 char *class, char *prop_class, picl_prophdl_t tblhdl,
2576 picl_nodehdl_t *sensorhdlp)
2577 {
2578 int err;
2579
2580 err = ptree_create_and_add_node(sch, nodename, class, sensorhdlp);
2581 if (err != PICL_SUCCESS) {
2582 syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err);
2583 return (err);
2584 }
2585
2586 err = create_table_entry(tblhdl, *sensorhdlp, class);
2587 if (err != PICL_SUCCESS)
2588 return (err);
2589
2590 err = add_sensor_prop(*sensorhdlp, prop_class);
2591 if (err != PICL_SUCCESS)
2592 return (err);
2593
2594 err = add_prop_charstring(*sensorhdlp, "0", PICL_PROP_UNIT_ADDRESS);
2595 if (err != PICL_SUCCESS)
2596 return (err);
2597
2598 if (fruhdl != 0) {
2599 err = add_prop_ref(*sensorhdlp, fruhdl,
2600 PICL_REFPROP_FRU_PARENT);
2601 } else {
2602 err = add_prop_ref(*sensorhdlp, lochdl,
2603 PICL_REFPROP_LOC_PARENT);
2604 }
2605 return (err);
2606 }
2607
2608 /*
2609 * subroutine for add_sensor_node()/add_env_nodes(). Used for adding dynamic
2610 * properties
2611 */
2612 static int
add_sensor_prop(picl_nodehdl_t nodeh,char * class)2613 add_sensor_prop(picl_nodehdl_t nodeh, char *class)
2614 {
2615 ptree_propinfo_t propinfo;
2616 int err;
2617
2618 if (strcmp(class, PICL_PROP_TEMPERATURE) == 0) {
2619 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2620 PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE,
2621 sizeof (int), class, get_sensor_data, NULL);
2622 } else if (strcmp(class, PICL_PROP_FAN_SPEED) == 0) {
2623 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2624 PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE,
2625 sizeof (int), class, get_sensor_data, NULL);
2626 } else if (strcmp(class, PICL_PROP_FAN_SPEED_UNIT) == 0) {
2627 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2628 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
2629 MAX_SPEED_UNIT_LEN, class, get_sensor_data, NULL);
2630 } else if (strcmp(class, PICL_PROP_CONDITION) == 0) {
2631 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2632 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
2633 MAX_CONDITION_LEN, class, get_sensor_data, NULL);
2634 } else if (strcmp(class, PICL_PROP_STATE) == 0) {
2635 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2636 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_WRITE +
2637 PICL_VOLATILE, MAX_STATE_LEN, class, get_led_data,
2638 set_led_data);
2639 } else {
2640 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2641 PICL_PTYPE_FLOAT, PICL_READ + PICL_VOLATILE,
2642 sizeof (float), class, get_sensor_data, NULL);
2643 }
2644 if (err != PICL_SUCCESS) {
2645 syslog(LOG_ERR, PROPINFO_FAIL, class, err);
2646 return (err);
2647 }
2648
2649 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
2650 if (err != PICL_SUCCESS) {
2651 syslog(LOG_ERR, ADD_PROP_FAIL, class, err);
2652 return (err);
2653 }
2654 return (PICL_SUCCESS);
2655 }
2656
2657 /*
2658 * Get requested kstat
2659 */
2660 static int
open_kstat(char * name,void ** ptr,kstat_ctl_t ** kcp)2661 open_kstat(char *name, void **ptr, kstat_ctl_t **kcp)
2662 {
2663 kstat_t *info_ksp;
2664
2665 *kcp = kstat_open();
2666 if (*kcp == NULL) {
2667 syslog(LOG_ERR, KSTAT_FAIL);
2668 return (PICL_FAILURE);
2669 }
2670 info_ksp = kstat_lookup(*kcp, NULL, -1, name);
2671 if (info_ksp == NULL) {
2672 kstat_close(*kcp);
2673 syslog(LOG_ERR, KSTAT_FAIL);
2674 return (PICL_FAILURE);
2675 }
2676 if (kstat_read(*kcp, info_ksp, NULL) == -1) {
2677 kstat_close(*kcp);
2678 syslog(LOG_ERR, KSTAT_FAIL);
2679 return (PICL_FAILURE);
2680 }
2681 *ptr = info_ksp;
2682 return (PICL_SUCCESS);
2683 }
2684
2685 /*
2686 * dimm status - uses bank-status property on memory-controller node
2687 */
2688
2689 static int
get_dimm_status(ptree_rarg_t * arg,void * result)2690 get_dimm_status(ptree_rarg_t *arg, void *result)
2691 {
2692 int err;
2693 int i;
2694 picl_prophdl_t tblhdl;
2695 picl_prophdl_t nextprop;
2696 picl_prophdl_t refprop;
2697 picl_prophdl_t mmgprop;
2698 picl_prophdl_t mcprop;
2699 picl_prophdl_t bankprop;
2700 char nodename[PICL_PROPNAMELEN_MAX];
2701 char class[PICL_CLASSNAMELEN_MAX];
2702 char bankname[PICL_PROPNAMELEN_MAX];
2703 char state[MAX_STATE_SIZE];
2704
2705 /*
2706 * find the name of this node
2707 */
2708 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, nodename,
2709 sizeof (nodename));
2710 if (err != PICL_SUCCESS) {
2711 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
2712 return (err);
2713 }
2714
2715 /*
2716 * find the name of grandparent (dimm bank) node
2717 */
2718 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &bankprop,
2719 sizeof (picl_nodehdl_t));
2720 if (err != PICL_SUCCESS) {
2721 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
2722 return (err);
2723 }
2724 err = ptree_get_propval_by_name(bankprop, PICL_PROP_PARENT, &bankprop,
2725 sizeof (picl_nodehdl_t));
2726 if (err != PICL_SUCCESS) {
2727 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
2728 return (err);
2729 }
2730 err = ptree_get_propval_by_name(bankprop, PICL_PROP_NAME, bankname,
2731 sizeof (bankname));
2732 if (err != PICL_SUCCESS) {
2733 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
2734 return (err);
2735 }
2736
2737 /*
2738 * lookup memory-module node in Devices table
2739 */
2740 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl,
2741 sizeof (tblhdl));
2742 if (err != PICL_SUCCESS) {
2743 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err);
2744 return (err);
2745 }
2746 err = ptree_get_next_by_row(tblhdl, &nextprop);
2747 if (err != PICL_SUCCESS) {
2748 /*
2749 * if Devices table empty then dimm is unconfigured
2750 */
2751 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2752 MAX_OPERATIONAL_STATUS_LEN);
2753 return (PICL_SUCCESS);
2754 }
2755 err = ptree_get_next_by_row(nextprop, &nextprop);
2756 if (err != PICL_SUCCESS) {
2757 syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err);
2758 return (err);
2759 }
2760
2761 /*
2762 * walk down second column (ref ptr)
2763 */
2764 while (err == PICL_SUCCESS) {
2765 err = ptree_get_propval(nextprop, &refprop, sizeof (refprop));
2766 if (err != PICL_SUCCESS) {
2767 syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
2768 return (PICL_PROPVALUNAVAILABLE);
2769 }
2770 err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME,
2771 class, sizeof (class));
2772 if (err == PICL_SUCCESS && strcmp(class,
2773 PICL_CLASS_MEMORY_MODULE) == 0)
2774 break;
2775 if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) {
2776 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME,
2777 err);
2778 return (err);
2779 }
2780 err = ptree_get_next_by_col(nextprop, &nextprop);
2781 if (err != PICL_SUCCESS) {
2782 /*
2783 * if no memory-module in Devices table
2784 * then dimm is unconfigured
2785 */
2786 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2787 MAX_OPERATIONAL_STATUS_LEN);
2788 return (PICL_SUCCESS);
2789 }
2790 }
2791
2792 /*
2793 * we've finally found the associated memory-module
2794 * node. Now need to find the bank-status property on
2795 * its parent memory-controller.
2796 */
2797 err = ptree_get_propval_by_name(refprop, PICL_PROP_PARENT,
2798 &mmgprop, sizeof (picl_nodehdl_t));
2799 if (err != PICL_SUCCESS) {
2800 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
2801 return (err);
2802 }
2803 err = ptree_get_propval_by_name(mmgprop, PICL_PROP_PARENT, &mcprop,
2804 sizeof (picl_nodehdl_t));
2805 if (err != PICL_SUCCESS) {
2806 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
2807 return (err);
2808 }
2809 err = ptree_get_propval_by_name(mcprop, PICL_PROP_BANK_STATUS, &tblhdl,
2810 sizeof (tblhdl));
2811 if (err != PICL_SUCCESS) {
2812 (void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
2813 MAX_OPERATIONAL_STATUS_LEN);
2814 return (PICL_SUCCESS);
2815 }
2816
2817 /*
2818 * bank-status is a table. Need to find the entry corresponding
2819 * to this node
2820 */
2821 err = ptree_get_next_by_row(tblhdl, &nextprop);
2822 if (err != PICL_SUCCESS) {
2823 (void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
2824 MAX_OPERATIONAL_STATUS_LEN);
2825 return (PICL_SUCCESS);
2826 }
2827 for (i = 0; i < 4; i++) {
2828 err = ptree_get_propval(nextprop, &state, sizeof (state));
2829 if (err != PICL_SUCCESS) {
2830 (void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
2831 MAX_OPERATIONAL_STATUS_LEN);
2832 return (err);
2833 }
2834 if ((i & 1) == (bankname[1] - '0')) {
2835 if (strcmp(state, "pass") == 0) {
2836 (void) strlcpy(result, PICL_PROPVAL_OKAY,
2837 MAX_OPERATIONAL_STATUS_LEN);
2838 } else if (strcmp(state, "fail") == 0) {
2839 (void) strlcpy(result, PICL_PROPVAL_FAILED,
2840 MAX_OPERATIONAL_STATUS_LEN);
2841 } else {
2842 (void) strlcpy(result, state,
2843 MAX_OPERATIONAL_STATUS_LEN);
2844 }
2845 break;
2846 }
2847 err = ptree_get_next_by_col(nextprop, &nextprop);
2848 if (err != PICL_SUCCESS) {
2849 (void) strlcpy(result, PICL_PROPVAL_OKAY,
2850 MAX_OPERATIONAL_STATUS_LEN);
2851 break;
2852 }
2853 }
2854 return (PICL_SUCCESS);
2855 }
2856
2857 /*
2858 * cpu status - uses State property on cpu node
2859 */
2860
2861 static int
get_cpu_status(ptree_rarg_t * arg,void * result)2862 get_cpu_status(ptree_rarg_t *arg, void *result)
2863 {
2864 int err;
2865 picl_prophdl_t tblhdl;
2866 picl_prophdl_t nextprop;
2867 picl_prophdl_t refprop;
2868 char class[PICL_CLASSNAMELEN_MAX];
2869 char state[MAX_STATE_SIZE];
2870
2871 /*
2872 * lookup cpu node in Devices table
2873 */
2874 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl,
2875 sizeof (tblhdl));
2876 if (err != PICL_SUCCESS) {
2877 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err);
2878 return (err);
2879 }
2880 err = ptree_get_next_by_row(tblhdl, &nextprop);
2881 if (err != PICL_SUCCESS) {
2882 /*
2883 * if Devices table empty then cpu is unconfigured
2884 */
2885 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2886 MAX_OPERATIONAL_STATUS_LEN);
2887 return (PICL_SUCCESS);
2888 }
2889 err = ptree_get_next_by_row(nextprop, &nextprop);
2890 if (err != PICL_SUCCESS) {
2891 syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err);
2892 return (err);
2893 }
2894
2895 /*
2896 * walk down second column (ref ptr)
2897 */
2898 while (err == PICL_SUCCESS) {
2899 err = ptree_get_propval(nextprop, &refprop, sizeof (refprop));
2900 if (err != PICL_SUCCESS) {
2901 syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
2902 return (err);
2903 }
2904 err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME,
2905 class, sizeof (class));
2906 if (err == PICL_SUCCESS && strcmp(class, PICL_CLASS_CPU) == 0)
2907 break;
2908 if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) {
2909 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME,
2910 err);
2911 return (err);
2912 }
2913 err = ptree_get_next_by_col(nextprop, &nextprop);
2914 if (err != PICL_SUCCESS) {
2915 /*
2916 * if no cpu in Devices table
2917 * then cpu is unconfigured
2918 */
2919 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2920 MAX_OPERATIONAL_STATUS_LEN);
2921 return (PICL_SUCCESS);
2922 }
2923 }
2924
2925 /*
2926 * we've finally found the associated cpu node. Now need to find its
2927 * status property if present (if not assume OK)
2928 */
2929 err = ptree_get_propval_by_name(refprop, OBP_STATUS,
2930 state, sizeof (state));
2931 if (err == PICL_SUCCESS) {
2932 if (strcmp(state, "fail") == 0)
2933 (void) strlcpy(result, PICL_PROPVAL_FAILED,
2934 MAX_OPERATIONAL_STATUS_LEN);
2935 else
2936 (void) strlcpy(result, state,
2937 MAX_OPERATIONAL_STATUS_LEN);
2938 return (PICL_SUCCESS);
2939 }
2940
2941 (void) strlcpy(result, PICL_PROPVAL_OKAY, MAX_OPERATIONAL_STATUS_LEN);
2942 return (PICL_SUCCESS);
2943 }
2944
2945 /*
2946 * system/io board condition - uses sgenv driver kstats
2947 */
2948
2949 static int
get_board_status(ptree_rarg_t * arg,void * result)2950 get_board_status(ptree_rarg_t *arg, void *result)
2951 {
2952 int err = PICL_SUCCESS;
2953 int i;
2954 sg_board_info_t *brd;
2955 char name[PICL_PROPNAMELEN_MAX];
2956 char buf[PICL_PROPNAMELEN_MAX];
2957 kstat_ctl_t *kc;
2958 kstat_t *board_info_ksp;
2959
2960 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
2961 sizeof (name));
2962 if (err != PICL_SUCCESS) {
2963 return (err);
2964 }
2965
2966 err = open_kstat(SG_BOARD_STATUS_KSTAT_NAME, (void **)&board_info_ksp,
2967 &kc);
2968 if (err != PICL_SUCCESS) {
2969 return (err);
2970 }
2971
2972 brd = board_info_ksp->ks_data;
2973 for (i = 0; i < SGENV_NUM_BOARD_READINGS(board_info_ksp); i++, brd++) {
2974 /*
2975 * check this kstat matches the name of the node
2976 */
2977 if (SG_BOARD_IS_CPU_TYPE(brd->board_num)) {
2978 sprintf_buf3(buf, "%s%d",
2979 SG_HPU_TYPE_CPU_BOARD_ID, brd->board_num);
2980 } else {
2981 sprintf_buf3(buf, "%s%d",
2982 SG_HPU_TYPE_PCI_IO_BOARD_ID, brd->board_num);
2983 }
2984 if (strncmp(buf, name, strlen(buf)) != 0)
2985 continue;
2986
2987 /*
2988 * ok - got the right kstat - get it's value
2989 * note that values 0-4 are defined in sbdp_mbox.h
2990 */
2991 if (brd->condition >= 0 && brd->condition < 5)
2992 (void) strlcpy(result,
2993 hpu_condition_table[brd->condition],
2994 MAX_OPERATIONAL_STATUS_LEN);
2995 kstat_close(kc);
2996 return (PICL_SUCCESS);
2997 }
2998 kstat_close(kc);
2999 return (PICL_PROPVALUNAVAILABLE);
3000 }
3001
3002 static int
get_op_status(ptree_rarg_t * arg,void * result)3003 get_op_status(ptree_rarg_t *arg, void *result)
3004 {
3005 int err = PICL_SUCCESS;
3006 char name[PICL_PROPNAMELEN_MAX];
3007 char value[MAX_STATE_LEN];
3008 char parent_name[PICL_PROPNAMELEN_MAX];
3009 picl_nodehdl_t loch;
3010 picl_nodehdl_t parentfruh;
3011
3012 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3013 sizeof (name));
3014 if (err != PICL_SUCCESS) {
3015 return (err);
3016 }
3017
3018 /*
3019 * handle dimms, cpus and system boards specially
3020 */
3021 if (IS_PROC_NODE(name)) {
3022 return (get_cpu_status(arg, result));
3023 } else if (IS_DIMM_NODE(name)) {
3024 return (get_dimm_status(arg, result));
3025 } else if (IS_SB_NODE(name) || IS_IB_NODE(name)) {
3026 return (get_board_status(arg, result));
3027 }
3028
3029 /*
3030 * otherwise OperationalStatus is derived from the fault led state
3031 */
3032
3033 /*
3034 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
3035 */
3036 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &loch,
3037 sizeof (loch));
3038 if (err != PICL_SUCCESS)
3039 return (PICL_PROPVALUNAVAILABLE);
3040 err = ptree_get_propval_by_name(loch, PICL_PROP_PARENT, &parentfruh,
3041 sizeof (parentfruh));
3042 if (err != PICL_SUCCESS)
3043 return (PICL_PROPVALUNAVAILABLE);
3044 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, parent_name,
3045 sizeof (parent_name));
3046 if (err != PICL_SUCCESS)
3047 return (PICL_PROPVALUNAVAILABLE);
3048 if (strcmp(name, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0) {
3049 if (get_led("FAN8", FAULT_LED, value) != PICL_SUCCESS) {
3050 return (PICL_PROPVALUNAVAILABLE);
3051 }
3052 } else if (strcmp(name, "FAN1") == 0 && strcmp(parent_name,
3053 "IB6") == 0) {
3054 if (get_led("FAN9", FAULT_LED, value) != PICL_SUCCESS) {
3055 return (PICL_PROPVALUNAVAILABLE);
3056 }
3057 } else {
3058 if (get_led(name, FAULT_LED, value) != PICL_SUCCESS) {
3059 return (PICL_PROPVALUNAVAILABLE);
3060 }
3061 }
3062 if (strcmp(value, PICL_PROPVAL_ON) == 0)
3063 (void) strlcpy(result, PICL_PROPVAL_FAILED,
3064 MAX_OPERATIONAL_STATUS_LEN);
3065 else
3066 (void) strlcpy(result, PICL_PROPVAL_OKAY,
3067 MAX_OPERATIONAL_STATUS_LEN);
3068 return (PICL_SUCCESS);
3069 }
3070
3071 static int
add_board_status(picl_nodehdl_t nodeh,char * nodename)3072 add_board_status(picl_nodehdl_t nodeh, char *nodename)
3073 {
3074 ptree_propinfo_t propinfo;
3075 int err;
3076 picl_prophdl_t prophdl;
3077
3078 /*
3079 * check if OperationalStatus property already created for this fru
3080 */
3081 err = ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
3082 &prophdl);
3083 if (err == PICL_SUCCESS)
3084 return (PICL_SUCCESS);
3085
3086 /*
3087 * put operational status on dimms, cpus, SBs, IBs, PSUs, FTs, Fans, RPs
3088 */
3089 if (IS_DIMM_NODE(nodename) || IS_PROC_NODE(nodename) ||
3090 IS_SB_NODE(nodename) || IS_IB_NODE(nodename) ||
3091 IS_PSU_NODE(nodename) || IS_FT_NODE(nodename) ||
3092 IS_FAN_NODE(nodename) || IS_RP_NODE(nodename)) {
3093 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
3094 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
3095 MAX_OPERATIONAL_STATUS_LEN, PICL_PROP_OPERATIONAL_STATUS,
3096 get_op_status, NULL);
3097 if (err != PICL_SUCCESS) {
3098 syslog(LOG_ERR, PROPINFO_FAIL,
3099 PICL_PROP_OPERATIONAL_STATUS, err);
3100 return (err);
3101 }
3102 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
3103 if (err != PICL_SUCCESS) {
3104 syslog(LOG_ERR, ADD_PROP_FAIL,
3105 PICL_PROP_OPERATIONAL_STATUS, err);
3106 return (err);
3107 }
3108 }
3109 return (PICL_SUCCESS);
3110 }
3111
3112 /*
3113 * environmental information handling - uses sgenv driver kstats
3114 */
3115
3116 static int
add_env_nodes(picl_nodehdl_t nodeh,char * nodename,picl_prophdl_t tblhdl)3117 add_env_nodes(picl_nodehdl_t nodeh, char *nodename, picl_prophdl_t tblhdl)
3118 {
3119 int err = PICL_SUCCESS;
3120 env_sensor_t *env;
3121 int i;
3122 picl_prophdl_t tblhdl2;
3123 picl_prophdl_t frutype;
3124 char fruname[PICL_PROPNAMELEN_MAX];
3125 char buf[PICL_PROPNAMELEN_MAX];
3126 char id[PICL_PROPNAMELEN_MAX];
3127 float scale;
3128 picl_nodehdl_t childh;
3129 picl_nodehdl_t sensorhdl;
3130 kstat_ctl_t *kc;
3131 kstat_t *env_info_ksp;
3132
3133 err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
3134 if (err != PICL_SUCCESS) {
3135 return (err);
3136 }
3137
3138 env = env_info_ksp->ks_data;
3139 for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
3140 /*
3141 * check values from kstat entry are within valid range
3142 */
3143 if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT)
3144 continue;
3145 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB)
3146 continue;
3147 if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC)
3148 continue;
3149 if ((env->sd_id.id.hpu_type >> 8) >=
3150 (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8))
3151 continue;
3152 if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT)
3153 continue;
3154
3155 /*
3156 * does this kstat entry belong to this fru?
3157 * Note sc reports RPS as 10 and 12 via env messages
3158 * but by 0 and 2 via fru messages, so correct here
3159 */
3160 if ((env->sd_id.id.hpu_type >> 8) ==
3161 (SG_HPU_TYPE_REPEATER_BOARD >> 8)) {
3162 sprintf_buf3(fruname, "%s%d",
3163 hpu_type_table[env->sd_id.id.hpu_type >> 8],
3164 env->sd_id.id.hpu_slot - 10);
3165 } else {
3166 sprintf_buf3(fruname, "%s%d",
3167 hpu_type_table[env->sd_id.id.hpu_type >> 8],
3168 env->sd_id.id.hpu_slot);
3169 }
3170 if (strcmp(nodename, fruname) != 0)
3171 continue;
3172
3173 /*
3174 * set up FRUType. Note we only want to do this once per fru
3175 */
3176 err = ptree_get_prop_by_name(nodeh, PICL_PROP_FRU_TYPE,
3177 &frutype);
3178 if (err != PICL_SUCCESS) {
3179 err = add_prop_charstring(nodeh,
3180 hpu_fru_type_table[env->sd_id.id.hpu_type >> 8],
3181 PICL_PROP_FRU_TYPE);
3182 if (err != PICL_SUCCESS)
3183 goto done;
3184 }
3185
3186 /*
3187 * create the sensor node with a sensible name
3188 */
3189 switch (env->sd_id.id.sensor_type) {
3190 case SG_SENSOR_TYPE_TEMPERATURE:
3191 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
3192 sprintf_buf2(id, "t_ambient%d",
3193 env->sd_id.id.sensor_typenum);
3194 } else {
3195 sprintf_buf3(id, "t_%s%d",
3196 hpu_part_table[env->sd_id.id.sensor_part],
3197 env->sd_id.id.sensor_partnum);
3198 }
3199 break;
3200 case SG_SENSOR_TYPE_CURRENT:
3201 sprintf_buf3(id, "i_%s%d",
3202 hpu_part_table[env->sd_id.id.sensor_part],
3203 env->sd_id.id.sensor_partnum);
3204 break;
3205 case SG_SENSOR_TYPE_COOLING:
3206 sprintf_buf3(id, "ft_%s%d",
3207 hpu_part_table[env->sd_id.id.sensor_part],
3208 env->sd_id.id.sensor_partnum);
3209 break;
3210 default: /* voltage */
3211 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
3212 sprintf_buf3(id, "v_%s%d",
3213 hpu_sensor_table[env->sd_id.id.sensor_type],
3214 env->sd_id.id.sensor_typenum);
3215 } else {
3216 sprintf_buf3(id, "v_%s%d",
3217 hpu_part_table[env->sd_id.id.sensor_part],
3218 env->sd_id.id.sensor_partnum);
3219 }
3220 break;
3221 }
3222
3223 /*
3224 * check if sensor node has already been created
3225 */
3226 sprintf_buf3(buf, "%s_%s", nodename, id);
3227 if (find_child_by_name(sch, buf) != 0)
3228 continue;
3229
3230 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_COOLING) {
3231 /*
3232 * create individual fan_unit nodes
3233 */
3234 childh = nodeh;
3235 sprintf_buf2(fruname, "FAN%d",
3236 env->sd_id.id.sensor_partnum);
3237 err = add_intermediate_nodes(&childh, fruname,
3238 &tblhdl2, "fan-unit", "FAN");
3239 if (err != PICL_SUCCESS)
3240 goto done;
3241 err = add_board_status(childh, fruname);
3242 if (err != PICL_SUCCESS)
3243 goto done;
3244 } else if (env->sd_id.id.sensor_part ==
3245 SG_SENSOR_PART_CHEETAH ||
3246 ((env->sd_id.id.hpu_type >> 8) ==
3247 (SG_HPU_TYPE_CPU_BOARD >> 8) &&
3248 (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_TEMPERATURE) &&
3249 (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD))) {
3250 /*
3251 * put sensors under individual processor nodes
3252 */
3253 childh = nodeh;
3254 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD)
3255 sprintf_buf2(fruname, "P%d",
3256 env->sd_id.id.sensor_typenum);
3257 else
3258 sprintf_buf2(fruname, "P%d",
3259 env->sd_id.id.sensor_partnum);
3260 err = add_intermediate_nodes(&childh, fruname,
3261 &tblhdl2, "cpu", "PROC");
3262 if (err != PICL_SUCCESS)
3263 goto done;
3264 } else {
3265 childh = nodeh;
3266 tblhdl2 = tblhdl;
3267 }
3268 err = add_sensor_node(childh, 0, buf,
3269 hpu_sensor_class_table[env->sd_id.id.sensor_type],
3270 hpu_sensor_prop_table[env->sd_id.id.sensor_type],
3271 tblhdl2, &sensorhdl);
3272 if (err != PICL_SUCCESS)
3273 goto done;
3274
3275 /*
3276 * add additional properties
3277 */
3278 switch (env->sd_id.id.sensor_type) {
3279 case SG_SENSOR_TYPE_COOLING:
3280 err = add_prop_charstring(sensorhdl, id,
3281 PICL_PROP_LABEL);
3282 if (err != PICL_SUCCESS)
3283 goto done;
3284 /*
3285 * add threshold at 75% of full speed
3286 */
3287 err = add_prop_int(sensorhdl, 75,
3288 PICL_PROP_LOW_WARNING_THRESHOLD);
3289 if (err != PICL_SUCCESS)
3290 goto done;
3291 err = add_sensor_prop(sensorhdl,
3292 PICL_PROP_FAN_SPEED_UNIT);
3293 if (err != PICL_SUCCESS)
3294 goto done;
3295 continue;
3296 case SG_SENSOR_TYPE_TEMPERATURE:
3297 if ((env->sd_id.id.hpu_type >> 8 ==
3298 (SG_HPU_TYPE_CPU_BOARD >> 8)) &&
3299 (env->sd_id.id.sensor_part ==
3300 SG_SENSOR_PART_BOARD)) {
3301 err = add_prop_charstring(sensorhdl,
3302 PICL_PROPVAL_AMBIENT, PICL_PROP_LABEL);
3303 if (err != PICL_SUCCESS)
3304 goto done;
3305 } else if (env->sd_id.id.sensor_part ==
3306 SG_SENSOR_PART_CHEETAH) {
3307 err = add_prop_charstring(sensorhdl,
3308 PICL_PROPVAL_DIE, PICL_PROP_LABEL);
3309 if (err != PICL_SUCCESS)
3310 goto done;
3311 } else {
3312 err = add_prop_charstring(sensorhdl, id,
3313 PICL_PROP_LABEL);
3314 if (err != PICL_SUCCESS)
3315 goto done;
3316 }
3317 err = add_prop_int(sensorhdl, env->sd_lo_warn /
3318 SG_TEMPERATURE_SCALE, PICL_PROP_LOW_WARNING);
3319 if (err != PICL_SUCCESS)
3320 goto done;
3321 err = add_prop_int(sensorhdl, env->sd_lo /
3322 SG_TEMPERATURE_SCALE, PICL_PROP_LOW_SHUTDOWN);
3323 if (err != PICL_SUCCESS)
3324 goto done;
3325 err = add_prop_int(sensorhdl, env->sd_hi_warn /
3326 SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_WARNING);
3327 if (err != PICL_SUCCESS)
3328 goto done;
3329 err = add_prop_int(sensorhdl, env->sd_hi /
3330 SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_SHUTDOWN);
3331 if (err != PICL_SUCCESS)
3332 goto done;
3333 continue;
3334 case SG_SENSOR_TYPE_1_5_VDC:
3335 scale = SG_1_5_VDC_SCALE;
3336 break;
3337 case SG_SENSOR_TYPE_1_8_VDC:
3338 scale = SG_1_8_VDC_SCALE;
3339 break;
3340 case SG_SENSOR_TYPE_2_5_VDC:
3341 scale = SG_2_5_VDC_SCALE;
3342 break;
3343 case SG_SENSOR_TYPE_3_3_VDC:
3344 scale = SG_3_3_VDC_SCALE;
3345 break;
3346 case SG_SENSOR_TYPE_5_VDC:
3347 scale = SG_5_VDC_SCALE;
3348 break;
3349 case SG_SENSOR_TYPE_12_VDC:
3350 scale = SG_12_VDC_SCALE;
3351 break;
3352 case SG_SENSOR_TYPE_48_VDC:
3353 /*
3354 * The 48VDC sensor is just an indicator - doesn't
3355 * give reading or thresholds
3356 */
3357 err = add_prop_charstring(sensorhdl, id,
3358 PICL_PROP_LABEL);
3359 if (err != PICL_SUCCESS)
3360 goto done;
3361 continue;
3362 case SG_SENSOR_TYPE_CURRENT:
3363 scale = SG_CURRENT_SCALE;
3364 break;
3365 }
3366 err = add_prop_charstring(sensorhdl, id, PICL_PROP_LABEL);
3367 if (err != PICL_SUCCESS)
3368 goto done;
3369 err = add_prop_float(sensorhdl, (float)env->sd_lo_warn / scale,
3370 PICL_PROP_LOW_WARNING);
3371 if (err != PICL_SUCCESS)
3372 goto done;
3373 err = add_prop_float(sensorhdl, (float)env->sd_lo / scale,
3374 PICL_PROP_LOW_SHUTDOWN);
3375 if (err != PICL_SUCCESS)
3376 goto done;
3377 err = add_prop_float(sensorhdl, (float)env->sd_hi_warn / scale,
3378 PICL_PROP_HIGH_WARNING);
3379 if (err != PICL_SUCCESS)
3380 goto done;
3381 err = add_prop_float(sensorhdl, (float)env->sd_hi / scale,
3382 PICL_PROP_HIGH_SHUTDOWN);
3383 if (err != PICL_SUCCESS)
3384 goto done;
3385 }
3386 done:
3387 kstat_close(kc);
3388 return (err);
3389 }
3390
3391 static int
get_sensor_data(ptree_rarg_t * arg,void * result)3392 get_sensor_data(ptree_rarg_t *arg, void *result)
3393 {
3394 int err; /* return code */
3395 kstat_ctl_t *kc;
3396 char name[PICL_PROPNAMELEN_MAX];
3397 ptree_propinfo_t propinfo;
3398 int i;
3399 env_sensor_t *env;
3400 char buf[PICL_PROPNAMELEN_MAX];
3401 char buf1[PICL_PROPNAMELEN_MAX];
3402 kstat_t *env_info_ksp;
3403
3404 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3405 sizeof (name));
3406 if (err != PICL_SUCCESS)
3407 return (err);
3408 err = ptree_get_propinfo(arg->proph, &propinfo);
3409 if (err != PICL_SUCCESS)
3410 return (err);
3411
3412 err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
3413 if (err != PICL_SUCCESS) {
3414 return (err);
3415 }
3416
3417 env = env_info_ksp->ks_data;
3418 for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
3419 /*
3420 * check kstat values are within range
3421 */
3422 if (SG_INFO_VALUESTATUS(env->sd_infostamp) != SG_INFO_VALUE_OK)
3423 continue;
3424 if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT)
3425 continue;
3426 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB)
3427 continue;
3428 if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC)
3429 continue;
3430 if ((env->sd_id.id.hpu_type >> 8) >=
3431 (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8))
3432 continue;
3433 if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT)
3434 continue;
3435
3436 /*
3437 * check this kstat matches the name of the node
3438 * note sc reports RPS as 10 and 12 via env messages
3439 * but by 0 and 2 via fru messages, so correct here
3440 */
3441 if ((env->sd_id.id.hpu_type >> 8) ==
3442 (SG_HPU_TYPE_REPEATER_BOARD >> 8))
3443 sprintf_buf3(buf, "%s%d",
3444 hpu_type_table[env->sd_id.id.hpu_type >> 8],
3445 env->sd_id.id.hpu_slot - 10);
3446 else
3447 sprintf_buf3(buf, "%s%d",
3448 hpu_type_table[env->sd_id.id.hpu_type >> 8],
3449 env->sd_id.id.hpu_slot);
3450 switch (env->sd_id.id.sensor_type) {
3451 case SG_SENSOR_TYPE_TEMPERATURE:
3452 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
3453 sprintf_buf3(buf1, "%s_t_ambient%d",
3454 buf, env->sd_id.id.sensor_typenum);
3455 } else {
3456 sprintf_buf4(buf1, "%s_t_%s%d", buf,
3457 hpu_part_table[env->sd_id.id.sensor_part],
3458 env->sd_id.id.sensor_partnum);
3459 }
3460 break;
3461 case SG_SENSOR_TYPE_CURRENT:
3462 sprintf_buf4(buf1, "%s_i_%s%d", buf,
3463 hpu_part_table[env->sd_id.id.sensor_part],
3464 env->sd_id.id.sensor_partnum);
3465 break;
3466 case SG_SENSOR_TYPE_COOLING:
3467 sprintf_buf4(buf1, "%s_ft_%s%d", buf,
3468 hpu_part_table[env->sd_id.id.sensor_part],
3469 env->sd_id.id.sensor_partnum);
3470 break;
3471 default: /* voltage */
3472 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
3473 sprintf_buf4(buf1, "%s_v_%s%d", buf,
3474 hpu_sensor_table[env->sd_id.id.sensor_type],
3475 env->sd_id.id.sensor_typenum);
3476 } else {
3477 sprintf_buf4(buf1, "%s_v_%s%d", buf,
3478 hpu_part_table[env->sd_id.id.sensor_part],
3479 env->sd_id.id.sensor_partnum);
3480 }
3481 break;
3482 }
3483 if (strcmp(buf1, name) != 0)
3484 continue;
3485
3486 /*
3487 * ok - this is the kstat we want - update
3488 * Condition, or sensor reading as requested
3489 */
3490 if (strcmp(propinfo.piclinfo.name, PICL_PROP_CONDITION) == 0) {
3491 switch (SG_GET_SENSOR_STATUS(env->sd_status)) {
3492 case SG_SENSOR_STATUS_OK:
3493 (void) strlcpy(result, PICL_PROPVAL_OKAY,
3494 MAX_CONDITION_LEN);
3495 break;
3496 case SG_SENSOR_STATUS_LO_WARN:
3497 case SG_SENSOR_STATUS_HI_WARN:
3498 (void) strlcpy(result, PICL_PROPVAL_WARNING,
3499 MAX_CONDITION_LEN);
3500 break;
3501 case SG_SENSOR_STATUS_LO_DANGER:
3502 case SG_SENSOR_STATUS_HI_DANGER:
3503 (void) strlcpy(result, PICL_PROPVAL_FAILED,
3504 MAX_CONDITION_LEN);
3505 break;
3506 default:
3507 kstat_close(kc);
3508 return (PICL_PROPVALUNAVAILABLE);
3509 }
3510 kstat_close(kc);
3511 return (PICL_SUCCESS);
3512 }
3513 switch (env->sd_id.id.sensor_type) {
3514 case SG_SENSOR_TYPE_TEMPERATURE:
3515 *(int *)result = env->sd_value / SG_TEMPERATURE_SCALE;
3516 break;
3517 case SG_SENSOR_TYPE_1_5_VDC:
3518 *(float *)result =
3519 (float)env->sd_value / (float)SG_1_5_VDC_SCALE;
3520 break;
3521 case SG_SENSOR_TYPE_1_8_VDC:
3522 *(float *)result =
3523 (float)env->sd_value / (float)SG_1_8_VDC_SCALE;
3524 break;
3525 case SG_SENSOR_TYPE_2_5_VDC:
3526 *(float *)result =
3527 (float)env->sd_value / (float)SG_2_5_VDC_SCALE;
3528 break;
3529 case SG_SENSOR_TYPE_3_3_VDC:
3530 *(float *)result =
3531 (float)env->sd_value / (float)SG_3_3_VDC_SCALE;
3532 break;
3533 case SG_SENSOR_TYPE_5_VDC:
3534 *(float *)result =
3535 (float)env->sd_value / (float)SG_5_VDC_SCALE;
3536 break;
3537 case SG_SENSOR_TYPE_12_VDC:
3538 *(float *)result =
3539 (float)env->sd_value / (float)SG_12_VDC_SCALE;
3540 break;
3541 case SG_SENSOR_TYPE_CURRENT:
3542 *(float *)result =
3543 (float)env->sd_value / (float)SG_CURRENT_SCALE;
3544 break;
3545 case SG_SENSOR_TYPE_COOLING:
3546 if (strcmp(propinfo.piclinfo.name,
3547 PICL_PROP_FAN_SPEED_UNIT) == 0) {
3548 if (SG_GET_SENSOR_STATUS(env->sd_status) ==
3549 SG_SENSOR_STATUS_FAN_LOW) {
3550 (void) strlcpy(result,
3551 PICL_PROPVAL_SELF_REGULATING,
3552 MAX_SPEED_UNIT_LEN);
3553 } else {
3554 (void) strlcpy(result,
3555 PICL_PROPVAL_PER_CENT,
3556 MAX_SPEED_UNIT_LEN);
3557 }
3558 } else {
3559 switch (SG_GET_SENSOR_STATUS(env->sd_status)) {
3560 case SG_SENSOR_STATUS_FAN_HIGH:
3561 *(int *)result = 100;
3562 break;
3563 case SG_SENSOR_STATUS_FAN_FAIL:
3564 case SG_SENSOR_STATUS_FAN_OFF:
3565 *(int *)result = 0;
3566 break;
3567 default:
3568 case SG_SENSOR_STATUS_FAN_LOW:
3569 kstat_close(kc);
3570 return (PICL_PROPVALUNAVAILABLE);
3571 }
3572 }
3573 break;
3574 default:
3575 kstat_close(kc);
3576 return (PICL_PROPVALUNAVAILABLE);
3577 }
3578 kstat_close(kc);
3579 return (PICL_SUCCESS);
3580 }
3581 kstat_close(kc);
3582 return (PICL_PROPVALUNAVAILABLE);
3583 }
3584
3585 /*
3586 * led information handling - uses lw8 driver
3587 */
3588
3589 static int
add_led_nodes(picl_nodehdl_t nodeh,char * name,int position,picl_prophdl_t tblhdl)3590 add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
3591 picl_prophdl_t tblhdl)
3592 {
3593 int err;
3594 int ledfd;
3595 lom_get_led_t lom_get_led;
3596 picl_nodehdl_t sensorhdl;
3597 char buf[PICL_PROPNAMELEN_MAX];
3598
3599 /*
3600 * Open the lw8 pseudo dev to get the led information
3601 */
3602 if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
3603 syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
3604 return (PICL_SUCCESS);
3605 }
3606 bzero(&lom_get_led, sizeof (lom_get_led));
3607 (void) strlcpy(lom_get_led.location, name,
3608 sizeof (lom_get_led.location));
3609 if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
3610 (void) close(ledfd);
3611 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
3612 return (PICL_FAILURE);
3613 }
3614 while (lom_get_led.next_id[0] != '\0') {
3615 (void) strlcpy(lom_get_led.id, lom_get_led.next_id,
3616 sizeof (lom_get_led.id));
3617 lom_get_led.next_id[0] = '\0';
3618 lom_get_led.position = LOM_LED_POSITION_FRU;
3619 if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
3620 (void) close(ledfd);
3621 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
3622 return (PICL_FAILURE);
3623 }
3624 sprintf_buf3(buf, "%s_%s", name, lom_get_led.id);
3625 if (position != lom_get_led.position)
3626 continue;
3627 if (position == LOM_LED_POSITION_LOCATION) {
3628 err = add_sensor_node(0, nodeh, buf, PICL_CLASS_LED,
3629 PICL_PROP_STATE, tblhdl, &sensorhdl);
3630 } else {
3631 err = add_sensor_node(nodeh, 0, buf, PICL_CLASS_LED,
3632 PICL_PROP_STATE, tblhdl, &sensorhdl);
3633 }
3634 if (err != PICL_SUCCESS) {
3635 (void) close(ledfd);
3636 return (err);
3637 }
3638 if (strcmp(name, "chassis") == 0 && strcmp(lom_get_led.id,
3639 "locator") == 0) {
3640 err = add_prop_charstring(sensorhdl, PICL_PROPVAL_TRUE,
3641 PICL_PROP_IS_LOCATOR);
3642 if (err != PICL_SUCCESS) {
3643 (void) close(ledfd);
3644 return (err);
3645 }
3646 err = add_prop_charstring(sensorhdl,
3647 PICL_PROPVAL_SYSTEM, PICL_PROP_LOCATOR_NAME);
3648 if (err != PICL_SUCCESS) {
3649 (void) close(ledfd);
3650 return (err);
3651 }
3652 }
3653 err = add_prop_charstring(sensorhdl, lom_get_led.id,
3654 PICL_PROP_LABEL);
3655 if (err != PICL_SUCCESS) {
3656 (void) close(ledfd);
3657 return (err);
3658 }
3659 err = add_prop_charstring(sensorhdl, lom_get_led.color,
3660 PICL_PROP_COLOR);
3661 if (err != PICL_SUCCESS) {
3662 (void) close(ledfd);
3663 return (err);
3664 }
3665 }
3666 (void) close(ledfd);
3667 return (PICL_SUCCESS);
3668 }
3669
3670 static int
get_led(char * name,char * ptr,char * result)3671 get_led(char *name, char *ptr, char *result)
3672 {
3673 int ledfd;
3674 lom_get_led_t lom_get_led;
3675
3676 /*
3677 * Open the lw8 pseudo dev to get the led information
3678 */
3679 if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
3680 syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
3681 return (PICL_FAILURE);
3682 }
3683 bzero(&lom_get_led, sizeof (lom_get_led));
3684 (void) strlcpy(lom_get_led.location, name,
3685 sizeof (lom_get_led.location));
3686 (void) strlcpy(lom_get_led.id, ptr, sizeof (lom_get_led.id));
3687 if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
3688 (void) close(ledfd);
3689 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
3690 return (PICL_PROPVALUNAVAILABLE);
3691 }
3692 if (lom_get_led.status == LOM_LED_STATUS_ON)
3693 (void) strlcpy(result, PICL_PROPVAL_ON, MAX_STATE_LEN);
3694 else if (lom_get_led.status == LOM_LED_STATUS_FLASHING)
3695 (void) strlcpy(result, PICL_PROPVAL_FLASHING, MAX_STATE_LEN);
3696 else if (lom_get_led.status == LOM_LED_STATUS_BLINKING)
3697 (void) strlcpy(result, PICL_PROPVAL_BLINKING, MAX_STATE_LEN);
3698 else
3699 (void) strlcpy(result, PICL_PROPVAL_OFF, MAX_STATE_LEN);
3700 (void) close(ledfd);
3701 return (PICL_SUCCESS);
3702 }
3703
3704 static int
get_led_data(ptree_rarg_t * arg,void * result)3705 get_led_data(ptree_rarg_t *arg, void *result)
3706 {
3707 int rc; /* return code */
3708 char name[PICL_PROPNAMELEN_MAX];
3709 char *ptr;
3710
3711 rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3712 sizeof (name));
3713 if (rc != PICL_SUCCESS)
3714 return (rc);
3715
3716 ptr = strchr(name, '_');
3717 *ptr++ = '\0'; /* now name is fru name, ptr is led name */
3718 return (get_led(name, ptr, (char *)result));
3719 }
3720
3721 static int
set_led(char * name,char * ptr,char * value)3722 set_led(char *name, char *ptr, char *value)
3723 {
3724 int ledfd;
3725 lom_set_led_t lom_set_led;
3726
3727 /*
3728 * Open the lw8 pseudo dev to set the led information
3729 */
3730 if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
3731 syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
3732 return (PICL_FAILURE);
3733 }
3734 bzero(&lom_set_led, sizeof (lom_set_led));
3735 (void) strlcpy(lom_set_led.location, name,
3736 sizeof (lom_set_led.location));
3737 (void) strlcpy(lom_set_led.id, ptr, sizeof (lom_set_led.id));
3738 if (strcmp(value, PICL_PROPVAL_ON) == 0) {
3739 lom_set_led.status = LOM_LED_STATUS_ON;
3740 } else if (strcmp(value, PICL_PROPVAL_FLASHING) == 0) {
3741 lom_set_led.status = LOM_LED_STATUS_FLASHING;
3742 } else if (strcmp(value, PICL_PROPVAL_BLINKING) == 0) {
3743 lom_set_led.status = LOM_LED_STATUS_BLINKING;
3744 } else {
3745 lom_set_led.status = LOM_LED_STATUS_OFF;
3746 }
3747 if (ioctl(ledfd, LOMIOCSETLED, &lom_set_led) == -1) {
3748 (void) close(ledfd);
3749 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
3750 return (PICL_PROPVALUNAVAILABLE);
3751 }
3752 (void) close(ledfd);
3753 return (PICL_SUCCESS);
3754 }
3755
3756 static int
set_led_data(ptree_warg_t * arg,const void * value)3757 set_led_data(ptree_warg_t *arg, const void *value)
3758 {
3759 int rc; /* return code */
3760 char name[PICL_PROPNAMELEN_MAX];
3761 char *ptr;
3762
3763 rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3764 sizeof (name));
3765 if (rc != PICL_SUCCESS)
3766 return (rc);
3767
3768 ptr = strchr(name, '_');
3769 *ptr++ = '\0'; /* now name is fru name, ptr is led name */
3770 return (set_led(name, ptr, (char *)value));
3771 }
3772
3773 static void
disk_leds_init(void)3774 disk_leds_init(void)
3775 {
3776 int err = 0, i;
3777
3778 if (!g_mutex_init) {
3779 if ((pthread_cond_init(&g_cv, NULL) == 0) &&
3780 (pthread_cond_init(&g_cv_ack, NULL) == 0) &&
3781 (pthread_mutex_init(&g_mutex, NULL) == 0)) {
3782 g_mutex_init = B_TRUE;
3783 } else {
3784 return;
3785 }
3786 }
3787
3788 if (ledsthr_created) {
3789 /*
3790 * this is a restart, wake up sleeping threads
3791 */
3792 err = pthread_mutex_lock(&g_mutex);
3793 if (err != 0) {
3794 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
3795 return;
3796 }
3797 g_wait_now = B_FALSE;
3798 (void) pthread_cond_broadcast(&g_cv);
3799 (void) pthread_mutex_unlock(&g_mutex);
3800 } else {
3801 if ((pthread_attr_init(&ledsthr_attr) != 0) ||
3802 (pthread_attr_setscope(&ledsthr_attr,
3803 PTHREAD_SCOPE_SYSTEM) != 0))
3804 return;
3805 if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr,
3806 disk_leds_thread, NULL)) != 0) {
3807 syslog(LOG_ERR, EM_THREAD_CREATE_FAILED, strerror(err));
3808 return;
3809 }
3810 ledsthr_created = B_TRUE;
3811 }
3812 for (i = 0; i < N_DISKS; i++) {
3813 (void) set_led(lw8_disks[i].d_fruname, FAULT_LED,
3814 PICL_PROPVAL_OFF);
3815 }
3816 }
3817
3818 static void
disk_leds_fini(void)3819 disk_leds_fini(void)
3820 {
3821 int err;
3822
3823 /*
3824 * tell led thread to pause
3825 */
3826 if (!ledsthr_created)
3827 return;
3828 err = pthread_mutex_lock(&g_mutex);
3829 if (err != 0) {
3830 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
3831 return;
3832 }
3833 g_wait_now = B_TRUE;
3834 disk_leds_thread_ack = B_FALSE;
3835 (void) pthread_cond_broadcast(&g_cv);
3836
3837 /*
3838 * and wait for the led thread to acknowledge
3839 */
3840 while (!disk_leds_thread_ack) {
3841 (void) pthread_cond_wait(&g_cv_ack, &g_mutex);
3842 }
3843 (void) pthread_mutex_unlock(&g_mutex);
3844 }
3845
3846 static void
update_disk_node(struct lw8_disk * diskp)3847 update_disk_node(struct lw8_disk *diskp)
3848 {
3849 picl_nodehdl_t slotndh;
3850 picl_nodehdl_t diskndh;
3851 picl_nodehdl_t devhdl;
3852 picl_prophdl_t tblhdl;
3853 int err;
3854 char path[MAXPATHLEN];
3855 char *fruname = diskp->d_fruname;
3856
3857 sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
3858 if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
3859 return;
3860 }
3861 diskndh = find_child_by_name(slotndh, fruname);
3862 err = ptree_get_node_by_path(diskp->d_plat_path, &devhdl);
3863 if (err == PICL_SUCCESS) {
3864 if (diskndh != 0)
3865 return;
3866 err = ptree_create_and_add_node(slotndh, fruname,
3867 PICL_CLASS_FRU, &diskndh);
3868 if (err != PICL_SUCCESS) {
3869 syslog(LOG_ERR, ADD_NODE_FAIL, fruname, err);
3870 return;
3871 }
3872 err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES);
3873 if (err != PICL_SUCCESS)
3874 return;
3875 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
3876 if (err != PICL_SUCCESS)
3877 return;
3878 err = add_prop_ref(devhdl, diskndh, PICL_REFPROP_FRU_PARENT);
3879 if (err != PICL_SUCCESS)
3880 return;
3881 } else {
3882 if (diskndh == 0)
3883 return;
3884 err = ptree_delete_node(diskndh);
3885 if (err != PICL_SUCCESS)
3886 return;
3887 (void) ptree_destroy_node(diskndh);
3888 }
3889 }
3890
3891 /*
3892 * Implement a state machine in order to:
3893 *
3894 * o enable/disable disk LEDs
3895 * o add/delete the disk's node in the FRU tree
3896 *
3897 * The machine changes state based on the current, in-memory
3898 * state of the disk (eg, the d_state field of 'struct lw8_disk')
3899 * and libdevice's current view of whether the disk is
3900 * Configured or Unconfigured.
3901 *
3902 * If the new state is the same as the previous state, then
3903 * no side effects occur. Otherwise, the LEDs for the
3904 * disk are set and the disk's associated node in the
3905 * FRU Tree is added or deleted.
3906 */
3907 static void
set_disk_leds(struct lw8_disk * disk)3908 set_disk_leds(struct lw8_disk *disk)
3909 {
3910 devctl_hdl_t dhdl;
3911 uint_t cur_state = 0;
3912
3913 dhdl = devctl_device_acquire(disk->d_devices_path, 0);
3914 if (dhdl == NULL) {
3915 int err = errno;
3916 syslog(LOG_ERR, DEVCTL_DEVICE_ACQUIRE_FAILED,
3917 strerror(err));
3918 return;
3919 }
3920 devctl_device_getstate(dhdl, &cur_state);
3921 devctl_release(dhdl);
3922
3923 if ((cur_state & DEVICE_OFFLINE) != 0) {
3924 switch (disk->d_state) {
3925 default:
3926 /*
3927 * State machine should never get here.
3928 * When NDEBUG is defined, control will
3929 * fall through and force d_state to
3930 * match the semantics of "DEVICE_OFFLINE".
3931 * During development, NDEBUG can be undefined,
3932 * and this will fire an assertion.
3933 */
3934 assert(0);
3935 /*FALLTHROUGH*/
3936
3937 case DISK_STATE_NOT_INIT:
3938 case DISK_STATE_READY:
3939 disk->d_state = DISK_STATE_NOT_READY;
3940
3941 (void) set_led(disk->d_fruname, POWER_LED,
3942 PICL_PROPVAL_OFF);
3943 (void) set_led(disk->d_fruname, REMOK_LED,
3944 PICL_PROPVAL_ON);
3945
3946 update_disk_node(disk);
3947 break;
3948
3949 case DISK_STATE_NOT_READY:
3950 break;
3951 }
3952 } else if ((cur_state & DEVICE_ONLINE) != 0) {
3953 switch (disk->d_state) {
3954 default:
3955 /*
3956 * State machine should never get here.
3957 * When NDEBUG is defined, control will
3958 * fall through and force d_state to
3959 * match the semantics of "DEVICE_ONLINE".
3960 * During development, NDEBUG can be undefined,
3961 * and this will fire an assertion.
3962 */
3963 assert(0);
3964 /*FALLTHROUGH*/
3965
3966 case DISK_STATE_NOT_INIT:
3967 case DISK_STATE_NOT_READY:
3968 disk->d_state = DISK_STATE_READY;
3969
3970 (void) set_led(disk->d_fruname, REMOK_LED,
3971 PICL_PROPVAL_OFF);
3972 (void) set_led(disk->d_fruname, POWER_LED,
3973 PICL_PROPVAL_ON);
3974
3975 update_disk_node(disk);
3976 break;
3977
3978 case DISK_STATE_READY:
3979 break;
3980 }
3981 }
3982 }
3983
3984 /*
3985 * NOTE: this implementation of disk_leds_thread is based on the version in
3986 * plugins/sun4u/mpxu/frudr/piclfrudr.c (with V440 raid support removed). Some
3987 * day the source code layout and build environment should support common code
3988 * used by platform specific plugins, in which case LW8 support could be added
3989 * to the mpxu version (which would be moved to a common directory).
3990 */
3991 /*ARGSUSED*/
3992 static void *
disk_leds_thread(void * args)3993 disk_leds_thread(void *args)
3994 {
3995 int i;
3996 int err = 0;
3997 int n_disks = N_DISKS;
3998
3999 static char *lw8_pci_devs[] = {
4000 DISK0_BASE_PATH,
4001 DISK1_BASE_PATH
4002 };
4003
4004 static char *lw8_pcix_devs[] = {
4005 DISK0_BASE_PATH_PCIX,
4006 DISK1_BASE_PATH_PCIX
4007 };
4008
4009 static char **lw8_devs;
4010
4011 if (pcix_io) {
4012 lw8_devs = lw8_pcix_devs;
4013 } else {
4014 lw8_devs = lw8_pci_devs;
4015 }
4016
4017 /*
4018 * create aliases for disk names
4019 */
4020 for (i = 0; i < n_disks; i++) {
4021 char buffer[MAXPATHLEN];
4022
4023 (void) snprintf(buffer, sizeof (buffer), "/devices%s",
4024 lw8_devs[i]);
4025 lw8_disks[i].d_devices_path = strdup(buffer);
4026
4027 (void) snprintf(buffer, sizeof (buffer), "/platform%s",
4028 lw8_devs[i]);
4029 lw8_disks[i].d_plat_path = strdup(buffer);
4030 }
4031
4032 for (;;) {
4033 for (i = 0; i < n_disks; i++) {
4034 set_disk_leds(&lw8_disks[i]);
4035 }
4036
4037 /*
4038 * wait a bit until we check again
4039 */
4040 err = poll(NULL, 0, ledsthr_poll_period);
4041 if (err == -1) {
4042 err = errno;
4043 syslog(LOG_ERR, EM_POLL_FAIL, strerror(err));
4044 break;
4045 }
4046 err = pthread_mutex_lock(&g_mutex);
4047 if (err != 0) {
4048 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
4049 break;
4050 }
4051 if (g_wait_now != B_FALSE) {
4052 /* notify _fini routine that we've paused */
4053 disk_leds_thread_ack = B_TRUE;
4054 (void) pthread_cond_signal(&g_cv_ack);
4055 /* and go to sleep in case we get restarted */
4056 while (g_wait_now != B_FALSE)
4057 (void) pthread_cond_wait(&g_cv, &g_mutex);
4058 }
4059 (void) pthread_mutex_unlock(&g_mutex);
4060 }
4061 return ((void *)err);
4062 }
4063