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.
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.
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]
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
36 #include <picld_pluginutil.h>
37 #include <sys/types.h>
41 #include <sys/sysevent/dr.h>
43 #include <libdevinfo.h>
45 #include <sys/systeminfo.h>
46 #include <sys/envmon.h>
48 #include "libdevice.h"
50 #include <sys/raidioctl.h>
51 #include <sys/param.h>
55 * Plugin registration entry points
57 static void piclfrudr_register(void);
58 static void piclfrudr_init(void);
59 static void piclfrudr_fini(void);
60 static void rmc_state_event(void);
61 static void seattle_setleds(void);
62 static void boston_set_frontleds(const char *, int);
63 static void boston_set_rearleds(const char *, int);
65 #pragma init(piclfrudr_register)
67 static picld_plugin_reg_t my_reg_info
= {
68 PICLD_PLUGIN_VERSION_1
,
69 PICLD_PLUGIN_CRITICAL
,
78 #define EM_THREAD_CREATE_FAILED gettext("piclfrudr: pthread_create failed: %s")
79 #define DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d")
80 #define EM_DI_INIT_FAIL gettext("piclfrudr: di_init failed: %s")
81 #define PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d")
82 #define ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d")
83 #define ADD_TBL_ENTRY_FAIL gettext("piclfrudr: cannot add entry to table")
84 #define EM_POLL_FAIL gettext("piclfrudr: poll() failed: %s")
85 #define ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d")
86 #define EM_MUTEX_FAIL gettext("piclfrudr: pthread_mutex_lock returned: %s")
87 #define EM_UNK_FRU gettext("piclfrudr: Fru removed event for unknown node")
88 #define PARSE_CONF_FAIL gettext("parse config file %s failed")
89 #define EM_NO_SC_DEV gettext("piclfrudr: failed to locate SC device node")
90 #define EM_NO_SYSINFO gettext("piclfrudr: failed to get SC sysinfo: %s")
93 * PICL property values
95 #define PICL_PROPVAL_ON "ON"
96 #define PICL_PROPVAL_OFF "OFF"
101 #define SEEPROM_DRIVER_NAME "seeprom"
102 #define FRUTREE_PATH "/frutree"
103 #define CHASSIS_LOC_PATH "/frutree/chassis/%s"
104 #define SYS_BOARD_PATH "/frutree/chassis/MB/system-board/%s"
105 #define SEATTLE1U_HDDBP_PATH \
106 "/frutree/chassis/MB/system-board/HDDBP/disk-backplane-1/%s"
107 #define SEATTLE2U_HDDBP_PATH \
108 "/frutree/chassis/MB/system-board/HDDBP/disk-backplane-3/%s"
109 #define BOSTON_HDDBP_PATH \
110 "/frutree/chassis/MB/system-board/HDDCNTRL/disk-controller/HDDBP" \
111 "/disk-backplane-8/%s"
113 #define CONFFILE_PREFIX "fru_"
114 #define CONFFILE_SUFFIX ".conf"
115 #define CONFFILE_FRUTREE "piclfrutree.conf"
117 #define PS_NAME_LEN 2
118 #define PS_FRU_NAME "power-supply"
119 #define PS_PLATFORM_NAME "power-supply-fru-prom"
120 #define DISK_NAME "HDD"
121 #define DISK_NAME_LEN 3
122 #define DISK_FRU_NAME "disk"
123 #define SCC_NAME "SCC"
124 #define SCC_NAME_LEN 3
125 #define SCC_FRU_NAME "scc"
126 #define RMC_NAME "SC"
127 #define RMC_NAME_LEN 2
128 #define RMC_FRU_NAME "sc"
130 #define FT_NAME_LEN 2
132 #define F0_NAME_LEN 2
134 #define F1_NAME_LEN 2
135 #define FT_FRU_NAME "fan-tray"
136 #define FT_FRU_NAME_LEN 8
137 #define FT_ID_BUFSZ (FT_NAME_LEN + 2)
138 #define DEV_PREFIX "/devices"
139 #define ENXS_FRONT_SRVC_LED 0x20
140 #define ENXS_FRONT_ACT_LED 0x10
141 #define ENXS_REAR_SRVC_LED 0x20
142 #define ENXS_REAR_ACT_LED 0x10
143 #define ENTS_SRVC_LED 0x20
144 #define ENTS_ACT_LED 0x10
145 #define V440_SRVC_LED 0x2
146 #define V440_ACT_LED 0x1
147 #define BOSTON_FRONT_SRVC_LED 0x2
148 #define BOSTON_FRONT_ACT_LED 0x4
149 #define BOSTON_FRONT_CLEAR_DIR 0x0
150 #define BOSTON_FRONT_CLEAR_POL 0x0
151 #define BOSTON_FRONT_LED_MASK 0xffffffff
152 #define BOSTON_REAR_SRVC_LED 0x8000
153 #define BOSTON_REAR_ACT_LED 0x2000
154 #define BOSTON_REAR_CLEAR_POL 0x0000
155 #define BOSTON_REAR_LED_MASK 0xe000
160 #define PSU_I2C_BUS_DEV "/devices/pci@1e,600000/isa@7/i2c@0,320:devctl"
162 "/devices/pci@1e,600000/isa@7/i2c@0,320/power-supply-fru-prom@0,%x"
163 #define PSU_PLATFORM "/platform/pci@1e,600000/isa@7/i2c@0,320"
164 #define PS0_ADDR ((sys_platform == PLAT_CHALUPA19) ? 0xc0 : 0xb0)
165 #define PS1_ADDR ((sys_platform == PLAT_CHALUPA19) ? 0xc2 : 0xa4)
166 #define PS2_ADDR 0x70
167 #define PS3_ADDR 0x72
168 #define PS0_UNITADDR ((sys_platform == PLAT_CHALUPA19) ? "0,c0" : "0,b0")
169 #define PS1_UNITADDR ((sys_platform == PLAT_CHALUPA19) ? "0,c2" : "0,a4")
170 #define PS2_UNITADDR "0,70"
171 #define PS3_UNITADDR "0,72"
172 #define PS0_NAME "PS0"
173 #define PS1_NAME "PS1"
174 #define PS2_NAME "PS2"
175 #define PS3_NAME "PS3"
176 #define PSU0_NAME "PSU0"
177 #define PSU1_NAME "PSU1"
178 #define PSU2_NAME "PSU2"
179 #define PSU3_NAME "PSU3"
180 #define PS_DEVICE_NAME "power-supply-fru-prom"
181 #define PSU_COMPATIBLE "i2c-at24c64"
184 * Seattle/Boston PSU defines
186 #define SEATTLE_PSU_I2C_BUS_DEV "/devices/i2c@1f,530000:devctl"
187 #define SEATTLE_PSU_DEV \
188 "/devices/i2c@1f,530000/power-supply-fru-prom@0,%x"
189 #define SEATTLE_PSU_PLATFORM "/platform/i2c@1f,530000"
190 #define SEATTLE_PS0_ADDR 0x6c
191 #define SEATTLE_PS1_ADDR 0x6e
192 #define SEATTLE_PS0_UNITADDR "0,6c"
193 #define SEATTLE_PS1_UNITADDR "0,6e"
194 #define SEATTLE_PSU_COMPATIBLE "i2c-at34c02"
195 #define BOSTON_PSU_I2C_BUS_DEV "/devices/i2c@1f,520000:devctl"
196 #define BOSTON_PSU_DEV \
197 "/devices/i2c@1f,520000/power-supply-fru-prom@0,%x"
198 #define BOSTON_PSU_PLATFORM "/platform/i2c@1f,520000"
199 #define BOSTON_PS0_ADDR 0x24
200 #define BOSTON_PS1_ADDR 0x32
201 #define BOSTON_PS2_ADDR 0x52
202 #define BOSTON_PS3_ADDR 0x72
203 #define BOSTON_PS0_UNITADDR "0,24"
204 #define BOSTON_PS1_UNITADDR "0,32"
205 #define BOSTON_PS2_UNITADDR "0,52"
206 #define BOSTON_PS3_UNITADDR "0,72"
207 #define BOSTON_PSU_COMPATIBLE "i2c-at34c02"
210 * Seattle fan-tray paths
212 #define SEATTLE_FCB0_1U \
213 "/frutree/chassis/MB/system-board/FIOB/front-io-board-1" \
214 "/FCB0/fan-connector-board/%s"
215 #define SEATTLE_FCB1_1U \
216 "/frutree/chassis/MB/system-board/FIOB/front-io-board-1" \
217 "/FCB1/fan-connector-board/%s"
218 #define SEATTLE_PDB_1U \
219 "/frutree/chassis/PDB/power-distribution-board/%s"
220 #define SEATTLE_FCB0_2U \
221 "/frutree/chassis/MB/system-board/FIOB/front-io-board-2" \
222 "/FCB0/fan-connector-board/%s"
223 #define SEATTLE_FCB1_2U \
224 "/frutree/chassis/MB/system-board/FIOB/front-io-board-2" \
225 "/FCB1/fan-connector-board/%s"
226 #define SEATTLE_PDB_2U \
227 "/frutree/chassis/PDB/power-distribution-board" \
228 "/HDDFB/fan-connector-board/%s"
233 #define REMOK_LED "OK2RM"
234 #define FAULT_LED "SERVICE"
235 #define PLATFORMLEN 9
237 #define N_CHALUPA_DISKS 4
238 #define N_ENTS_DISKS 8
239 #define N_MPXU_DISKS 4
240 #define N_EN19_DISKS 2
241 #define DISK_POLL_TIME 5000
242 /* For V440 RAID policy */
243 #define V440_DISK_DEVCTL "/devices/pci@1f,700000/scsi@2:devctl"
246 * Seattle/Boston disk defines
248 #define N_SEATTLE1U_DISKS 2
249 #define N_SEATTLE2U_DISKS 4
250 #define N_BOSTON_DISKS 8
251 #define SEATTLE_DISK_DEVCTL \
252 "/devices/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1:devctl"
253 #define BOSTON_DISK_DEVCTL_1068X \
254 "/devices/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1:devctl"
255 #define BOSTON_DISK_DEVCTL_1068E \
256 "/devices/pci@1e,600000/pci@0/pci@2/scsi@0:devctl"
261 #define ENXS_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/"
262 #define ENXS_FRONT_LEDS "gpio@0,70:"
263 #define ENXS_REAR_LEDS ENXS_LED_DIR "gpio@0,44:port_1"
265 #define ENTS_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/"
266 #define ENTS_LEDS "gpio@0,70:"
268 #define V440_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/"
269 #define V440_LED_PATH V440_LED_DIR "gpio@0,48:port_0"
272 * Seattle/Boston led defines
274 #define SEATTLE_LED_DEV "/devices/ebus@1f,464000/env-monitor@3,0:env-monitor0"
275 #define BOSTON_LED_DIR "/devices/i2c@1f,520000/"
276 #define BOSTON_FRONT_LED_PATH BOSTON_LED_DIR "gpio@0,3a:port_0"
277 #define BOSTON_REAR_LED_PATH BOSTON_LED_DIR "hardware-monitor@0,5c:adm1026"
280 * Seattle/Boston USB defines
282 #define MAX_USB_PORTS 4
283 #define USB_CONF_FILE_NAME "usb-a-"
285 typedef struct id_props
{
286 envmon_handle_t envhandle
;
287 picl_prophdl_t volprop
;
290 typedef struct idp_lkup
{
291 int maxnum
; /* entries in array */
292 int num
; /* entries in use */
297 * table for mapping RMC handles to volatile property handles
299 static idp_lkup_t
*idprop
= NULL
;
302 * path names to system-controller device and fault led gpio
304 static char *sc_device_name
= NULL
;
305 static char *bezel_leds
= NULL
;
310 static int disk_ready
[N_DISKS
];
311 static char *disk_name
[N_DISKS
] = { "HDD0", "HDD1", "HDD2", "HDD3",
312 "HDD4", "HDD5", "HDD6", "HDD7" };
313 static volatile boolean_t disk_leds_thread_ack
= B_FALSE
;
314 static volatile boolean_t disk_leds_thread_running
= B_FALSE
;
315 static pthread_t ledsthr_tid
;
316 static pthread_attr_t ledsthr_attr
;
317 static boolean_t ledsthr_created
= B_FALSE
;
318 static boolean_t g_mutex_init
= B_FALSE
;
319 static pthread_cond_t g_cv
;
320 static pthread_cond_t g_cv_ack
;
321 static pthread_mutex_t g_mutex
;
322 static volatile boolean_t g_finish_now
= B_FALSE
;
325 * Boston platform-specific flag which tells us if we are using
326 * a LSI 1068X disk controller (0) or a LSI 1068E (1).
328 static int boston_1068e_flag
= 0;
333 static const char str_devfs_path
[] = "devfs-path";
336 * OperationalStatus property values
338 static const char str_opst_present
[] = "present";
339 static const char str_opst_ok
[] = "okay";
340 static const char str_opst_faulty
[] = "faulty";
341 static const char str_opst_download
[] = "download";
342 static const char str_opst_unknown
[] = "unknown";
343 static size_t max_opst_len
= sizeof (str_opst_download
);
348 static void opst_init(void);
349 static void add_op_status_by_name(const char *name
, const char *child_name
,
350 picl_prophdl_t
*prophdl_p
);
351 static void add_op_status_to_node(picl_nodehdl_t nodeh
,
352 picl_prophdl_t
*prophdl_p
);
353 static int read_vol_data(ptree_rarg_t
*r_arg
, void *buf
);
354 static int find_picl_handle(picl_prophdl_t proph
);
355 static void disk_leds_init(void);
356 static void disk_leds_fini(void);
357 static void *disk_leds_thread(void *args
);
358 static picl_nodehdl_t
find_child_by_name(picl_nodehdl_t parh
, char *name
);
359 static void post_frudr_event(char *ename
, picl_nodehdl_t parenth
,
360 picl_nodehdl_t fruh
);
361 static int add_prop_ref(picl_nodehdl_t nodeh
, picl_nodehdl_t value
, char *name
);
362 static void remove_fru_parents(picl_nodehdl_t fruh
);
363 static int get_node_by_class(picl_nodehdl_t nodeh
, const char *classname
,
364 picl_nodehdl_t
*foundnodeh
);
365 static int get_sys_controller_node(picl_nodehdl_t
*nodeh
);
366 static char *create_sys_controller_pathname(picl_nodehdl_t sysconh
);
367 static char *create_bezel_leds_pathname(const char *dirpath
,
368 const char *devname
);
369 static void frudr_evhandler(const char *ename
, const void *earg
,
370 size_t size
, void *cookie
);
371 static void fru_add_handler(const char *ename
, const void *earg
,
372 size_t size
, void *cookie
);
373 static void frutree_evhandler(const char *ename
, const void *earg
,
374 size_t size
, void *cookie
);
375 static int create_table(picl_nodehdl_t fruhdl
, picl_prophdl_t
*tblhdlp
,
377 static int create_table_entry(picl_prophdl_t tblhdl
,
378 picl_nodehdl_t refhdl
, char *class);
379 static int create_i2c_node(char *ap_id
);
380 static void delete_i2c_node(char *ap_id
);
381 static int set_led(char *name
, char *ptr
, char *value
);
382 static int ps_name_to_addr(char *name
);
383 static char *ps_name_to_unitaddr(char *name
);
384 static char *ps_apid_to_nodename(char *apid
);
385 static void add_op_status(envmon_hpu_t
*hpu
, int *index
);
386 static void get_fantray_path(char *ap_id
, char *path
, int bufsz
);
388 #define sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2)
391 * Because this plugin is shared across different platforms, we need to
392 * distinguish for certain functionality
394 #define PLAT_UNKNOWN (-1)
397 #define PLAT_CHALUPA 2
399 #define PLAT_CHALUPA19 4
400 #define PLAT_SALSA19 5
401 #define PLAT_SEATTLE1U 6
402 #define PLAT_SEATTLE2U 7
403 #define PLAT_BOSTON 8
405 static int sys_platform
;
411 (void) sysinfo(SI_PLATFORM
, platform
, sizeof (platform
));
412 if (strcmp(platform
, "SUNW,Sun-Fire-V250") == 0)
413 sys_platform
= PLAT_ENTS
;
414 else if (strcmp(platform
, "SUNW,Sun-Fire-V440") == 0)
415 sys_platform
= PLAT_CHALUPA
;
416 else if (strcmp(platform
, "SUNW,Sun-Fire-V210") == 0)
417 sys_platform
= PLAT_ENXS
;
418 else if (strcmp(platform
, "SUNW,Sun-Fire-V240") == 0)
419 sys_platform
= PLAT_ENXS
;
420 else if (strcmp(platform
, "SUNW,Netra-240") == 0)
421 sys_platform
= PLAT_EN19
;
422 else if (strcmp(platform
, "SUNW,Netra-210") == 0)
423 sys_platform
= PLAT_SALSA19
;
424 else if (strcmp(platform
, "SUNW,Netra-440") == 0)
425 sys_platform
= PLAT_CHALUPA19
;
426 else if (strcmp(platform
, "SUNW,Sun-Fire-V215") == 0)
427 sys_platform
= PLAT_SEATTLE1U
;
428 else if (strcmp(platform
, "SUNW,Sun-Fire-V245") == 0)
429 sys_platform
= PLAT_SEATTLE2U
;
430 else if (strcmp(platform
, "SUNW,Sun-Fire-V445") == 0)
431 sys_platform
= PLAT_BOSTON
;
433 sys_platform
= PLAT_UNKNOWN
;
437 * This function is executed as part of .init when the plugin is
441 piclfrudr_register(void)
443 (void) picld_plugin_register(&my_reg_info
);
447 * This function is the init entry point of the plugin.
448 * It initializes the /frutree tree
453 picl_nodehdl_t sc_nodeh
;
454 picl_nodehdl_t locationh
;
455 picl_nodehdl_t childh
;
456 char namebuf
[PATH_MAX
];
460 if (sc_device_name
!= NULL
) {
461 free(sc_device_name
); /* must have reen restarted */
462 sc_device_name
= NULL
;
465 if ((get_sys_controller_node(&sc_nodeh
) != PICL_SUCCESS
) ||
466 ((sc_device_name
= create_sys_controller_pathname(sc_nodeh
)) ==
468 syslog(LOG_ERR
, EM_NO_SC_DEV
);
473 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE
,
474 frudr_evhandler
, NULL
);
475 (void) ptree_register_handler(PICL_FRU_ADDED
, fru_add_handler
, NULL
);
476 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED
,
477 frutree_evhandler
, NULL
);
480 * There is a window of opportunity for the RMC to deliver an event
481 * indicating a newly operable state just before we are listening for
482 * it. In this case, envmon will have missed setting up /platform
483 * and won't get a signal from frudr. So send it a PICL_FRU_ADDED just
487 if ((sys_platform
== PLAT_CHALUPA
) ||
488 (sys_platform
== PLAT_CHALUPA19
)) {
489 sprintf_buf2(namebuf
, CHASSIS_LOC_PATH
, RMC_NAME
);
491 sprintf_buf2(namebuf
, SYS_BOARD_PATH
, RMC_NAME
);
494 if (ptree_get_node_by_path(namebuf
, &locationh
) != PICL_SUCCESS
)
496 if (ptree_get_propval_by_name(locationh
, PICL_PROP_CHILD
,
497 &childh
, sizeof (picl_nodehdl_t
)) != PICL_SUCCESS
)
499 post_frudr_event(PICL_FRU_ADDED
, locationh
, childh
);
503 add_op_status_by_name(const char *name
, const char *child_name
,
504 picl_prophdl_t
*prophdl_p
)
506 picl_nodehdl_t nodeh
;
508 if (ptree_get_node_by_path(name
, &nodeh
) != PICL_SUCCESS
) {
512 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_CHILD
,
513 &nodeh
, sizeof (picl_nodehdl_t
)) != PICL_SUCCESS
) {
515 if (child_name
== NULL
)
518 * create fru node of supplied name
520 if (ptree_create_and_add_node(nodeh
, child_name
,
521 PICL_CLASS_FRU
, &nodeh
) != PICL_SUCCESS
)
525 add_op_status_to_node(nodeh
, prophdl_p
);
529 * function to add a volatile property to a specified node
532 add_op_status_to_node(picl_nodehdl_t nodeh
, picl_prophdl_t
*prophdl_p
)
535 ptree_propinfo_t info
;
536 picl_prophdl_t proph
;
538 err
= ptree_init_propinfo(&info
, PTREE_PROPINFO_VERSION
,
539 PICL_PTYPE_CHARSTRING
, PICL_VOLATILE
| PICL_READ
, max_opst_len
,
540 PICL_PROP_OPERATIONAL_STATUS
, read_vol_data
, NULL
);
542 if (err
== PICL_SUCCESS
) {
543 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_OPERATIONAL_STATUS
,
544 &proph
) == PICL_SUCCESS
) {
545 if (ptree_delete_prop(proph
) == PICL_SUCCESS
)
546 err
= ptree_destroy_prop(proph
);
550 if ((err
!= PICL_SUCCESS
) || ((err
= ptree_create_and_add_prop(nodeh
,
551 &info
, NULL
, prophdl_p
)) != PICL_SUCCESS
)) {
552 syslog(LOG_ERR
, ADD_PROP_FAIL
, PICL_PROP_OPERATIONAL_STATUS
,
559 * Deliver volatile property value.
560 * prtpicl gets very upset if we fail this command, so if the property
561 * cannot be retrieved, return a status of unknown.
564 read_vol_data(ptree_rarg_t
*r_arg
, void *buf
)
566 picl_prophdl_t proph
;
572 proph
= r_arg
->proph
;
573 index
= find_picl_handle(proph
);
577 * We drop memory of PSU op status handles in opst_init()
578 * when we get an RMC faulty event. We cannot access the
579 * status info in this circumstance, so returning "unknown"
582 (void) strlcpy(buf
, str_opst_unknown
, max_opst_len
);
583 return (PICL_SUCCESS
);
586 envmon_fd
= open(sc_device_name
, O_RDONLY
);
590 * To get this far we must have succeeded with an earlier
591 * open, so this is an unlikely failure. It would be more
592 * helpful to indicate the nature of the failure, but we
593 * don't have the space to say much. Just return "unknown".
595 (void) strlcpy(buf
, str_opst_unknown
, max_opst_len
);
596 return (PICL_SUCCESS
);
599 data
.id
= idprop
->idp
[index
].envhandle
;
600 err
= ioctl(envmon_fd
, ENVMONIOCHPU
, &data
);
604 * If we can't read the stats, "unknown" is a reasonable
605 * status to return. This one really shouldn't happen.
607 (void) strlcpy(buf
, str_opst_unknown
, max_opst_len
);
608 (void) close(envmon_fd
);
609 return (PICL_SUCCESS
);
612 (void) close(envmon_fd
);
614 if (strncmp(data
.id
.name
, DISK_NAME
, DISK_NAME_LEN
) == 0 &&
615 data
.fru_status
== ENVMON_FRU_PRESENT
) {
616 (void) strlcpy(buf
, str_opst_present
, max_opst_len
);
617 return (PICL_SUCCESS
);
620 if (data
.sensor_status
!= ENVMON_SENSOR_OK
) {
621 (void) strlcpy(buf
, str_opst_unknown
, max_opst_len
);
622 return (PICL_SUCCESS
);
626 data
.fru_status
== ENVMON_FRU_PRESENT
? str_opst_ok
:
627 data
.fru_status
== ENVMON_FRU_DOWNLOAD
? str_opst_download
:
628 data
.fru_status
== ENVMON_FRU_FAULT
? str_opst_faulty
:
629 str_opst_unknown
, max_opst_len
);
631 return (PICL_SUCCESS
);
635 * Function for explicitly turning on system leds
636 * for a failed/degraded RMC (SC).
639 solaris_setleds(const char *led_path
, int leds
)
642 int fd
= open(led_path
, O_RDWR
);
647 gpio
.reg_val
= (leds
^ 0xff);
648 gpio
.reg_mask
= 0xffffffff;
649 if (ioctl(fd
, GPIO_SET_CONFIG
, &gpio
) == 0) {
650 gpio
.reg_val
= (leds
^ 0xff);
651 gpio
.reg_mask
= 0xffffffff;
652 (void) ioctl(fd
, GPIO_SET_OUTPUT
, &gpio
);
658 * Function for explicitly turning on system leds
659 * for a failed/degraded RMC (SC) on Seattle
662 seattle_setleds(void)
666 fd
= open(SEATTLE_LED_DEV
, O_RDWR
);
671 ioctl(fd
, EPIC_SET_POWER_LED
, (char *)0);
672 ioctl(fd
, EPIC_SET_ALERT_LED
, (char *)0);
677 * Function for explicitly turning on the front system leds
678 * for a failed/degraded RMC (SC) on Boston
681 boston_set_frontleds(const char *led_path
, int leds
)
684 int fd
= open(led_path
, O_RDWR
);
690 /* first clear the polarity */
691 gpio
.reg_val
= BOSTON_FRONT_CLEAR_POL
;
692 gpio
.reg_mask
= BOSTON_FRONT_LED_MASK
;
693 if (ioctl(fd
, GPIO_SET_POLARITY
, &gpio
) < 0) {
698 /* now clear the direction */
699 gpio
.reg_val
= BOSTON_FRONT_CLEAR_DIR
;
700 gpio
.reg_mask
= BOSTON_FRONT_LED_MASK
;
701 if (ioctl(fd
, GPIO_SET_CONFIG
, &gpio
) < 0) {
706 /* and light the leds */
708 gpio
.reg_mask
= BOSTON_FRONT_LED_MASK
;
709 ioctl(fd
, GPIO_SET_OUTPUT
, &gpio
);
714 * Function for explicitly turning on the rear system leds
715 * for a failed/degraded RMC (SC) on Boston
718 boston_set_rearleds(const char *led_path
, int leds
)
721 int fd
= open(led_path
, O_RDWR
);
727 /* first clear the polarity */
728 gpio
.reg_val
= BOSTON_REAR_CLEAR_POL
;
729 gpio
.reg_mask
= BOSTON_REAR_LED_MASK
;
730 if (ioctl(fd
, GPIO_SET_POLARITY
, &gpio
) < 0) {
735 /* now set the direction */
736 gpio
.reg_val
= BOSTON_REAR_LED_MASK
;
737 gpio
.reg_mask
= BOSTON_REAR_LED_MASK
;
738 if (ioctl(fd
, GPIO_SET_CONFIG
, &gpio
) < 0) {
743 /* and light the leds */
745 gpio
.reg_mask
= BOSTON_REAR_LED_MASK
;
746 ioctl(fd
, GPIO_SET_OUTPUT
, &gpio
);
751 rmc_state_event(void)
755 int fd
= open(sc_device_name
, O_RDONLY
);
760 (void) strlcpy(hpu
.id
.name
, RMC_NAME
, sizeof (hpu
.id
.name
));
761 res
= ioctl(fd
, ENVMONIOCHPU
, &hpu
);
764 if ((res
== 0) && (hpu
.sensor_status
== ENVMON_SENSOR_OK
) &&
765 ((hpu
.fru_status
& ENVMON_FRU_FAULT
) != 0)) {
767 * SC failed event - light the service led
768 * note that as Solaris is still running,
769 * the Solaris active led should be lit too.
771 switch (sys_platform
) {
775 solaris_setleds(ENXS_REAR_LEDS
,
776 ENXS_REAR_SRVC_LED
| ENXS_REAR_ACT_LED
);
778 * the device name for the bezel leds GPIO device
779 * tends to vary from Unix to Unix. Search for it.
781 if (bezel_leds
== NULL
) {
783 create_bezel_leds_pathname(ENXS_LED_DIR
,
786 if (bezel_leds
== NULL
)
788 solaris_setleds(bezel_leds
,
789 ENXS_FRONT_SRVC_LED
| ENXS_FRONT_ACT_LED
);
793 * the device name for the system leds gpio can vary
794 * as there are several similar gpio devices. Search
795 * for one with the desired address.
797 if (bezel_leds
== NULL
) {
799 create_bezel_leds_pathname(ENTS_LED_DIR
,
802 if (bezel_leds
== NULL
)
804 solaris_setleds(bezel_leds
,
805 ENTS_SRVC_LED
| ENTS_ACT_LED
);
809 solaris_setleds(V440_LED_PATH
,
810 V440_SRVC_LED
| V440_ACT_LED
);
814 boston_set_frontleds(BOSTON_FRONT_LED_PATH
,
815 BOSTON_FRONT_SRVC_LED
| BOSTON_FRONT_ACT_LED
);
816 /* and then the rear leds */
817 boston_set_rearleds(BOSTON_REAR_LED_PATH
,
818 BOSTON_REAR_SRVC_LED
| BOSTON_REAR_ACT_LED
);
831 find_picl_handle(picl_prophdl_t proph
)
838 for (index
= 0; index
< idprop
->num
; index
++) {
839 if (idprop
->idp
[index
].volprop
== proph
)
847 find_vol_prop_by_name(const char *name
)
854 for (index
= 0; index
< idprop
->num
; index
++) {
855 if (strcmp(idprop
->idp
[index
].envhandle
.name
, name
) == 0)
863 * This function is the fini entry point of the plugin.
868 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE
,
869 frudr_evhandler
, NULL
);
870 (void) ptree_unregister_handler(PICL_FRU_ADDED
, fru_add_handler
,
873 if (idprop
!= NULL
) {
877 if (sc_device_name
!= NULL
) {
878 free(sc_device_name
);
879 sc_device_name
= NULL
;
884 * subroutine for various functions. Finds immediate child of parh with
885 * requested name if present. Otherwise returns NULL.
887 static picl_nodehdl_t
888 find_child_by_name(picl_nodehdl_t parh
, char *name
)
890 picl_nodehdl_t nodeh
;
892 char nodename
[PICL_PROPNAMELEN_MAX
];
894 err
= ptree_get_propval_by_name(parh
, PICL_PROP_CHILD
,
895 &nodeh
, sizeof (picl_nodehdl_t
));
896 if (err
!= PICL_SUCCESS
)
899 err
= ptree_get_propval_by_name(nodeh
, PICL_PROP_NAME
, nodename
,
901 if (err
!= PICL_SUCCESS
)
903 if (strcmp(name
, nodename
) == 0) {
906 err
= ptree_get_propval_by_name(nodeh
, PICL_PROP_PEER
,
907 &nodeh
, sizeof (picl_nodehdl_t
));
908 if (err
!= PICL_SUCCESS
)
913 /* Creates a reference property for a given PICL node */
915 add_prop_ref(picl_nodehdl_t nodeh
, picl_nodehdl_t value
, char *name
)
917 picl_prophdl_t proph
;
918 ptree_propinfo_t propinfo
;
921 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
922 PICL_PTYPE_REFERENCE
, PICL_READ
, sizeof (picl_nodehdl_t
), name
,
924 if (err
!= PICL_SUCCESS
) {
925 syslog(LOG_ERR
, PROPINFO_FAIL
, name
, err
);
928 err
= ptree_create_and_add_prop(nodeh
, &propinfo
, &value
, &proph
);
929 if (err
!= PICL_SUCCESS
) {
930 syslog(LOG_ERR
, ADD_PROP_FAIL
, name
, err
);
933 return (PICL_SUCCESS
);
936 /* create an entry in the specified table */
938 create_table_entry(picl_prophdl_t tblhdl
, picl_nodehdl_t refhdl
, char *class)
941 ptree_propinfo_t prop
;
942 picl_prophdl_t prophdl
[2];
944 /* first column is class */
945 prop
.version
= PTREE_PROPINFO_VERSION
;
946 prop
.piclinfo
.type
= PICL_PTYPE_CHARSTRING
;
947 prop
.piclinfo
.accessmode
= PICL_READ
;
948 prop
.piclinfo
.size
= PICL_CLASSNAMELEN_MAX
;
951 (void) strlcpy(prop
.piclinfo
.name
, PICL_PROP_CLASS
,
952 sizeof (prop
.piclinfo
.name
));
953 err
= ptree_create_prop(&prop
, class, &prophdl
[0]);
954 if (err
!= PICL_SUCCESS
) {
955 syslog(LOG_ERR
, ADD_TBL_ENTRY_FAIL
, err
);
959 /* second column is reference property */
960 prop
.version
= PTREE_PROPINFO_VERSION
;
961 prop
.piclinfo
.type
= PICL_PTYPE_REFERENCE
;
962 prop
.piclinfo
.accessmode
= PICL_READ
;
963 prop
.piclinfo
.size
= sizeof (picl_nodehdl_t
);
966 sprintf_buf2(prop
.piclinfo
.name
, "_%s_", class);
967 err
= ptree_create_prop(&prop
, &refhdl
, &prophdl
[1]);
968 if (err
!= PICL_SUCCESS
) {
969 syslog(LOG_ERR
, ADD_TBL_ENTRY_FAIL
, err
);
973 /* add row to table */
974 err
= ptree_add_row_to_table(tblhdl
, 2, prophdl
);
975 if (err
!= PICL_SUCCESS
)
976 syslog(LOG_ERR
, ADD_TBL_ENTRY_FAIL
, err
);
980 /* create an empty table property */
982 create_table(picl_nodehdl_t fruhdl
, picl_prophdl_t
*tblhdlp
, char *tbl_name
)
985 ptree_propinfo_t prop
;
986 picl_prophdl_t tblprophdl
;
988 err
= ptree_create_table(tblhdlp
);
989 if (err
!= PICL_SUCCESS
) {
990 syslog(LOG_ERR
, ADD_PROP_FAIL
, tbl_name
, err
);
993 prop
.version
= PTREE_PROPINFO_VERSION
;
994 prop
.piclinfo
.type
= PICL_PTYPE_TABLE
;
995 prop
.piclinfo
.accessmode
= PICL_READ
;
996 prop
.piclinfo
.size
= sizeof (picl_prophdl_t
);
999 (void) strlcpy(prop
.piclinfo
.name
, tbl_name
,
1000 sizeof (prop
.piclinfo
.name
));
1001 err
= ptree_create_and_add_prop(fruhdl
, &prop
, tblhdlp
, &tblprophdl
);
1002 if (err
!= PICL_SUCCESS
)
1003 syslog(LOG_ERR
, ADD_PROP_FAIL
, tbl_name
, err
);
1008 * The size of outfilename must be PATH_MAX
1011 get_config_file(char *outfilename
, char *fru
)
1013 char nmbuf
[SYS_NMLN
];
1014 char pname
[PATH_MAX
];
1017 for (dir
= 0; dir
< 2; dir
++) {
1018 if (sysinfo(dir
== 0 ? SI_PLATFORM
: SI_MACHINE
,
1019 nmbuf
, sizeof (nmbuf
)) == -1) {
1023 (void) snprintf(pname
, PATH_MAX
, PICLD_PLAT_PLUGIN_DIRF
, nmbuf
);
1024 (void) strlcat(pname
, CONFFILE_PREFIX
, PATH_MAX
);
1025 (void) strlcat(pname
, fru
, PATH_MAX
);
1026 (void) strlcat(pname
, CONFFILE_SUFFIX
, PATH_MAX
);
1028 if (access(pname
, R_OK
) == 0) {
1029 (void) strlcpy(outfilename
, pname
, PATH_MAX
);
1034 (void) snprintf(pname
, PATH_MAX
, "%s/%s%s%s",
1035 PICLD_COMMON_PLUGIN_DIR
, CONFFILE_PREFIX
, fru
,
1038 if (access(pname
, R_OK
) == 0) {
1039 (void) strlcpy(outfilename
, pname
, PATH_MAX
);
1047 * This helper function for Netra-440 fan tray removal removes
1048 * the rmclomv-rooted nodes and their properties.
1051 delete_node_and_props(picl_nodehdl_t hdl
)
1053 picl_prophdl_t prop
;
1057 err
= ptree_get_first_prop(hdl
, &prop
);
1058 if (err
== PICL_SUCCESS
) {
1059 if (ptree_delete_prop(prop
) == PICL_SUCCESS
)
1060 (void) ptree_destroy_prop(prop
);
1062 } while (err
== PICL_SUCCESS
);
1063 if (ptree_delete_node(hdl
) == PICL_SUCCESS
)
1064 (void) ptree_destroy_node(hdl
);
1068 remove_fru_parents(picl_nodehdl_t fruh
)
1070 char name
[MAXPATHLEN
];
1072 picl_nodehdl_t nodeh
;
1073 picl_prophdl_t tableh
;
1074 picl_prophdl_t tblh
;
1075 picl_prophdl_t fruph
;
1076 picl_nodehdl_t childh
;
1079 retval
= ptree_get_propval_by_name(fruh
, PICL_PROP_NAME
, name
,
1081 if (retval
!= PICL_SUCCESS
) {
1082 syslog(LOG_ERR
, EM_UNK_FRU
);
1086 retval
= ptree_get_prop_by_name(fruh
, PICL_PROP_DEVICES
, &tableh
);
1087 if (retval
!= PICL_SUCCESS
) {
1089 * No Devices table. However on Seattle, Boston and
1090 * Netra-440 (Chalupa19) (which support fan fru hotplug),
1091 * the Devices table will be found under the child node (Fn)
1092 * of the fru (fan-tray).
1093 * Therefore, check the first child of the fru for the
1094 * Devices table on these platforms before returning.
1096 switch (sys_platform
) {
1097 case PLAT_SEATTLE1U
:
1098 case PLAT_SEATTLE2U
:
1100 if (strcmp(name
, FT_FRU_NAME
) != 0)
1104 case PLAT_CHALUPA19
:
1105 if (strncmp(name
, F0_NAME
, F0_NAME_LEN
) &&
1106 strncmp(name
, F1_NAME
, F1_NAME_LEN
))
1114 retval
= ptree_get_propval_by_name(fruh
,
1115 PICL_PROP_CHILD
, &childh
, sizeof (picl_nodehdl_t
));
1116 if (retval
!= PICL_SUCCESS
)
1118 retval
= ptree_get_prop_by_name(childh
,
1119 PICL_PROP_DEVICES
, &tableh
);
1120 if (retval
!= PICL_SUCCESS
)
1125 * follow all reference properties in the second
1126 * column of the table and delete any _fru_parent node
1127 * at the referenced node.
1129 retval
= ptree_get_propval(tableh
, &tblh
, sizeof (tblh
));
1130 if (retval
!= PICL_SUCCESS
) {
1131 /* can't get value of table property */
1135 /* get first col, first row */
1136 retval
= ptree_get_next_by_col(tblh
, &tblh
);
1137 if (retval
!= PICL_SUCCESS
) {
1143 * starting at next col, get every entry in the column
1145 for (retval
= ptree_get_next_by_row(tblh
, &tblh
);
1146 retval
== PICL_SUCCESS
;
1147 retval
= ptree_get_next_by_col(tblh
, &tblh
)) {
1149 * should be a ref prop in our hands,
1150 * get the target node handle
1152 retval
= ptree_get_propval(tblh
, &nodeh
,
1154 if (retval
!= PICL_SUCCESS
) {
1158 * got the referenced node, has it got a
1159 * _fru_parent property?
1161 retval
= ptree_get_prop_by_name(nodeh
,
1162 PICL_REFPROP_FRU_PARENT
, &fruph
);
1163 if (retval
!= PICL_SUCCESS
) {
1165 * on Boston, Seattle and Netra-440 we should
1166 * actually be looking for the _location_parent
1167 * property for fan frus
1170 retval
= ptree_get_prop_by_name(nodeh
,
1171 PICL_REFPROP_LOC_PARENT
, &fruph
);
1173 if (retval
!= PICL_SUCCESS
)
1177 * got a _fru_parent node reference delete it
1179 if (ptree_delete_prop(fruph
) == PICL_SUCCESS
)
1180 (void) ptree_destroy_prop(fruph
);
1182 /* On Netra-440, extra clean-up is required for fan trays */
1183 if ((sys_platform
== PLAT_CHALUPA19
) && (fanfru
)) {
1184 /* remove the rmclomv node and its properties */
1185 delete_node_and_props(nodeh
);
1189 /* More Netra-440 fan tray clean-up */
1190 if ((sys_platform
== PLAT_CHALUPA19
) && (fanfru
)) {
1191 /* remove the fru's child's table */
1192 if (ptree_delete_prop(tableh
) == PICL_SUCCESS
)
1193 (void) ptree_destroy_prop(tableh
);
1194 /* remove the child */
1195 if (ptree_delete_node(childh
) == PICL_SUCCESS
)
1196 (void) ptree_destroy_node(childh
);
1201 remove_tables(picl_nodehdl_t rootnd
)
1203 picl_nodehdl_t tableh
;
1206 retval
= ptree_get_prop_by_name(rootnd
, PICL_PROP_DEVICES
, &tableh
);
1208 if (retval
== PICL_SUCCESS
) {
1210 * found a Devices property, delete it
1212 if ((retval
= ptree_delete_prop(tableh
)) == PICL_SUCCESS
) {
1213 (void) ptree_destroy_prop(tableh
);
1218 * is there a child node?
1220 retval
= ptree_get_propval_by_name(rootnd
, PICL_PROP_CHILD
, &rootnd
,
1223 while (retval
== PICL_SUCCESS
) {
1225 remove_tables(rootnd
);
1230 retval
= ptree_get_propval_by_name(rootnd
, PICL_PROP_PEER
,
1231 &rootnd
, sizeof (rootnd
));
1236 * Event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events
1240 frudr_completion_handler(char *ename
, void *earg
, size_t size
)
1242 picl_nodehdl_t fruh
;
1243 picl_nodehdl_t parh
;
1244 picl_nodehdl_t peerh
= NULL
;
1245 char nodename
[PICL_PROPNAMELEN_MAX
] = { '\0' };
1248 if (strcmp(ename
, PICL_FRU_REMOVED
) == 0) {
1250 * now frudata has been notified that the node is to be
1251 * removed, we can actually remove it
1254 (void) nvlist_lookup_uint64(earg
,
1255 PICLEVENTARG_FRUHANDLE
, &fruh
);
1257 (void) ptree_get_propval_by_name(fruh
, PICL_PROP_PEER
,
1258 &peerh
, sizeof (peerh
));
1261 * first find name of the fru
1263 err
= ptree_get_propval_by_name(fruh
, PICL_PROP_PARENT
,
1264 &parh
, sizeof (parh
));
1265 if (err
== PICL_SUCCESS
) {
1266 err
= ptree_get_propval_by_name(parh
,
1267 PICL_PROP_NAME
, nodename
,
1270 if (err
== PICL_SUCCESS
) {
1272 * if it was a power supply, delete i2c node
1274 if (strncmp(nodename
, PS_NAME
,
1275 PS_NAME_LEN
) == 0) {
1276 (void) delete_i2c_node(nodename
);
1280 * is disk node, make thread re-evaluate led
1283 if (strncmp(nodename
, DISK_NAME
,
1284 DISK_NAME_LEN
) == 0) {
1285 disk_ready
[nodename
[DISK_NAME_LEN
] -
1290 remove_fru_parents(fruh
);
1293 * now we can delete the node
1295 err
= ptree_delete_node(fruh
);
1296 if (err
== PICL_SUCCESS
) {
1297 (void) ptree_destroy_node(fruh
);
1299 syslog(LOG_ERR
, DELETE_PROP_FAIL
, err
);
1302 if ((sys_platform
== PLAT_CHALUPA19
) &&
1303 (strncmp(nodename
, FT_NAME
, FT_NAME_LEN
) == 0) &&
1306 * On Netra-440 platforms, a fan tray
1307 * may contain 2 fans (F0 and F1) but
1308 * we only receive a single notification
1309 * for removal of F0. If F1 is present,
1310 * peerh will be valid and we need to
1311 * process it as well.
1313 remove_fru_parents(peerh
);
1314 err
= ptree_delete_node(peerh
);
1315 if (err
== PICL_SUCCESS
) {
1316 (void) ptree_destroy_node(peerh
);
1318 syslog(LOG_ERR
, DELETE_PROP_FAIL
, err
);
1329 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
1332 post_frudr_event(char *ename
, picl_nodehdl_t parenth
, picl_nodehdl_t fruh
)
1337 ev_name
= strdup(ename
);
1338 if (ev_name
== NULL
)
1340 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME_TYPE
, NULL
)) {
1344 if (parenth
!= 0L &&
1345 nvlist_add_uint64(nvl
, PICLEVENTARG_PARENTHANDLE
, parenth
)) {
1351 nvlist_add_uint64(nvl
, PICLEVENTARG_FRUHANDLE
, fruh
)) {
1356 if (ptree_post_event(ev_name
, nvl
, sizeof (nvl
),
1357 frudr_completion_handler
) != 0) {
1364 add_ps_to_platform(char *unit
)
1366 picl_nodehdl_t parent_hdl
;
1367 picl_nodehdl_t child_hdl
;
1368 ptree_propinfo_t info
;
1369 int unit_size
= 1 + strlen(unit
);
1371 char unit_addr
[PICL_UNITADDR_LEN_MAX
];
1373 switch (sys_platform
) {
1374 case PLAT_SEATTLE1U
:
1375 case PLAT_SEATTLE2U
:
1376 res
= ptree_get_node_by_path(SEATTLE_PSU_PLATFORM
, &parent_hdl
);
1379 res
= ptree_get_node_by_path(BOSTON_PSU_PLATFORM
, &parent_hdl
);
1382 res
= ptree_get_node_by_path(PSU_PLATFORM
, &parent_hdl
);
1386 if (res
!= PICL_SUCCESS
)
1389 * seeprom nodes sit below this node,
1390 * is there one with the supplied unit address?
1392 res
= ptree_get_propval_by_name(parent_hdl
, PICL_PROP_CHILD
,
1393 &child_hdl
, sizeof (picl_nodehdl_t
));
1395 while (res
== PICL_SUCCESS
) {
1396 res
= ptree_get_propval_by_name(child_hdl
, PICL_PROP_PEER
,
1397 &child_hdl
, sizeof (picl_nodehdl_t
));
1398 if ((res
== PICL_SUCCESS
) &&
1399 ptree_get_propval_by_name(child_hdl
,
1400 PICL_PROP_UNIT_ADDRESS
, unit_addr
,
1401 sizeof (unit_addr
)) == PICL_SUCCESS
) {
1402 unit_addr
[sizeof (unit_addr
) - 1] = '\0';
1403 if (strcmp(unit_addr
, unit
) == 0)
1404 return; /* unit address exists already */
1409 * found platform location for PS seeprom node, create it
1411 if (ptree_create_and_add_node(parent_hdl
, PS_PLATFORM_NAME
,
1412 PICL_CLASS_SEEPROM
, &child_hdl
) != PICL_SUCCESS
)
1414 if (ptree_init_propinfo(&info
, PTREE_PROPINFO_VERSION
,
1415 PICL_PTYPE_CHARSTRING
, PICL_READ
, unit_size
,
1416 PICL_PROP_UNIT_ADDRESS
, NULL
, NULL
) != PICL_SUCCESS
)
1418 (void) ptree_create_and_add_prop(child_hdl
, &info
, unit
, NULL
);
1422 get_fantray_path(char *ap_id
, char *path
, int bufsz
)
1424 char ft_id
[FT_ID_BUFSZ
];
1426 (void) strlcpy(ft_id
, ap_id
, FT_ID_BUFSZ
);
1428 switch (sys_platform
) {
1429 case PLAT_SEATTLE1U
:
1430 if ((strncmp(ap_id
, "FT0", 3) == 0) ||
1431 (strncmp(ap_id
, "FT1", 3) == 0) ||
1432 (strncmp(ap_id
, "FT2", 3) == 0)) {
1433 (void) snprintf(path
, bufsz
, SEATTLE_FCB0_1U
, ft_id
);
1434 } else if ((strncmp(ap_id
, "FT3", 3) == 0) ||
1435 (strncmp(ap_id
, "FT4", 3) == 0) ||
1436 (strncmp(ap_id
, "FT5", 3) == 0)) {
1437 (void) snprintf(path
, bufsz
, SEATTLE_FCB1_1U
, ft_id
);
1439 (void) snprintf(path
, bufsz
, SEATTLE_PDB_1U
, ft_id
);
1443 case PLAT_SEATTLE2U
:
1444 if ((strncmp(ap_id
, "FT0", 3) == 0) ||
1445 (strncmp(ap_id
, "FT1", 3) == 0) ||
1446 (strncmp(ap_id
, "FT2", 3) == 0)) {
1447 (void) snprintf(path
, bufsz
, SEATTLE_FCB0_2U
, ft_id
);
1448 } else if ((strncmp(ap_id
, "FT3", 3) == 0) ||
1449 (strncmp(ap_id
, "FT4", 3) == 0) ||
1450 (strncmp(ap_id
, "FT5", 3) == 0)) {
1451 (void) snprintf(path
, bufsz
, SEATTLE_FCB1_2U
, ft_id
);
1453 (void) snprintf(path
, bufsz
, SEATTLE_PDB_2U
, ft_id
);
1458 (void) snprintf(path
, bufsz
, SYS_BOARD_PATH
, ft_id
);
1462 (void) snprintf(path
, bufsz
, CHASSIS_LOC_PATH
, ft_id
);
1468 * handle EC_DR picl events
1472 frudr_evhandler(const char *ename
, const void *earg
, size_t size
, void *cookie
)
1478 char path
[MAXPATHLEN
];
1479 picl_nodehdl_t fruh
;
1480 picl_nodehdl_t locnodeh
;
1483 picl_nodehdl_t childh
;
1485 boolean_t rmc_flag
= B_FALSE
;
1487 if (strcmp(ename
, PICLEVENT_DR_AP_STATE_CHANGE
) != 0) {
1491 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
)) {
1495 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_DATA_TYPE
, &dtype
)) {
1500 if (strcmp(dtype
, PICLEVENTARG_PICLEVENT_DATA
) != 0) {
1505 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_AP_ID
, &ap_id
)) {
1511 * check ap_id really is a hot-plug device
1513 if (strncmp(ap_id
, PS_NAME
, PS_NAME_LEN
) == 0) {
1514 fru_name
= PS_FRU_NAME
;
1515 } else if (strncmp(ap_id
, DISK_NAME
, DISK_NAME_LEN
) == 0) {
1516 fru_name
= DISK_FRU_NAME
;
1517 } else if (strncmp(ap_id
, SCC_NAME
, SCC_NAME_LEN
) == 0) {
1518 fru_name
= SCC_FRU_NAME
;
1519 } else if (strncmp(ap_id
, RMC_NAME
, RMC_NAME_LEN
) == 0) {
1520 fru_name
= RMC_FRU_NAME
;
1522 } else if (strncmp(ap_id
, FT_NAME
, FT_NAME_LEN
) == 0) {
1523 fru_name
= FT_FRU_NAME
;
1529 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_HINT
, &hint
)) {
1535 * OK - so this is an EC_DR event - let's handle it.
1537 if (rmc_flag
&& (sys_platform
!= PLAT_CHALUPA
) &&
1538 (sys_platform
!= PLAT_CHALUPA19
))
1539 sprintf_buf2(path
, SYS_BOARD_PATH
, ap_id
);
1541 if ((sys_platform
== PLAT_CHALUPA19
) &&
1542 (strncmp(ap_id
, PS_NAME
, PS_NAME_LEN
) == 0)) {
1543 sprintf_buf2(path
, CHASSIS_LOC_PATH
,
1544 ps_apid_to_nodename(ap_id
));
1545 } else if (strncmp(ap_id
, DISK_NAME
, DISK_NAME_LEN
) == 0) {
1546 switch (sys_platform
) {
1547 case PLAT_SEATTLE1U
:
1548 sprintf_buf2(path
, SEATTLE1U_HDDBP_PATH
, ap_id
);
1550 case PLAT_SEATTLE2U
:
1551 sprintf_buf2(path
, SEATTLE2U_HDDBP_PATH
, ap_id
);
1554 sprintf_buf2(path
, BOSTON_HDDBP_PATH
, ap_id
);
1557 sprintf_buf2(path
, CHASSIS_LOC_PATH
, ap_id
);
1560 } else if (strncmp(ap_id
, FT_NAME
, FT_NAME_LEN
) == 0) {
1561 get_fantray_path(ap_id
, path
, MAXPATHLEN
);
1563 sprintf_buf2(path
, CHASSIS_LOC_PATH
, ap_id
);
1567 if (ptree_get_node_by_path(path
, &locnodeh
) != PICL_SUCCESS
) {
1573 * now either add or delete the fru node as appropriate. If no
1574 * hint, treat as insert and update the tree if necessary.
1576 if (strcmp(hint
, DR_HINT_REMOVE
) == 0) {
1577 if (ptree_get_propval_by_name(locnodeh
, PICL_PROP_CHILD
,
1578 &fruh
, sizeof (picl_nodehdl_t
)) == PICL_SUCCESS
) {
1580 * fru was there - but has gone away
1582 post_frudr_event(PICL_FRU_REMOVED
, NULL
, fruh
);
1584 } else if (rmc_flag
) {
1586 * An event on the RMC location, just pass it on
1587 * it's not really a PICL_FRU_ADDED event, so offer
1588 * the child handle as well (if it exists).
1590 if (ptree_get_propval_by_name(locnodeh
, PICL_PROP_CHILD
,
1591 &fruh
, sizeof (picl_nodehdl_t
)) != PICL_SUCCESS
) {
1594 post_frudr_event(PICL_FRU_ADDED
, locnodeh
, fruh
);
1597 * fru has been inserted (or may need to update)
1598 * if node already there, then just return
1600 childh
= find_child_by_name(locnodeh
, fru_name
);
1601 if (childh
!= NULL
) {
1607 * On Netra-440, the fan-tray location nodes are
1608 * not deleted when fan-trays are physically
1609 * removed, so we do not need to create another
1612 if ((sys_platform
!= PLAT_CHALUPA19
) ||
1613 (strncmp(fru_name
, FT_FRU_NAME
, FT_FRU_NAME_LEN
) != 0)) {
1615 * create requested fru node
1617 err
= ptree_create_and_add_node(locnodeh
, fru_name
,
1618 PICL_CLASS_FRU
, &childh
);
1619 if (err
!= PICL_SUCCESS
) {
1620 syslog(LOG_ERR
, ADD_NODE_FAIL
, ap_id
, err
);
1627 * power supplies have operational status and fruid -
1628 * add OperationalStatus property and create i2c device node
1629 * before posting fru_added event
1631 if (strncmp(ap_id
, PS_NAME
, PS_NAME_LEN
) == 0) {
1632 index
= find_vol_prop_by_name(
1633 ps_apid_to_nodename(ap_id
));
1635 add_op_status_to_node(childh
,
1636 &idprop
->idp
[index
].volprop
);
1637 (void) create_i2c_node(ap_id
);
1638 add_ps_to_platform(ps_name_to_unitaddr(ap_id
));
1644 post_frudr_event(PICL_FRU_ADDED
, locnodeh
, NULL
);
1650 * Handle PICL_FRU_ADDED events.
1651 * These events are posted by the frudr_evhandler of this plugin in response to
1652 * PICLEVENT_DR_AP_STATE_CHANGE events. The sequence is as follows:
1653 * 1) frudr_evhandler catches PICLEVENT_DR_AP_STATE_CHANGE and creates a
1654 * child node below the relevant location.
1655 * 2) frudr_evhandler posts a PICL_FRU_ADDED event.
1656 * 3) envmon catches PICL_FRU_ADDED event, gropes the RMC configuration
1657 * and creates platform tree nodes (primarily for PSUs). (If the event
1658 * is for the RMC itself, envmon deletes existing platform nodes and
1659 * rebuilds from scratch.)
1660 * 4) this plugin catches PICL_FRU_ADDED event, looks for a related
1661 * configuration file and parses it. This adds Fru data properties (etc.).
1662 * 5) frudata catches the event and updates its FRUID data cache.
1666 fru_add_handler(const char *ename
, const void *earg
, size_t size
, void *cookie
)
1669 picl_nodehdl_t locnodeh
;
1670 picl_nodehdl_t rooth
;
1671 char path
[MAXPATHLEN
];
1674 if (strcmp(ename
, PICL_FRU_ADDED
) != 0)
1677 retval
= nvlist_lookup_uint64((nvlist_t
*)earg
,
1678 PICLEVENTARG_PARENTHANDLE
, &locnodeh
);
1679 if (retval
!= PICL_SUCCESS
)
1682 retval
= ptree_get_propval_by_name(locnodeh
, PICL_PROP_NAME
,
1683 path
, sizeof (path
));
1684 if (retval
!= PICL_SUCCESS
)
1687 fru_name
= strdup(path
);
1688 if (fru_name
== NULL
)
1692 * We're about to parse a fru-specific .conf file to populate
1693 * picl nodes relating to the dynamically added component. In the
1694 * case of the RMC, there is a problem: all of its /platform tree
1695 * nodes have just been replaced by envmon. It is now necessary to
1696 * repopulate Devices tables in /frutree.
1697 * picld_pluginutil_parse_config_file doesn't handle repopulating
1698 * existing tables, so as a work round, delete all tables found
1699 * under /frutree. This works on Enchilada Server as the tables
1700 * are all created from parsing a .conf file, and we're about to
1703 if (strcmp(fru_name
, RMC_NAME
) == 0) {
1705 retval
= ptree_get_node_by_path(FRUTREE_PATH
, &rooth
);
1706 if (retval
== PICL_SUCCESS
) {
1707 remove_tables(rooth
);
1712 * Re-establish the HPU(FRU) volatile properties.
1713 * This needs to be done before the .conf file is parsed because
1714 * it has a side effect of re-creating any missing power-supply
1715 * fru node. The .conf file can then hang properties beneath.
1720 * see if there's a .conf file for this fru
1722 if (get_config_file(path
, fru_name
) == 0) {
1723 if ((ptree_get_root(&rooth
) != PICL_SUCCESS
) ||
1724 (picld_pluginutil_parse_config_file(rooth
, path
) !=
1726 syslog(LOG_ERR
, PARSE_CONF_FAIL
, path
);
1734 * Handle PICLEVENT_SYSEVENT_DEVICE_ADDED events.
1738 frutree_evhandler(const char *ename
, const void *earg
, size_t size
,
1742 picl_nodehdl_t rooth
;
1743 char path
[MAXPATHLEN
];
1752 if (strcmp(ename
, PICLEVENT_SYSEVENT_DEVICE_ADDED
) != 0)
1755 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
))
1758 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_DATA_TYPE
, &dtype
)) {
1763 if (strcmp(dtype
, PICLEVENTARG_PICLEVENT_DATA
) != 0) {
1768 if (nvlist_lookup_string(nvlp
, PICLEVENTARG_DEVFS_PATH
, &dpath
)) {
1773 fru_name
= strdup(dpath
);
1774 if (fru_name
== NULL
) {
1782 * fru_name is of the form
1783 * "/pci@1e,600000/usb@a/mouse@2"
1785 * "/pci@1e,600000/usb@a/device@2/mouse@0"
1786 * reduce it to "usb-a-2"
1788 if ((sys_platform
== PLAT_SEATTLE1U
) ||
1789 (sys_platform
== PLAT_SEATTLE2U
) ||
1790 (sys_platform
== PLAT_BOSTON
)) {
1791 for (i
= 0; i
< MAX_USB_PORTS
; i
++) {
1792 sprintf(fru_name
, "%s%d", USB_CONF_FILE_NAME
, i
+1);
1793 if (get_config_file(path
, fru_name
) == 0) {
1794 if ((ptree_get_root(&rooth
) != PICL_SUCCESS
) ||
1795 (picld_pluginutil_parse_config_file(rooth
,
1796 path
) != PICL_SUCCESS
)) {
1797 syslog(LOG_ERR
, PARSE_CONF_FAIL
, path
);
1805 ptr
= strchr(ptr
, '/');
1808 (void) memmove(fru_name
, ptr
, strlen(ptr
) + 1);
1809 ptr
= strchr(fru_name
, '@');
1813 ptr
= strchr(ptr
, '/');
1818 ptr
= strchr(ptr
, '@');
1821 (void) memmove(ptr2
,
1822 ptr
, strlen(ptr
)+1);
1834 if (done
== B_FALSE
) {
1840 * see if there's a .conf file for this fru
1843 if (get_config_file(path
, fru_name
) == 0) {
1844 if ((ptree_get_root(&rooth
) != PICL_SUCCESS
) ||
1845 (picld_pluginutil_parse_config_file(rooth
, path
) !=
1847 syslog(LOG_ERR
, PARSE_CONF_FAIL
, path
);
1856 set_led(char *name
, char *ptr
, char *value
)
1858 char path
[MAXPATHLEN
];
1859 picl_prophdl_t proph
;
1860 ptree_propinfo_t propinfo
;
1861 picl_prophdl_t tableh
;
1862 picl_nodehdl_t locnodeh
;
1863 picl_nodehdl_t nodeh
;
1864 picl_prophdl_t tblh
;
1867 char label
[PICL_PROPNAMELEN_MAX
];
1868 char class[PICL_PROPNAMELEN_MAX
];
1870 /* find the location node */
1871 switch (sys_platform
) {
1873 case PLAT_CHALUPA19
:
1874 sprintf_buf2(path
, CHASSIS_LOC_PATH
, name
);
1876 case PLAT_SEATTLE1U
:
1877 sprintf_buf2(path
, SEATTLE1U_HDDBP_PATH
, name
);
1879 case PLAT_SEATTLE2U
:
1880 sprintf_buf2(path
, SEATTLE2U_HDDBP_PATH
, name
);
1883 sprintf_buf2(path
, BOSTON_HDDBP_PATH
, name
);
1886 sprintf_buf2(path
, CHASSIS_LOC_PATH
, name
);
1890 if (ptree_get_node_by_path(path
, &locnodeh
) != PICL_SUCCESS
) {
1891 return (PICL_FAILURE
);
1895 * if no fru node, then turn led off
1897 if (find_child_by_name(locnodeh
, DISK_FRU_NAME
) != NULL
)
1900 value_ptr
= PICL_PROPVAL_OFF
;
1902 /* get its Devices table */
1903 if (ptree_get_prop_by_name(locnodeh
, PICL_PROP_DEVICES
, &tableh
) !=
1905 return (PICL_FAILURE
);
1906 if (ptree_get_propval(tableh
, &tblh
, sizeof (tblh
)) != PICL_SUCCESS
)
1907 return (PICL_FAILURE
);
1909 /* get first col, first row */
1910 if (ptree_get_next_by_col(tblh
, &tblh
) != PICL_SUCCESS
)
1911 return (PICL_FAILURE
);
1914 * starting at next col, get every entry in the column
1916 for (retval
= ptree_get_next_by_row(tblh
, &tblh
);
1917 retval
== PICL_SUCCESS
;
1918 retval
= ptree_get_next_by_col(tblh
, &tblh
)) {
1920 * get the target node handle
1922 if (ptree_get_propval(tblh
, &nodeh
, sizeof (nodeh
))
1929 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_CLASSNAME
,
1930 class, sizeof (class)) != PICL_SUCCESS
)
1932 if (strcmp(class, "led") != 0)
1936 * check its the right led
1938 if (ptree_get_propval_by_name(nodeh
, PICL_PROP_LABEL
,
1939 label
, sizeof (label
)) != PICL_SUCCESS
)
1941 if (strcmp(label
, ptr
) == 0) {
1945 if (ptree_get_prop_by_name(nodeh
, PICL_PROP_STATE
,
1946 &proph
) != PICL_SUCCESS
)
1948 if (ptree_get_propinfo(proph
, &propinfo
) !=
1951 retval
= ptree_update_propval_by_name(nodeh
,
1952 PICL_PROP_STATE
, value_ptr
, propinfo
.piclinfo
.size
);
1956 return (PICL_FAILURE
);
1960 * function to find first node of specified class beneath supplied node
1963 get_node_by_class(picl_nodehdl_t nodeh
, const char *classname
,
1964 picl_nodehdl_t
*foundnodeh
)
1967 char clname
[PICL_CLASSNAMELEN_MAX
+1];
1968 picl_nodehdl_t childh
;
1971 * go through the children
1973 err
= ptree_get_propval_by_name(nodeh
, PICL_PROP_CHILD
, &childh
,
1974 sizeof (picl_nodehdl_t
));
1976 while (err
== PICL_SUCCESS
) {
1977 err
= ptree_get_propval_by_name(childh
, PICL_PROP_CLASSNAME
,
1978 clname
, sizeof (clname
));
1980 if ((err
== PICL_SUCCESS
) && (strcmp(clname
, classname
) == 0)) {
1981 *foundnodeh
= childh
;
1982 return (PICL_SUCCESS
);
1985 err
= get_node_by_class(childh
, classname
, foundnodeh
);
1986 if (err
== PICL_SUCCESS
)
1987 return (PICL_SUCCESS
);
1989 err
= ptree_get_propval_by_name(childh
, PICL_PROP_PEER
,
1990 &childh
, sizeof (picl_nodehdl_t
));
1993 return (PICL_NODENOTFOUND
);
1997 * get system-controller node
2000 get_sys_controller_node(picl_nodehdl_t
*nodeh
)
2004 /* get platform node */
2005 err
= ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM
, nodeh
);
2006 if (err
!= PICL_SUCCESS
)
2008 err
= get_node_by_class(*nodeh
, PICL_CLASS_SERVICE_PROCESSOR
, nodeh
);
2013 * create pathname string for system-controller device
2016 create_sys_controller_pathname(picl_nodehdl_t sysconh
)
2019 char namebuf
[PATH_MAX
];
2023 struct stat statbuf
;
2026 * prefix devfs-path name with /devices
2028 (void) strlcpy(namebuf
, DEV_PREFIX
, PATH_MAX
);
2031 * append devfs-path property
2033 len
= strlen(namebuf
);
2034 if (ptree_get_propval_by_name(sysconh
, str_devfs_path
, namebuf
+ len
,
2035 sizeof (namebuf
) - len
) != PICL_SUCCESS
) {
2040 * locate final component of name
2042 ptr
= strrchr(namebuf
, '/');
2045 *ptr
= '\0'; /* terminate at end of directory path */
2046 len
= strlen(ptr
+ 1); /* length of terminal name */
2047 dirp
= opendir(namebuf
);
2051 *ptr
++ = '/'; /* restore '/' and advance to final name */
2053 while ((dp
= readdir(dirp
)) != NULL
) {
2055 * look for a name which starts with the string at *ptr
2057 if (strlen(dp
->d_name
) < len
)
2058 continue; /* skip short names */
2059 if (strncmp(dp
->d_name
, ptr
, len
) == 0) {
2061 * Got a match, restore full pathname and stat the
2062 * entry. Reject if not a char device
2064 (void) strlcpy(ptr
, dp
->d_name
,
2065 sizeof (namebuf
) - (ptr
- namebuf
));
2066 if (stat(namebuf
, &statbuf
) < 0)
2067 continue; /* reject if can't stat it */
2068 if (!S_ISCHR(statbuf
.st_mode
))
2069 continue; /* not a character device */
2071 * go with this entry
2073 (void) closedir(dirp
);
2074 return (strdup(namebuf
));
2077 (void) closedir(dirp
);
2082 * create pathname string for bezel leds device
2085 create_bezel_leds_pathname(const char *dirpath
, const char *devname
)
2087 char namebuf
[PATH_MAX
];
2092 struct stat statbuf
;
2095 * start with directory name
2097 (void) strlcpy(namebuf
, dirpath
, PATH_MAX
);
2100 * append devfs-path property
2102 lendirpath
= strlen(namebuf
);
2103 dirp
= opendir(namebuf
);
2108 len
= strlen(devname
);
2110 while ((dp
= readdir(dirp
)) != NULL
) {
2112 * look for a name which starts with the gpio string
2114 if (strlen(dp
->d_name
) < len
)
2115 continue; /* skip short names */
2116 if (strncmp(dp
->d_name
, devname
, len
) == 0) {
2118 * Got a match, restore full pathname and stat the
2119 * entry. Reject if not a char device
2121 (void) strlcpy(namebuf
+ lendirpath
, dp
->d_name
,
2122 sizeof (namebuf
) - lendirpath
);
2123 if (stat(namebuf
, &statbuf
) < 0)
2124 continue; /* reject if can't stat it */
2125 if (!S_ISCHR(statbuf
.st_mode
))
2126 continue; /* not a character device */
2128 * go with this entry
2130 (void) closedir(dirp
);
2131 return (strdup(namebuf
));
2134 (void) closedir(dirp
);
2139 * initialise structure associated with nodes requiring OperationalStatus
2151 boolean_t disk_flag
;
2153 envmon_sysinfo_t sysinfo
;
2156 if (idprop
!= NULL
) {
2158 * This must be a restart, clean up earlier allocation
2164 if (sc_device_name
== NULL
)
2167 fd
= open(sc_device_name
, O_RDONLY
);
2170 syslog(LOG_ERR
, EM_NO_SC_DEV
);
2176 res
= ioctl(fd
, ENVMONIOCSYSINFO
, &sysinfo
);
2179 syslog(LOG_ERR
, EM_NO_SYSINFO
, strerror(errno
));
2186 entries
= sysinfo
.maxHPU
;
2187 len
= offsetof(idp_lkup_t
, idp
) + entries
* sizeof (id_props_t
);
2188 idprop
= calloc(len
, 1);
2189 if (idprop
== NULL
) {
2196 idprop
->maxnum
= entries
;
2197 hpu
.id
.name
[0] = '\0'; /* request for first name */
2198 res
= ioctl(fd
, ENVMONIOCHPU
, &hpu
);
2201 * The HPU node for the RMC is a special case. Its handle is
2202 * generated by the rmclomv driver. Rather than building
2203 * knowledge of its frutree hierarchic name into the driver, we
2204 * put that knowledge here.
2206 while ((res
== 0) && (index
< entries
) &&
2207 (hpu
.next_id
.name
[0] != '\0')) {
2208 hpu
.id
= hpu
.next_id
;
2209 res
= ioctl(fd
, ENVMONIOCHPU
, &hpu
);
2211 ((hpu
.sensor_status
& ENVMON_NOT_PRESENT
) == 0)) {
2212 add_op_status(&hpu
, &index
);
2216 idprop
->num
= index
;
2222 disk_leds_init(void)
2226 if (!g_mutex_init
) {
2227 if ((pthread_cond_init(&g_cv
, NULL
) == 0) &&
2228 (pthread_cond_init(&g_cv_ack
, NULL
) == 0) &&
2229 (pthread_mutex_init(&g_mutex
, NULL
) == 0)) {
2230 g_mutex_init
= B_TRUE
;
2237 * Initialise to -1 so the led thread will set correctly.
2238 * Do this before creating the disk_leds thread,
2239 * so there's no race.
2241 for (i
= 0; i
< N_DISKS
; i
++)
2244 if (ledsthr_created
) {
2246 * this is a restart, wake up sleeping threads
2248 err
= pthread_mutex_lock(&g_mutex
);
2250 syslog(LOG_ERR
, EM_MUTEX_FAIL
, strerror(errno
));
2253 g_finish_now
= B_FALSE
;
2254 (void) pthread_cond_broadcast(&g_cv
);
2255 (void) pthread_mutex_unlock(&g_mutex
);
2257 if ((pthread_attr_init(&ledsthr_attr
) != 0) ||
2258 (pthread_attr_setscope(&ledsthr_attr
,
2259 PTHREAD_SCOPE_SYSTEM
) != 0))
2261 if ((err
= pthread_create(&ledsthr_tid
, &ledsthr_attr
,
2262 disk_leds_thread
, NULL
)) != 0) {
2263 syslog(LOG_ERR
, EM_THREAD_CREATE_FAILED
,
2267 ledsthr_created
= B_TRUE
;
2272 disk_leds_fini(void)
2277 * turn the leds off as we'll no longer be monitoring them
2279 for (i
= 0; i
< N_DISKS
; i
++)
2280 (void) set_led(disk_name
[i
], REMOK_LED
, PICL_PROPVAL_OFF
);
2283 * disk_leds_thread() never started or an error occured so
2284 * that it's not running
2286 if (!disk_leds_thread_running
)
2290 * tell led thread to pause
2292 if (!ledsthr_created
)
2294 err
= pthread_mutex_lock(&g_mutex
);
2296 syslog(LOG_ERR
, EM_MUTEX_FAIL
, strerror(errno
));
2299 g_finish_now
= B_TRUE
;
2300 disk_leds_thread_ack
= B_FALSE
;
2301 (void) pthread_cond_broadcast(&g_cv
);
2304 * and wait for them to acknowledge
2306 while (!disk_leds_thread_ack
) {
2307 (void) pthread_cond_wait(&g_cv_ack
, &g_mutex
);
2309 (void) pthread_mutex_unlock(&g_mutex
);
2313 update_disk_node(char *fruname
, char *devpath
)
2315 picl_nodehdl_t slotndh
;
2316 picl_nodehdl_t diskndh
;
2317 picl_nodehdl_t devhdl
;
2318 picl_prophdl_t tblhdl
;
2319 picl_prophdl_t tblhdl2
;
2320 picl_prophdl_t tblproph
;
2322 char path
[MAXPATHLEN
];
2324 switch (sys_platform
) {
2326 case PLAT_CHALUPA19
:
2327 sprintf_buf2(path
, CHASSIS_LOC_PATH
, fruname
);
2329 case PLAT_SEATTLE1U
:
2330 sprintf_buf2(path
, SEATTLE1U_HDDBP_PATH
, fruname
);
2332 case PLAT_SEATTLE2U
:
2333 sprintf_buf2(path
, SEATTLE2U_HDDBP_PATH
, fruname
);
2336 sprintf_buf2(path
, BOSTON_HDDBP_PATH
, fruname
);
2339 sprintf_buf2(path
, CHASSIS_LOC_PATH
, fruname
);
2343 if (ptree_get_node_by_path(path
, &slotndh
) != PICL_SUCCESS
) {
2346 diskndh
= find_child_by_name(slotndh
, DISK_FRU_NAME
);
2347 if (diskndh
== NULL
) {
2350 err
= ptree_get_node_by_path(devpath
, &devhdl
);
2351 if (err
== PICL_SUCCESS
) {
2352 err
= ptree_get_propval_by_name(diskndh
,
2353 PICL_PROP_DEVICES
, &tblhdl
, sizeof (tblhdl
));
2354 if (err
!= PICL_SUCCESS
)
2356 err
= ptree_get_next_by_col(tblhdl
, &tblhdl2
);
2357 if (err
!= PICL_SUCCESS
) {
2358 err
= create_table_entry(tblhdl
, devhdl
,
2360 if (err
!= PICL_SUCCESS
)
2362 err
= add_prop_ref(devhdl
, diskndh
,
2363 PICL_REFPROP_FRU_PARENT
);
2364 if (err
!= PICL_SUCCESS
)
2369 * no mechanism for deleting row - so delete
2370 * whole table and start again
2372 err
= ptree_get_prop_by_name(diskndh
, PICL_PROP_DEVICES
,
2374 if (err
!= PICL_SUCCESS
)
2376 err
= ptree_delete_prop(tblproph
);
2377 if (err
!= PICL_SUCCESS
)
2379 (void) ptree_destroy_prop(tblproph
);
2380 err
= create_table(diskndh
, &tblhdl
, PICL_PROP_DEVICES
);
2381 if (err
!= PICL_SUCCESS
)
2387 * We will light the OK2REMOVE LED for disks configured
2388 * into a raid if (and only if) the driver reports
2389 * that the disk has failed.
2392 raid_ok2rem_policy(raid_config_t config
, int target
)
2396 for (i
= 0; i
< config
.ndisks
; i
++) {
2397 int d
= config
.disk
[i
];
2398 int dstatus
= config
.diskstatus
[i
];
2402 case RAID_DISKSTATUS_MISSING
:
2403 /* If LED is on, turn it off */
2404 if (disk_ready
[d
] == B_FALSE
) {
2405 if (set_led(disk_name
[d
], REMOK_LED
,
2406 PICL_PROPVAL_OFF
) == PICL_SUCCESS
) {
2407 disk_ready
[d
] = B_TRUE
;
2411 case RAID_DISKSTATUS_GOOD
:
2412 if (disk_ready
[d
] != B_TRUE
) {
2413 if (set_led(disk_name
[d
], REMOK_LED
,
2414 PICL_PROPVAL_OFF
) == PICL_SUCCESS
) {
2415 disk_ready
[d
] = B_TRUE
;
2419 case RAID_DISKSTATUS_FAILED
:
2420 if (disk_ready
[d
] != B_FALSE
) {
2421 if (set_led(disk_name
[d
], REMOK_LED
,
2422 PICL_PROPVAL_ON
) == PICL_SUCCESS
) {
2423 disk_ready
[d
] = B_FALSE
;
2437 check_raid(int target
)
2439 raid_config_t config
;
2444 switch (sys_platform
) {
2446 case PLAT_CHALUPA19
:
2447 fd
= open(V440_DISK_DEVCTL
, O_RDONLY
);
2449 case PLAT_SEATTLE1U
:
2450 case PLAT_SEATTLE2U
:
2451 fd
= open(SEATTLE_DISK_DEVCTL
, O_RDONLY
);
2454 if (boston_1068e_flag
) {
2455 fd
= open(BOSTON_DISK_DEVCTL_1068E
, O_RDONLY
);
2457 fd
= open(BOSTON_DISK_DEVCTL_1068X
, O_RDONLY
);
2469 if (ioctl(fd
, RAID_NUMVOLUMES
, &numvols
)) {
2474 for (i
= 0; i
< numvols
; i
++) {
2476 if (ioctl(fd
, RAID_GETCONFIG
, &config
)) {
2480 if (raid_ok2rem_policy(config
, target
)) {
2492 disk_leds_thread(void *args
)
2506 static char *mpxu_devs
[] = {
2507 "/pci@1c,600000/scsi@2/sd@0,0",
2508 "/pci@1c,600000/scsi@2/sd@1,0",
2509 "/pci@1c,600000/scsi@2/sd@2,0",
2510 "/pci@1c,600000/scsi@2/sd@3,0"
2513 static char *ents_devs
[] = {
2514 "/pci@1d,700000/scsi@4/sd@0,0",
2515 "/pci@1d,700000/scsi@4/sd@1,0",
2516 "/pci@1d,700000/scsi@4/sd@2,0",
2517 "/pci@1d,700000/scsi@4/sd@3,0",
2518 "/pci@1d,700000/scsi@4/sd@8,0",
2519 "/pci@1d,700000/scsi@4/sd@9,0",
2520 "/pci@1d,700000/scsi@4/sd@a,0",
2521 "/pci@1d,700000/scsi@4/sd@b,0"
2524 static char *v440_devs
[] = {
2525 "/pci@1f,700000/scsi@2/sd@0,0",
2526 "/pci@1f,700000/scsi@2/sd@1,0",
2527 "/pci@1f,700000/scsi@2/sd@2,0",
2528 "/pci@1f,700000/scsi@2/sd@3,0"
2531 static char *n210_devs
[] = {
2532 "/pci@1c,600000/LSILogic,sas@1/sd@0,0",
2533 "/pci@1c,600000/LSILogic,sas@1/sd@1,0"
2536 static char *seattle_devs
[] = {
2537 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@0,0",
2538 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@1,0",
2539 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@2,0",
2540 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@3,0"
2543 static char *boston_devs_1068e
[] = {
2544 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@0,0",
2545 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@1,0",
2546 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@2,0",
2547 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@3,0",
2548 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@4,0",
2549 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@5,0",
2550 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@6,0",
2551 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@7,0"
2553 static char *boston_devs_1068x
[] = {
2554 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@0,0",
2555 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@1,0",
2556 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@2,0",
2557 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@3,0",
2558 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@4,0",
2559 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@5,0",
2560 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@6,0",
2561 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@7,0"
2564 char *ddev
[N_DISKS
]; /* "/devices" */
2565 char *pdev
[N_DISKS
]; /* "/platform" */
2567 switch (sys_platform
) {
2570 disk_dev
= ents_devs
;
2571 n_disks
= N_ENTS_DISKS
;
2575 case PLAT_CHALUPA19
:
2577 disk_dev
= v440_devs
;
2578 n_disks
= N_CHALUPA_DISKS
;
2582 disk_dev
= n210_devs
;
2583 n_disks
= N_EN19_DISKS
;
2586 case PLAT_SEATTLE1U
:
2587 case PLAT_SEATTLE2U
:
2589 disk_dev
= seattle_devs
;
2590 n_disks
= (sys_platform
== PLAT_SEATTLE1U
) ?
2591 N_SEATTLE1U_DISKS
: N_SEATTLE2U_DISKS
;
2596 * If we can open the devctl path for the built-in 1068E
2597 * controller then assume we're a 1068E-equipped Boston
2598 * and make all the paths appropriate for that hardware.
2599 * Otherwise assume we are a 1068X-equipped Boston and
2600 * make all of the paths appropriate for a 1068X PCI-X
2601 * controller in PCI slot 4.
2603 * The flag is also used in the check_raid() function.
2605 if ((fd
= open(BOSTON_DISK_DEVCTL_1068E
, O_RDONLY
)) != -1) {
2606 boston_1068e_flag
= 1;
2607 disk_dev
= boston_devs_1068e
;
2609 boston_1068e_flag
= 0;
2610 disk_dev
= boston_devs_1068x
;
2614 n_disks
= N_BOSTON_DISKS
;
2617 default: /* PLAT_ENXS/PLAT_EN19 */
2618 disk_dev
= mpxu_devs
;
2619 n_disks
= (sys_platform
== PLAT_EN19
) ?
2620 N_EN19_DISKS
: N_MPXU_DISKS
;
2624 * make up disk names
2627 for (i
= 0; i
< n_disks
; i
++) {
2628 char buffer
[MAXPATHLEN
];
2629 sprintf(buffer
, "/devices%s", disk_dev
[i
]);
2630 ddev
[i
] = strdup(buffer
);
2631 sprintf(buffer
, "/platform%s", disk_dev
[i
]);
2632 pdev
[i
] = strdup(buffer
);
2635 disk_leds_thread_running
= B_TRUE
;
2638 for (i
= 0; i
< n_disks
; i
++) {
2640 * If it's one of the RAID disks, we have already
2641 * applied the ok2remove policy.
2643 if (do_raid
&& check_raid(i
)) {
2647 dhdl
= devctl_device_acquire(ddev
[i
], 0);
2648 devctl_device_getstate(dhdl
, &statep
);
2649 devctl_release(dhdl
);
2651 if (statep
& DEVICE_OFFLINE
) {
2652 if (disk_ready
[i
] != B_FALSE
) {
2653 update_disk_node(disk_name
[i
], pdev
[i
]);
2654 if (set_led(disk_name
[i
], REMOK_LED
,
2655 PICL_PROPVAL_ON
) == PICL_SUCCESS
)
2656 disk_ready
[i
] = B_FALSE
;
2658 } else if (statep
& DEVICE_ONLINE
) {
2659 if (disk_ready
[i
] != B_TRUE
) {
2660 update_disk_node(disk_name
[i
], pdev
[i
]);
2661 if (set_led(disk_name
[i
], REMOK_LED
,
2662 PICL_PROPVAL_OFF
) == PICL_SUCCESS
)
2663 disk_ready
[i
] = B_TRUE
;
2669 * wait a bit until we check again
2672 (void) poll(NULL
, 0, DISK_POLL_TIME
);
2678 (void) pthread_mutex_lock(&g_mutex
);
2680 while (g_finish_now
) {
2682 * notify _fini routine that we've paused
2684 disk_leds_thread_ack
= B_TRUE
;
2685 (void) pthread_cond_signal(&g_cv_ack
);
2688 * and go to sleep in case we get restarted
2690 (void) pthread_cond_wait(&g_cv
, &g_mutex
);
2692 (void) pthread_mutex_unlock(&g_mutex
);
2695 return ((void *)err
);
2699 * Given the powersupply name, convert to addr
2702 ps_name_to_addr(char *name
)
2705 if ((strcmp(name
, PS0_NAME
) == 0) ||
2706 (strcmp(name
, PSU0_NAME
) == 0)) {
2707 switch (sys_platform
) {
2708 case PLAT_SEATTLE1U
:
2709 case PLAT_SEATTLE2U
:
2710 ps_addr
= SEATTLE_PS0_ADDR
;
2713 ps_addr
= BOSTON_PS0_ADDR
;
2719 } else if ((strcmp(name
, PS1_NAME
) == 0) ||
2720 (strcmp(name
, PSU1_NAME
) == 0)) {
2721 switch (sys_platform
) {
2722 case PLAT_SEATTLE1U
:
2723 case PLAT_SEATTLE2U
:
2724 ps_addr
= SEATTLE_PS1_ADDR
;
2727 ps_addr
= BOSTON_PS1_ADDR
;
2733 } else if ((strcmp(name
, PS2_NAME
) == 0) ||
2734 (strcmp(name
, PSU2_NAME
) == 0)) {
2735 switch (sys_platform
) {
2737 ps_addr
= BOSTON_PS2_ADDR
;
2743 } else if ((strcmp(name
, PS3_NAME
) == 0) ||
2744 (strcmp(name
, PSU3_NAME
) == 0)) {
2745 switch (sys_platform
) {
2747 ps_addr
= BOSTON_PS3_ADDR
;
2759 * Given powersupply name, convert to unit addr
2762 ps_name_to_unitaddr(char *name
)
2766 if (strcmp(name
, PS0_NAME
) == 0) {
2767 switch (sys_platform
) {
2768 case PLAT_SEATTLE1U
:
2769 case PLAT_SEATTLE2U
:
2770 unitaddr
= SEATTLE_PS0_UNITADDR
;
2773 unitaddr
= BOSTON_PS0_UNITADDR
;
2776 unitaddr
= PS0_UNITADDR
;
2779 } else if (strcmp(name
, PS1_NAME
) == 0) {
2780 switch (sys_platform
) {
2781 case PLAT_SEATTLE1U
:
2782 case PLAT_SEATTLE2U
:
2783 unitaddr
= SEATTLE_PS1_UNITADDR
;
2786 unitaddr
= BOSTON_PS1_UNITADDR
;
2789 unitaddr
= PS1_UNITADDR
;
2792 } else if (strcmp(name
, PS2_NAME
) == 0) {
2793 switch (sys_platform
) {
2795 unitaddr
= BOSTON_PS2_UNITADDR
;
2798 unitaddr
= PS2_UNITADDR
;
2801 } else if (strcmp(name
, PS3_NAME
) == 0) {
2802 switch (sys_platform
) {
2804 unitaddr
= BOSTON_PS3_UNITADDR
;
2807 unitaddr
= PS3_UNITADDR
;
2818 * converts apid to real FRU name in PICL tree. The
2819 * name of powersupply devices on chalupa19 are
2823 ps_apid_to_nodename(char *apid
)
2827 if (sys_platform
!= PLAT_CHALUPA19
)
2830 if (strcmp(apid
, PS0_NAME
) == 0)
2831 nodename
= PSU0_NAME
;
2832 else if (strcmp(apid
, PS1_NAME
) == 0)
2833 nodename
= PSU1_NAME
;
2834 else if (strcmp(apid
, PS2_NAME
) == 0)
2835 nodename
= PSU2_NAME
;
2836 else if (strcmp(apid
, PS3_NAME
) == 0)
2837 nodename
= PSU3_NAME
;
2845 * Create SEEPROM node at insertion time.
2848 create_i2c_node(char *ap_id
)
2851 devctl_ddef_t ddef_hdl
;
2852 devctl_hdl_t bus_hdl
;
2853 devctl_hdl_t dev_hdl
;
2854 char dev_path
[MAXPATHLEN
];
2857 /* create seeprom node */
2859 nd_reg
[1] = ps_name_to_addr(ap_id
);
2861 switch (sys_platform
) {
2862 case PLAT_SEATTLE1U
:
2863 case PLAT_SEATTLE2U
:
2864 bus_hdl
= devctl_bus_acquire(SEATTLE_PSU_I2C_BUS_DEV
, 0);
2865 compatible
= SEATTLE_PSU_COMPATIBLE
;
2868 bus_hdl
= devctl_bus_acquire(BOSTON_PSU_I2C_BUS_DEV
, 0);
2869 compatible
= BOSTON_PSU_COMPATIBLE
;
2872 bus_hdl
= devctl_bus_acquire(PSU_I2C_BUS_DEV
, 0);
2873 compatible
= PSU_COMPATIBLE
;
2877 if (bus_hdl
== NULL
)
2878 return (DDI_FAILURE
);
2880 /* device definition properties */
2881 ddef_hdl
= devctl_ddef_alloc(PS_DEVICE_NAME
, 0);
2882 (void) devctl_ddef_string(ddef_hdl
, "compatible", compatible
);
2883 (void) devctl_ddef_string(ddef_hdl
, "device_type", "seeprom");
2884 (void) devctl_ddef_int_array(ddef_hdl
, "reg", 2, nd_reg
);
2886 /* create the device node */
2887 if (devctl_bus_dev_create(bus_hdl
, ddef_hdl
, 0, &dev_hdl
))
2888 return (DDI_FAILURE
);
2890 if (devctl_get_pathname(dev_hdl
, dev_path
, MAXPATHLEN
) == NULL
)
2891 return (DDI_FAILURE
);
2893 devctl_release(dev_hdl
);
2894 devctl_ddef_free(ddef_hdl
);
2895 devctl_release(bus_hdl
);
2896 return (DDI_SUCCESS
);
2900 * Delete SEEPROM node at insertion time.
2903 delete_i2c_node(char *ap_id
)
2905 devctl_hdl_t dev_hdl
;
2906 char buf
[MAXPATHLEN
];
2908 switch (sys_platform
) {
2909 case PLAT_SEATTLE1U
:
2910 case PLAT_SEATTLE2U
:
2911 sprintf_buf2(buf
, SEATTLE_PSU_DEV
, ps_name_to_addr(ap_id
));
2914 sprintf_buf2(buf
, BOSTON_PSU_DEV
, ps_name_to_addr(ap_id
));
2917 sprintf_buf2(buf
, PSU_DEV
, ps_name_to_addr(ap_id
));
2921 dev_hdl
= devctl_device_acquire(buf
, 0);
2922 if (dev_hdl
== NULL
) {
2927 * If the seeprom driver is not loaded, calls to
2928 * devctl_device_remove fails for seeprom devices
2930 if (devctl_device_remove(dev_hdl
)) {
2931 di_init_driver(SEEPROM_DRIVER_NAME
, 0);
2932 devctl_device_remove(dev_hdl
);
2934 devctl_release(dev_hdl
);
2938 add_op_status(envmon_hpu_t
*hpu
, int *index
)
2942 boolean_t disk_flag
;
2943 char node_name
[MAXPATHLEN
];
2946 rmc_flag
= (strcmp(hpu
->id
.name
, RMC_NAME
) == 0);
2947 ps_flag
= (strncmp(hpu
->id
.name
, PS_NAME
,
2949 disk_flag
= (strncmp(hpu
->id
.name
, DISK_NAME
,
2950 DISK_NAME_LEN
) == 0);
2951 if (rmc_flag
|| ps_flag
) {
2952 idprop
->idp
[*index
].envhandle
= hpu
->id
;
2953 flag
= rmc_flag
&& ((sys_platform
!= PLAT_CHALUPA
) &&
2954 (sys_platform
!= PLAT_CHALUPA19
));
2955 sprintf_buf2(node_name
,
2956 flag
? SYS_BOARD_PATH
: CHASSIS_LOC_PATH
, ps_flag
?
2957 ps_apid_to_nodename(hpu
->id
.name
) : hpu
->id
.name
);
2959 add_op_status_by_name(node_name
, ps_flag
? PS_FRU_NAME
: NULL
,
2960 &idprop
->idp
[(*index
)++].volprop
);
2961 } else if (disk_flag
) {
2962 idprop
->idp
[*index
].envhandle
= hpu
->id
;
2963 switch (sys_platform
) {
2965 case PLAT_CHALUPA19
:
2966 sprintf_buf2(node_name
, CHASSIS_LOC_PATH
, hpu
->id
.name
);
2968 case PLAT_SEATTLE1U
:
2969 sprintf_buf2(node_name
, SEATTLE1U_HDDBP_PATH
, \
2972 case PLAT_SEATTLE2U
:
2973 sprintf_buf2(node_name
, SEATTLE2U_HDDBP_PATH
, \
2977 sprintf_buf2(node_name
, BOSTON_HDDBP_PATH
, \
2981 sprintf_buf2(node_name
, SYS_BOARD_PATH
, hpu
->id
.name
);
2984 add_op_status_by_name(node_name
, DISK_FRU_NAME
,
2985 &idprop
->idp
[(*index
)++].volprop
);