8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / mpxu / frudr / piclfrudr.c
blob28adb31207926907eccd8960ad9fccb69bdb77ae
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <stdio.h>
27 #include <stddef.h>
28 #include <syslog.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <libintl.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <picl.h>
35 #include <picltree.h>
36 #include <picld_pluginutil.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <dirent.h>
41 #include <sys/sysevent/dr.h>
42 #include <pthread.h>
43 #include <libdevinfo.h>
44 #include <limits.h>
45 #include <sys/systeminfo.h>
46 #include <sys/envmon.h>
47 #include <i2c_gpio.h>
48 #include "libdevice.h"
49 #include "picldefs.h"
50 #include <sys/raidioctl.h>
51 #include <sys/param.h>
52 #include <sys/epic.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,
70 "SUNW_MPXU_frudr",
71 piclfrudr_init,
72 piclfrudr_fini,
76 * Log message texts
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"
99 * Local defines
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"
116 #define PS_NAME "PS"
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"
129 #define FT_NAME "FT"
130 #define FT_NAME_LEN 2
131 #define F0_NAME "F0"
132 #define F0_NAME_LEN 2
133 #define F1_NAME "F1"
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
158 * PSU defines
160 #define PSU_I2C_BUS_DEV "/devices/pci@1e,600000/isa@7/i2c@0,320:devctl"
161 #define PSU_DEV \
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"
231 * disk defines
233 #define REMOK_LED "OK2RM"
234 #define FAULT_LED "SERVICE"
235 #define PLATFORMLEN 9
236 #define N_DISKS 8
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"
259 * led defines
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;
288 } id_props_t;
290 typedef struct idp_lkup {
291 int maxnum; /* entries in array */
292 int num; /* entries in use */
293 id_props_t idp[1];
294 } idp_lkup_t;
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;
308 * disk data
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;
331 * static strings
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);
346 * forward reference
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,
376 char *tbl_name);
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)
395 #define PLAT_ENXS 0
396 #define PLAT_ENTS 1
397 #define PLAT_CHALUPA 2
398 #define PLAT_EN19 3
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;
407 static void
408 get_platform()
410 char platform[64];
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;
432 else
433 sys_platform = PLAT_UNKNOWN;
437 * This function is executed as part of .init when the plugin is
438 * dlopen()ed
440 static void
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
450 static void
451 piclfrudr_init(void)
453 picl_nodehdl_t sc_nodeh;
454 picl_nodehdl_t locationh;
455 picl_nodehdl_t childh;
456 char namebuf[PATH_MAX];
458 get_platform();
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)) ==
467 NULL))
468 syslog(LOG_ERR, EM_NO_SC_DEV);
470 opst_init();
471 disk_leds_init();
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
484 * in case.
487 if ((sys_platform == PLAT_CHALUPA) ||
488 (sys_platform == PLAT_CHALUPA19)) {
489 sprintf_buf2(namebuf, CHASSIS_LOC_PATH, RMC_NAME);
490 } else {
491 sprintf_buf2(namebuf, SYS_BOARD_PATH, RMC_NAME);
494 if (ptree_get_node_by_path(namebuf, &locationh) != PICL_SUCCESS)
495 return;
496 if (ptree_get_propval_by_name(locationh, PICL_PROP_CHILD,
497 &childh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
498 return;
499 post_frudr_event(PICL_FRU_ADDED, locationh, childh);
502 static void
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) {
509 return;
512 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
513 &nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
515 if (child_name == NULL)
516 return;
518 * create fru node of supplied name
520 if (ptree_create_and_add_node(nodeh, child_name,
521 PICL_CLASS_FRU, &nodeh) != PICL_SUCCESS)
522 return;
525 add_op_status_to_node(nodeh, prophdl_p);
529 * function to add a volatile property to a specified node
531 static void
532 add_op_status_to_node(picl_nodehdl_t nodeh, picl_prophdl_t *prophdl_p)
534 int err;
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,
553 err);
554 return;
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.
563 static int
564 read_vol_data(ptree_rarg_t *r_arg, void *buf)
566 picl_prophdl_t proph;
567 int index;
568 int envmon_fd;
569 int err;
570 envmon_hpu_t data;
572 proph = r_arg->proph;
573 index = find_picl_handle(proph);
575 if (index < 0) {
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"
580 * is appropriate.
582 (void) strlcpy(buf, str_opst_unknown, max_opst_len);
583 return (PICL_SUCCESS);
586 envmon_fd = open(sc_device_name, O_RDONLY);
588 if (envmon_fd < 0) {
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);
602 if (err < 0) {
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);
625 (void) strlcpy(buf,
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).
638 static void
639 solaris_setleds(const char *led_path, int leds)
641 i2c_gpio_t gpio;
642 int fd = open(led_path, O_RDWR);
644 if (fd < 0)
645 return;
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);
654 (void) close(fd);
658 * Function for explicitly turning on system leds
659 * for a failed/degraded RMC (SC) on Seattle
661 static void
662 seattle_setleds(void)
664 int fd;
666 fd = open(SEATTLE_LED_DEV, O_RDWR);
668 if (fd < 0)
669 return;
671 ioctl(fd, EPIC_SET_POWER_LED, (char *)0);
672 ioctl(fd, EPIC_SET_ALERT_LED, (char *)0);
673 (void) close(fd);
677 * Function for explicitly turning on the front system leds
678 * for a failed/degraded RMC (SC) on Boston
680 static void
681 boston_set_frontleds(const char *led_path, int leds)
683 i2c_gpio_t gpio;
684 int fd = open(led_path, O_RDWR);
686 if (fd < 0) {
687 return;
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) {
694 (void) close(fd);
695 return;
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) {
702 (void) close(fd);
703 return;
706 /* and light the leds */
707 gpio.reg_val = leds;
708 gpio.reg_mask = BOSTON_FRONT_LED_MASK;
709 ioctl(fd, GPIO_SET_OUTPUT, &gpio);
710 (void) close(fd);
714 * Function for explicitly turning on the rear system leds
715 * for a failed/degraded RMC (SC) on Boston
717 static void
718 boston_set_rearleds(const char *led_path, int leds)
720 i2c_gpio_t gpio;
721 int fd = open(led_path, O_RDWR);
723 if (fd < 0) {
724 return;
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) {
731 (void) close(fd);
732 return;
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) {
739 (void) close(fd);
740 return;
743 /* and light the leds */
744 gpio.reg_val = leds;
745 gpio.reg_mask = BOSTON_REAR_LED_MASK;
746 ioctl(fd, GPIO_SET_OUTPUT, &gpio);
747 (void) close(fd);
750 static void
751 rmc_state_event(void)
753 envmon_hpu_t hpu;
754 int res;
755 int fd = open(sc_device_name, O_RDONLY);
757 if (fd < 0)
758 return;
760 (void) strlcpy(hpu.id.name, RMC_NAME, sizeof (hpu.id.name));
761 res = ioctl(fd, ENVMONIOCHPU, &hpu);
762 (void) close(fd);
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) {
772 case PLAT_ENXS:
773 case PLAT_SALSA19:
774 case PLAT_EN19:
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) {
782 bezel_leds =
783 create_bezel_leds_pathname(ENXS_LED_DIR,
784 ENXS_FRONT_LEDS);
786 if (bezel_leds == NULL)
787 return;
788 solaris_setleds(bezel_leds,
789 ENXS_FRONT_SRVC_LED | ENXS_FRONT_ACT_LED);
790 break;
791 case PLAT_ENTS:
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) {
798 bezel_leds =
799 create_bezel_leds_pathname(ENTS_LED_DIR,
800 ENTS_LEDS);
802 if (bezel_leds == NULL)
803 return;
804 solaris_setleds(bezel_leds,
805 ENTS_SRVC_LED | ENTS_ACT_LED);
806 break;
807 case PLAT_CHALUPA:
808 case PLAT_CHALUPA19:
809 solaris_setleds(V440_LED_PATH,
810 V440_SRVC_LED | V440_ACT_LED);
811 break;
812 case PLAT_BOSTON:
813 /* set front leds */
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);
819 break;
820 case PLAT_SEATTLE1U:
821 case PLAT_SEATTLE2U:
822 seattle_setleds();
823 break;
824 default:
825 break;
830 static int
831 find_picl_handle(picl_prophdl_t proph)
833 int index;
835 if (idprop == NULL)
836 return (-1);
838 for (index = 0; index < idprop->num; index++) {
839 if (idprop->idp[index].volprop == proph)
840 return (index);
843 return (-1);
846 static int
847 find_vol_prop_by_name(const char *name)
849 int index;
851 if (idprop == NULL)
852 return (-1);
854 for (index = 0; index < idprop->num; index++) {
855 if (strcmp(idprop->idp[index].envhandle.name, name) == 0)
856 return (index);
859 return (-1);
863 * This function is the fini entry point of the plugin.
865 static void
866 piclfrudr_fini(void)
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,
871 NULL);
872 disk_leds_fini();
873 if (idprop != NULL) {
874 free(idprop);
875 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;
891 int err;
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)
897 return (NULL);
898 for (;;) {
899 err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename,
900 sizeof (nodename));
901 if (err != PICL_SUCCESS)
902 return (NULL);
903 if (strcmp(name, nodename) == 0) {
904 return (nodeh);
906 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
907 &nodeh, sizeof (picl_nodehdl_t));
908 if (err != PICL_SUCCESS)
909 return (NULL);
913 /* Creates a reference property for a given PICL node */
914 static int
915 add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name)
917 picl_prophdl_t proph;
918 ptree_propinfo_t propinfo;
919 int err;
921 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
922 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name,
923 NULL, NULL);
924 if (err != PICL_SUCCESS) {
925 syslog(LOG_ERR, PROPINFO_FAIL, name, err);
926 return (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);
931 return (err);
933 return (PICL_SUCCESS);
936 /* create an entry in the specified table */
937 static int
938 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
940 int err;
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;
949 prop.read = NULL;
950 prop.write = NULL;
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);
956 return (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);
964 prop.read = NULL;
965 prop.write = NULL;
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);
970 return (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);
977 return (err);
980 /* create an empty table property */
981 static int
982 create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
984 int err;
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);
991 return (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);
997 prop.read = NULL;
998 prop.write = NULL;
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);
1004 return (err);
1008 * The size of outfilename must be PATH_MAX
1010 static int
1011 get_config_file(char *outfilename, char *fru)
1013 char nmbuf[SYS_NMLN];
1014 char pname[PATH_MAX];
1015 int dir;
1017 for (dir = 0; dir < 2; dir++) {
1018 if (sysinfo(dir == 0 ? SI_PLATFORM : SI_MACHINE,
1019 nmbuf, sizeof (nmbuf)) == -1) {
1020 continue;
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);
1030 return (0);
1034 (void) snprintf(pname, PATH_MAX, "%s/%s%s%s",
1035 PICLD_COMMON_PLUGIN_DIR, CONFFILE_PREFIX, fru,
1036 CONFFILE_SUFFIX);
1038 if (access(pname, R_OK) == 0) {
1039 (void) strlcpy(outfilename, pname, PATH_MAX);
1040 return (0);
1043 return (-1);
1047 * This helper function for Netra-440 fan tray removal removes
1048 * the rmclomv-rooted nodes and their properties.
1050 static void
1051 delete_node_and_props(picl_nodehdl_t hdl)
1053 picl_prophdl_t prop;
1054 int err;
1056 do {
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);
1067 static void
1068 remove_fru_parents(picl_nodehdl_t fruh)
1070 char name[MAXPATHLEN];
1071 int retval;
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;
1077 int fanfru = 0;
1079 retval = ptree_get_propval_by_name(fruh, PICL_PROP_NAME, name,
1080 sizeof (name));
1081 if (retval != PICL_SUCCESS) {
1082 syslog(LOG_ERR, EM_UNK_FRU);
1083 return;
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:
1099 case PLAT_BOSTON:
1100 if (strcmp(name, FT_FRU_NAME) != 0)
1101 return;
1102 fanfru = 1;
1103 break;
1104 case PLAT_CHALUPA19:
1105 if (strncmp(name, F0_NAME, F0_NAME_LEN) &&
1106 strncmp(name, F1_NAME, F1_NAME_LEN))
1107 return;
1108 fanfru = 1;
1109 break;
1110 default:
1111 /* nothing to do */
1112 return;
1114 retval = ptree_get_propval_by_name(fruh,
1115 PICL_PROP_CHILD, &childh, sizeof (picl_nodehdl_t));
1116 if (retval != PICL_SUCCESS)
1117 return;
1118 retval = ptree_get_prop_by_name(childh,
1119 PICL_PROP_DEVICES, &tableh);
1120 if (retval != PICL_SUCCESS)
1121 return;
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 */
1132 goto afterloop;
1135 /* get first col, first row */
1136 retval = ptree_get_next_by_col(tblh, &tblh);
1137 if (retval != PICL_SUCCESS) {
1138 /* no rows? */
1139 goto afterloop;
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,
1153 sizeof (nodeh));
1154 if (retval != PICL_SUCCESS) {
1155 continue;
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
1169 if (fanfru) {
1170 retval = ptree_get_prop_by_name(nodeh,
1171 PICL_REFPROP_LOC_PARENT, &fruph);
1173 if (retval != PICL_SUCCESS)
1174 continue;
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);
1188 afterloop:
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);
1200 static void
1201 remove_tables(picl_nodehdl_t rootnd)
1203 picl_nodehdl_t tableh;
1204 int retval;
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,
1221 sizeof (rootnd));
1223 while (retval == PICL_SUCCESS) {
1225 remove_tables(rootnd);
1228 * any siblings?
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
1238 /* ARGSUSED */
1239 static void
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' };
1246 int err;
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
1253 fruh = NULL;
1254 (void) nvlist_lookup_uint64(earg,
1255 PICLEVENTARG_FRUHANDLE, &fruh);
1256 if (fruh != NULL) {
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,
1268 sizeof (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
1281 * state
1283 if (strncmp(nodename, DISK_NAME,
1284 DISK_NAME_LEN) == 0) {
1285 disk_ready[nodename[DISK_NAME_LEN] -
1286 '0'] = -1;
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);
1298 } else {
1299 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1302 if ((sys_platform == PLAT_CHALUPA19) &&
1303 (strncmp(nodename, FT_NAME, FT_NAME_LEN) == 0) &&
1304 (peerh != NULL)) {
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);
1317 } else {
1318 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1324 free(ename);
1325 nvlist_free(earg);
1329 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
1331 static void
1332 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
1334 nvlist_t *nvl;
1335 char *ev_name;
1337 ev_name = strdup(ename);
1338 if (ev_name == NULL)
1339 return;
1340 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) {
1341 free(ev_name);
1342 return;
1344 if (parenth != 0L &&
1345 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
1346 free(ev_name);
1347 nvlist_free(nvl);
1348 return;
1350 if (fruh != 0L &&
1351 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
1352 free(ev_name);
1353 nvlist_free(nvl);
1354 return;
1356 if (ptree_post_event(ev_name, nvl, sizeof (nvl),
1357 frudr_completion_handler) != 0) {
1358 free(ev_name);
1359 nvlist_free(nvl);
1363 static void
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);
1370 int res;
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);
1377 break;
1378 case PLAT_BOSTON:
1379 res = ptree_get_node_by_path(BOSTON_PSU_PLATFORM, &parent_hdl);
1380 break;
1381 default:
1382 res = ptree_get_node_by_path(PSU_PLATFORM, &parent_hdl);
1383 break;
1386 if (res != PICL_SUCCESS)
1387 return;
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)
1413 return;
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)
1417 return;
1418 (void) ptree_create_and_add_prop(child_hdl, &info, unit, NULL);
1421 static void
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);
1438 } else {
1439 (void) snprintf(path, bufsz, SEATTLE_PDB_1U, ft_id);
1441 break;
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);
1452 } else {
1453 (void) snprintf(path, bufsz, SEATTLE_PDB_2U, ft_id);
1455 break;
1457 case PLAT_BOSTON:
1458 (void) snprintf(path, bufsz, SYS_BOARD_PATH, ft_id);
1459 break;
1461 default:
1462 (void) snprintf(path, bufsz, CHASSIS_LOC_PATH, ft_id);
1463 break;
1468 * handle EC_DR picl events
1470 /*ARGSUSED*/
1471 static void
1472 frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
1474 nvlist_t *nvlp;
1475 char *dtype;
1476 char *ap_id;
1477 char *hint;
1478 char path[MAXPATHLEN];
1479 picl_nodehdl_t fruh;
1480 picl_nodehdl_t locnodeh;
1481 int err;
1482 int index;
1483 picl_nodehdl_t childh;
1484 char *fru_name;
1485 boolean_t rmc_flag = B_FALSE;
1487 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0) {
1488 return;
1491 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
1492 return;
1495 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
1496 nvlist_free(nvlp);
1497 return;
1500 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
1501 nvlist_free(nvlp);
1502 return;
1505 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
1506 nvlist_free(nvlp);
1507 return;
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;
1521 rmc_flag = B_TRUE;
1522 } else if (strncmp(ap_id, FT_NAME, FT_NAME_LEN) == 0) {
1523 fru_name = FT_FRU_NAME;
1524 } else {
1525 nvlist_free(nvlp);
1526 return;
1529 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
1530 nvlist_free(nvlp);
1531 return;
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);
1540 else {
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);
1549 break;
1550 case PLAT_SEATTLE2U:
1551 sprintf_buf2(path, SEATTLE2U_HDDBP_PATH, ap_id);
1552 break;
1553 case PLAT_BOSTON:
1554 sprintf_buf2(path, BOSTON_HDDBP_PATH, ap_id);
1555 break;
1556 default:
1557 sprintf_buf2(path, CHASSIS_LOC_PATH, ap_id);
1558 break;
1560 } else if (strncmp(ap_id, FT_NAME, FT_NAME_LEN) == 0) {
1561 get_fantray_path(ap_id, path, MAXPATHLEN);
1562 } else {
1563 sprintf_buf2(path, CHASSIS_LOC_PATH, ap_id);
1567 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
1568 nvlist_free(nvlp);
1569 return;
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) {
1592 fruh = NULL;
1594 post_frudr_event(PICL_FRU_ADDED, locnodeh, fruh);
1595 } else {
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) {
1602 nvlist_free(nvlp);
1603 return;
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
1610 * fru node.
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);
1621 nvlist_free(nvlp);
1622 return;
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));
1634 if (index >= 0)
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));
1642 * now post event
1644 post_frudr_event(PICL_FRU_ADDED, locnodeh, NULL);
1646 nvlist_free(nvlp);
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.
1664 /*ARGSUSED*/
1665 static void
1666 fru_add_handler(const char *ename, const void *earg, size_t size, void *cookie)
1668 int retval;
1669 picl_nodehdl_t locnodeh;
1670 picl_nodehdl_t rooth;
1671 char path[MAXPATHLEN];
1672 char *fru_name;
1674 if (strcmp(ename, PICL_FRU_ADDED) != 0)
1675 return;
1677 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1678 PICLEVENTARG_PARENTHANDLE, &locnodeh);
1679 if (retval != PICL_SUCCESS)
1680 return;
1682 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME,
1683 path, sizeof (path));
1684 if (retval != PICL_SUCCESS)
1685 return;
1687 fru_name = strdup(path);
1688 if (fru_name == NULL)
1689 return;
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
1701 * redo that action.
1703 if (strcmp(fru_name, RMC_NAME) == 0) {
1704 rmc_state_event();
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.
1717 opst_init();
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) !=
1725 PICL_SUCCESS)) {
1726 syslog(LOG_ERR, PARSE_CONF_FAIL, path);
1730 free(fru_name);
1734 * Handle PICLEVENT_SYSEVENT_DEVICE_ADDED events.
1736 /*ARGSUSED*/
1737 static void
1738 frutree_evhandler(const char *ename, const void *earg, size_t size,
1739 void *cookie)
1741 nvlist_t *nvlp;
1742 picl_nodehdl_t rooth;
1743 char path[MAXPATHLEN];
1744 char *fru_name;
1745 char *dtype;
1746 char *dpath;
1747 char *ptr;
1748 char *ptr2;
1749 int done = B_FALSE;
1750 int i;
1752 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) != 0)
1753 return;
1755 if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
1756 return;
1758 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
1759 nvlist_free(nvlp);
1760 return;
1763 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
1764 nvlist_free(nvlp);
1765 return;
1768 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &dpath)) {
1769 nvlist_free(nvlp);
1770 return;
1773 fru_name = strdup(dpath);
1774 if (fru_name == NULL) {
1775 nvlist_free(nvlp);
1776 return;
1779 nvlist_free(nvlp);
1782 * fru_name is of the form
1783 * "/pci@1e,600000/usb@a/mouse@2"
1784 * or
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);
1801 } else {
1802 ptr = fru_name;
1803 if (*ptr == '/') {
1804 ptr++;
1805 ptr = strchr(ptr, '/');
1806 if (ptr != NULL) {
1807 ptr++;
1808 (void) memmove(fru_name, ptr, strlen(ptr) + 1);
1809 ptr = strchr(fru_name, '@');
1810 if (ptr != NULL) {
1811 *ptr = '-';
1812 ptr++;
1813 ptr = strchr(ptr, '/');
1814 if (ptr != NULL) {
1815 *ptr = '-';
1816 ptr++;
1817 ptr2 = ptr;
1818 ptr = strchr(ptr, '@');
1819 if (ptr != NULL) {
1820 ptr++;
1821 (void) memmove(ptr2,
1822 ptr, strlen(ptr)+1);
1823 ptr2 = strchr(ptr2,
1824 '/');
1825 if (ptr2 != NULL) {
1826 *ptr2 = '\0';
1828 done = B_TRUE;
1834 if (done == B_FALSE) {
1835 free(fru_name);
1836 return;
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) !=
1846 PICL_SUCCESS)) {
1847 syslog(LOG_ERR, PARSE_CONF_FAIL, path);
1852 free(fru_name);
1855 static int
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;
1865 int retval;
1866 char *value_ptr;
1867 char label[PICL_PROPNAMELEN_MAX];
1868 char class[PICL_PROPNAMELEN_MAX];
1870 /* find the location node */
1871 switch (sys_platform) {
1872 case PLAT_CHALUPA:
1873 case PLAT_CHALUPA19:
1874 sprintf_buf2(path, CHASSIS_LOC_PATH, name);
1875 break;
1876 case PLAT_SEATTLE1U:
1877 sprintf_buf2(path, SEATTLE1U_HDDBP_PATH, name);
1878 break;
1879 case PLAT_SEATTLE2U:
1880 sprintf_buf2(path, SEATTLE2U_HDDBP_PATH, name);
1881 break;
1882 case PLAT_BOSTON:
1883 sprintf_buf2(path, BOSTON_HDDBP_PATH, name);
1884 break;
1885 default:
1886 sprintf_buf2(path, CHASSIS_LOC_PATH, name);
1887 break;
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)
1898 value_ptr = value;
1899 else
1900 value_ptr = PICL_PROPVAL_OFF;
1902 /* get its Devices table */
1903 if (ptree_get_prop_by_name(locnodeh, PICL_PROP_DEVICES, &tableh) !=
1904 PICL_SUCCESS)
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))
1923 != PICL_SUCCESS)
1924 continue;
1927 * check it's a led
1929 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
1930 class, sizeof (class)) != PICL_SUCCESS)
1931 continue;
1932 if (strcmp(class, "led") != 0)
1933 continue;
1936 * check its the right led
1938 if (ptree_get_propval_by_name(nodeh, PICL_PROP_LABEL,
1939 label, sizeof (label)) != PICL_SUCCESS)
1940 continue;
1941 if (strcmp(label, ptr) == 0) {
1943 * set it
1945 if (ptree_get_prop_by_name(nodeh, PICL_PROP_STATE,
1946 &proph) != PICL_SUCCESS)
1947 continue;
1948 if (ptree_get_propinfo(proph, &propinfo) !=
1949 PICL_SUCCESS)
1950 continue;
1951 retval = ptree_update_propval_by_name(nodeh,
1952 PICL_PROP_STATE, value_ptr, propinfo.piclinfo.size);
1953 return (retval);
1956 return (PICL_FAILURE);
1960 * function to find first node of specified class beneath supplied node
1962 static int
1963 get_node_by_class(picl_nodehdl_t nodeh, const char *classname,
1964 picl_nodehdl_t *foundnodeh)
1966 int err;
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
1999 static int
2000 get_sys_controller_node(picl_nodehdl_t *nodeh)
2002 int err;
2004 /* get platform node */
2005 err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, nodeh);
2006 if (err != PICL_SUCCESS)
2007 return (err);
2008 err = get_node_by_class(*nodeh, PICL_CLASS_SERVICE_PROCESSOR, nodeh);
2009 return (err);
2013 * create pathname string for system-controller device
2015 static char *
2016 create_sys_controller_pathname(picl_nodehdl_t sysconh)
2018 char *ptr;
2019 char namebuf[PATH_MAX];
2020 size_t len;
2021 DIR *dirp;
2022 struct dirent *dp;
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) {
2036 return (NULL);
2040 * locate final component of name
2042 ptr = strrchr(namebuf, '/');
2043 if (ptr == NULL)
2044 return (NULL);
2045 *ptr = '\0'; /* terminate at end of directory path */
2046 len = strlen(ptr + 1); /* length of terminal name */
2047 dirp = opendir(namebuf);
2048 if (dirp == NULL) {
2049 return (NULL);
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);
2078 return (NULL);
2082 * create pathname string for bezel leds device
2084 static char *
2085 create_bezel_leds_pathname(const char *dirpath, const char *devname)
2087 char namebuf[PATH_MAX];
2088 size_t lendirpath;
2089 size_t len;
2090 DIR *dirp;
2091 struct dirent *dp;
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);
2104 if (dirp == NULL) {
2105 return (NULL);
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);
2135 return (NULL);
2139 * initialise structure associated with nodes requiring OperationalStatus
2141 static void
2142 opst_init(void)
2144 int res;
2145 int index = 0;
2146 int fd;
2147 int entries = 0;
2148 int err = 0;
2149 boolean_t rmc_flag;
2150 boolean_t ps_flag;
2151 boolean_t disk_flag;
2152 size_t len;
2153 envmon_sysinfo_t sysinfo;
2154 envmon_hpu_t hpu;
2156 if (idprop != NULL) {
2158 * This must be a restart, clean up earlier allocation
2160 free(idprop);
2161 idprop = NULL;
2164 if (sc_device_name == NULL)
2165 err = 1;
2166 else {
2167 fd = open(sc_device_name, O_RDONLY);
2169 if (fd < 0) {
2170 syslog(LOG_ERR, EM_NO_SC_DEV);
2171 err = 1;
2175 if (err == 0) {
2176 res = ioctl(fd, ENVMONIOCSYSINFO, &sysinfo);
2178 if (res < 0) {
2179 syslog(LOG_ERR, EM_NO_SYSINFO, strerror(errno));
2180 (void) close(fd);
2181 err = 1;
2185 if (err == 0) {
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) {
2190 (void) close(fd);
2191 err = 1;
2195 if (err == 0) {
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);
2210 if ((res == 0) &&
2211 ((hpu.sensor_status & ENVMON_NOT_PRESENT) == 0)) {
2212 add_op_status(&hpu, &index);
2216 idprop->num = index;
2217 (void) close(fd);
2221 static void
2222 disk_leds_init(void)
2224 int err = 0, i;
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;
2231 } else {
2232 return;
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++)
2242 disk_ready[i] = -1;
2244 if (ledsthr_created) {
2246 * this is a restart, wake up sleeping threads
2248 err = pthread_mutex_lock(&g_mutex);
2249 if (err != 0) {
2250 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno));
2251 return;
2253 g_finish_now = B_FALSE;
2254 (void) pthread_cond_broadcast(&g_cv);
2255 (void) pthread_mutex_unlock(&g_mutex);
2256 } else {
2257 if ((pthread_attr_init(&ledsthr_attr) != 0) ||
2258 (pthread_attr_setscope(&ledsthr_attr,
2259 PTHREAD_SCOPE_SYSTEM) != 0))
2260 return;
2261 if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr,
2262 disk_leds_thread, NULL)) != 0) {
2263 syslog(LOG_ERR, EM_THREAD_CREATE_FAILED,
2264 strerror(errno));
2265 return;
2267 ledsthr_created = B_TRUE;
2271 static void
2272 disk_leds_fini(void)
2274 int err, i;
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)
2287 return;
2290 * tell led thread to pause
2292 if (!ledsthr_created)
2293 return;
2294 err = pthread_mutex_lock(&g_mutex);
2295 if (err != 0) {
2296 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno));
2297 return;
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);
2312 static void
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;
2321 int err;
2322 char path[MAXPATHLEN];
2324 switch (sys_platform) {
2325 case PLAT_CHALUPA:
2326 case PLAT_CHALUPA19:
2327 sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
2328 break;
2329 case PLAT_SEATTLE1U:
2330 sprintf_buf2(path, SEATTLE1U_HDDBP_PATH, fruname);
2331 break;
2332 case PLAT_SEATTLE2U:
2333 sprintf_buf2(path, SEATTLE2U_HDDBP_PATH, fruname);
2334 break;
2335 case PLAT_BOSTON:
2336 sprintf_buf2(path, BOSTON_HDDBP_PATH, fruname);
2337 break;
2338 default:
2339 sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
2340 break;
2343 if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
2344 return;
2346 diskndh = find_child_by_name(slotndh, DISK_FRU_NAME);
2347 if (diskndh == NULL) {
2348 return;
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)
2355 return;
2356 err = ptree_get_next_by_col(tblhdl, &tblhdl2);
2357 if (err != PICL_SUCCESS) {
2358 err = create_table_entry(tblhdl, devhdl,
2359 PICL_CLASS_BLOCK);
2360 if (err != PICL_SUCCESS)
2361 return;
2362 err = add_prop_ref(devhdl, diskndh,
2363 PICL_REFPROP_FRU_PARENT);
2364 if (err != PICL_SUCCESS)
2365 return;
2367 } else {
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,
2373 &tblproph);
2374 if (err != PICL_SUCCESS)
2375 return;
2376 err = ptree_delete_prop(tblproph);
2377 if (err != PICL_SUCCESS)
2378 return;
2379 (void) ptree_destroy_prop(tblproph);
2380 err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES);
2381 if (err != PICL_SUCCESS)
2382 return;
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.
2391 static int
2392 raid_ok2rem_policy(raid_config_t config, int target)
2394 int i;
2396 for (i = 0; i < config.ndisks; i++) {
2397 int d = config.disk[i];
2398 int dstatus = config.diskstatus[i];
2400 if (d == target) {
2401 switch (dstatus) {
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;
2410 break;
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;
2418 break;
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;
2426 break;
2427 default:
2428 break;
2430 return (1);
2433 return (0);
2436 static int
2437 check_raid(int target)
2439 raid_config_t config;
2440 int fd;
2441 int numvols;
2442 int i, j;
2444 switch (sys_platform) {
2445 case PLAT_CHALUPA:
2446 case PLAT_CHALUPA19:
2447 fd = open(V440_DISK_DEVCTL, O_RDONLY);
2448 break;
2449 case PLAT_SEATTLE1U:
2450 case PLAT_SEATTLE2U:
2451 fd = open(SEATTLE_DISK_DEVCTL, O_RDONLY);
2452 break;
2453 case PLAT_BOSTON:
2454 if (boston_1068e_flag) {
2455 fd = open(BOSTON_DISK_DEVCTL_1068E, O_RDONLY);
2456 } else {
2457 fd = open(BOSTON_DISK_DEVCTL_1068X, O_RDONLY);
2459 break;
2460 default:
2461 fd = -1;
2462 break;
2465 if (fd == -1) {
2466 return (0);
2469 if (ioctl(fd, RAID_NUMVOLUMES, &numvols)) {
2470 (void) close(fd);
2471 return (0);
2474 for (i = 0; i < numvols; i++) {
2475 config.unitid = i;
2476 if (ioctl(fd, RAID_GETCONFIG, &config)) {
2477 (void) close(fd);
2478 return (0);
2480 if (raid_ok2rem_policy(config, target)) {
2481 (void) close(fd);
2482 return (1);
2486 (void) close(fd);
2487 return (0);
2490 /*ARGSUSED*/
2491 static void *
2492 disk_leds_thread(void *args)
2494 int c;
2495 int i;
2496 char **disk_dev;
2497 int fd;
2499 devctl_hdl_t dhdl;
2501 int n_disks = 0,
2502 do_raid = 0,
2503 err = 0;
2504 uint_t statep = 0;
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) {
2569 case PLAT_ENTS:
2570 disk_dev = ents_devs;
2571 n_disks = N_ENTS_DISKS;
2572 break;
2574 case PLAT_CHALUPA:
2575 case PLAT_CHALUPA19:
2576 do_raid = 1;
2577 disk_dev = v440_devs;
2578 n_disks = N_CHALUPA_DISKS;
2579 break;
2581 case PLAT_SALSA19:
2582 disk_dev = n210_devs;
2583 n_disks = N_EN19_DISKS;
2584 break;
2586 case PLAT_SEATTLE1U:
2587 case PLAT_SEATTLE2U:
2588 do_raid = 1;
2589 disk_dev = seattle_devs;
2590 n_disks = (sys_platform == PLAT_SEATTLE1U) ?
2591 N_SEATTLE1U_DISKS : N_SEATTLE2U_DISKS;
2592 break;
2594 case PLAT_BOSTON:
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;
2608 } else {
2609 boston_1068e_flag = 0;
2610 disk_dev = boston_devs_1068x;
2612 (void) close(fd);
2613 do_raid = 1;
2614 n_disks = N_BOSTON_DISKS;
2615 break;
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;
2637 for (;;) {
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)) {
2644 continue;
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);
2675 * are we to stop?
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
2701 static int
2702 ps_name_to_addr(char *name)
2704 int ps_addr = 0;
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;
2711 break;
2712 case PLAT_BOSTON:
2713 ps_addr = BOSTON_PS0_ADDR;
2714 break;
2715 default:
2716 ps_addr = PS0_ADDR;
2717 break;
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;
2725 break;
2726 case PLAT_BOSTON:
2727 ps_addr = BOSTON_PS1_ADDR;
2728 break;
2729 default:
2730 ps_addr = PS1_ADDR;
2731 break;
2733 } else if ((strcmp(name, PS2_NAME) == 0) ||
2734 (strcmp(name, PSU2_NAME) == 0)) {
2735 switch (sys_platform) {
2736 case PLAT_BOSTON:
2737 ps_addr = BOSTON_PS2_ADDR;
2738 break;
2739 default:
2740 ps_addr = PS2_ADDR;
2741 break;
2743 } else if ((strcmp(name, PS3_NAME) == 0) ||
2744 (strcmp(name, PSU3_NAME) == 0)) {
2745 switch (sys_platform) {
2746 case PLAT_BOSTON:
2747 ps_addr = BOSTON_PS3_ADDR;
2748 break;
2749 default:
2750 ps_addr = PS3_ADDR;
2751 break;
2755 return (ps_addr);
2759 * Given powersupply name, convert to unit addr
2761 static char *
2762 ps_name_to_unitaddr(char *name)
2764 char *unitaddr;
2766 if (strcmp(name, PS0_NAME) == 0) {
2767 switch (sys_platform) {
2768 case PLAT_SEATTLE1U:
2769 case PLAT_SEATTLE2U:
2770 unitaddr = SEATTLE_PS0_UNITADDR;
2771 break;
2772 case PLAT_BOSTON:
2773 unitaddr = BOSTON_PS0_UNITADDR;
2774 break;
2775 default:
2776 unitaddr = PS0_UNITADDR;
2777 break;
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;
2784 break;
2785 case PLAT_BOSTON:
2786 unitaddr = BOSTON_PS1_UNITADDR;
2787 break;
2788 default:
2789 unitaddr = PS1_UNITADDR;
2790 break;
2792 } else if (strcmp(name, PS2_NAME) == 0) {
2793 switch (sys_platform) {
2794 case PLAT_BOSTON:
2795 unitaddr = BOSTON_PS2_UNITADDR;
2796 break;
2797 default:
2798 unitaddr = PS2_UNITADDR;
2799 break;
2801 } else if (strcmp(name, PS3_NAME) == 0) {
2802 switch (sys_platform) {
2803 case PLAT_BOSTON:
2804 unitaddr = BOSTON_PS3_UNITADDR;
2805 break;
2806 default:
2807 unitaddr = PS3_UNITADDR;
2808 break;
2811 else
2812 unitaddr = NULL;
2814 return (unitaddr);
2818 * converts apid to real FRU name in PICL tree. The
2819 * name of powersupply devices on chalupa19 are
2820 * PSU instead of PS
2822 static char *
2823 ps_apid_to_nodename(char *apid)
2825 char *nodename;
2827 if (sys_platform != PLAT_CHALUPA19)
2828 return (apid);
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;
2838 else
2839 nodename = apid;
2841 return (nodename);
2845 * Create SEEPROM node at insertion time.
2847 static int
2848 create_i2c_node(char *ap_id)
2850 int nd_reg[2];
2851 devctl_ddef_t ddef_hdl;
2852 devctl_hdl_t bus_hdl;
2853 devctl_hdl_t dev_hdl;
2854 char dev_path[MAXPATHLEN];
2855 char *compatible;
2857 /* create seeprom node */
2858 nd_reg[0] = 0;
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;
2866 break;
2867 case PLAT_BOSTON:
2868 bus_hdl = devctl_bus_acquire(BOSTON_PSU_I2C_BUS_DEV, 0);
2869 compatible = BOSTON_PSU_COMPATIBLE;
2870 break;
2871 default:
2872 bus_hdl = devctl_bus_acquire(PSU_I2C_BUS_DEV, 0);
2873 compatible = PSU_COMPATIBLE;
2874 break;
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.
2902 static void
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));
2912 break;
2913 case PLAT_BOSTON:
2914 sprintf_buf2(buf, BOSTON_PSU_DEV, ps_name_to_addr(ap_id));
2915 break;
2916 default:
2917 sprintf_buf2(buf, PSU_DEV, ps_name_to_addr(ap_id));
2918 break;
2921 dev_hdl = devctl_device_acquire(buf, 0);
2922 if (dev_hdl == NULL) {
2923 return;
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);
2937 static void
2938 add_op_status(envmon_hpu_t *hpu, int *index)
2940 boolean_t rmc_flag;
2941 boolean_t ps_flag;
2942 boolean_t disk_flag;
2943 char node_name[MAXPATHLEN];
2944 boolean_t flag;
2946 rmc_flag = (strcmp(hpu->id.name, RMC_NAME) == 0);
2947 ps_flag = (strncmp(hpu->id.name, PS_NAME,
2948 PS_NAME_LEN) == 0);
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) {
2964 case PLAT_CHALUPA:
2965 case PLAT_CHALUPA19:
2966 sprintf_buf2(node_name, CHASSIS_LOC_PATH, hpu->id.name);
2967 break;
2968 case PLAT_SEATTLE1U:
2969 sprintf_buf2(node_name, SEATTLE1U_HDDBP_PATH, \
2970 hpu->id.name);
2971 break;
2972 case PLAT_SEATTLE2U:
2973 sprintf_buf2(node_name, SEATTLE2U_HDDBP_PATH, \
2974 hpu->id.name);
2975 break;
2976 case PLAT_BOSTON:
2977 sprintf_buf2(node_name, BOSTON_HDDBP_PATH, \
2978 hpu->id.name);
2979 break;
2980 default:
2981 sprintf_buf2(node_name, SYS_BOARD_PATH, hpu->id.name);
2982 break;
2984 add_op_status_by_name(node_name, DISK_FRU_NAME,
2985 &idprop->idp[(*index)++].volprop);