1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
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>
53
54 /*
55 * Plugin registration entry points
56 */
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);
64
65 #pragma init(piclfrudr_register)
66
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,
73 };
74
75 /*
76 * Log message texts
77 */
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")
91
92 /*
93 * PICL property values
94 */
95 #define PICL_PROPVAL_ON "ON"
96 #define PICL_PROPVAL_OFF "OFF"
97
98 /*
99 * Local defines
100 */
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"
112
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
156
157 /*
158 * PSU defines
159 */
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"
182
183 /*
184 * Seattle/Boston PSU defines
185 */
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"
208
209 /*
210 * Seattle fan-tray paths
211 */
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"
229
230 /*
231 * disk defines
232 */
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"
244
245 /*
246 * Seattle/Boston disk defines
247 */
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"
257
258 /*
259 * led defines
260 */
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"
264
265 #define ENTS_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/"
266 #define ENTS_LEDS "gpio@0,70:"
267
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"
270
271 /*
272 * Seattle/Boston led defines
273 */
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"
278
279 /*
280 * Seattle/Boston USB defines
281 */
282 #define MAX_USB_PORTS 4
283 #define USB_CONF_FILE_NAME "usb-a-"
284
285 typedef struct id_props {
286 envmon_handle_t envhandle;
287 picl_prophdl_t volprop;
288 } id_props_t;
289
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;
295
296 /*
297 * table for mapping RMC handles to volatile property handles
298 */
299 static idp_lkup_t *idprop = NULL;
300
301 /*
302 * path names to system-controller device and fault led gpio
303 */
304 static char *sc_device_name = NULL;
305 static char *bezel_leds = NULL;
306
307 /*
308 * disk data
309 */
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;
323
324 /*
325 * Boston platform-specific flag which tells us if we are using
326 * a LSI 1068X disk controller (0) or a LSI 1068E (1).
327 */
328 static int boston_1068e_flag = 0;
329
330 /*
331 * static strings
332 */
333 static const char str_devfs_path[] = "devfs-path";
334
335 /*
336 * OperationalStatus property values
337 */
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);
344
345 /*
346 * forward reference
347 */
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);
387
388 #define sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2)
389
390 /*
391 * Because this plugin is shared across different platforms, we need to
392 * distinguish for certain functionality
393 */
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
404
405 static int sys_platform;
406
407 static void
get_platform()408 get_platform()
409 {
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;
434 }
435
436 /*
437 * This function is executed as part of .init when the plugin is
438 * dlopen()ed
439 */
440 static void
piclfrudr_register(void)441 piclfrudr_register(void)
442 {
443 (void) picld_plugin_register(&my_reg_info);
444 }
445
446 /*
447 * This function is the init entry point of the plugin.
448 * It initializes the /frutree tree
449 */
450 static void
piclfrudr_init(void)451 piclfrudr_init(void)
452 {
453 picl_nodehdl_t sc_nodeh;
454 picl_nodehdl_t locationh;
455 picl_nodehdl_t childh;
456 char namebuf[PATH_MAX];
457
458 get_platform();
459
460 if (sc_device_name != NULL) {
461 free(sc_device_name); /* must have reen restarted */
462 sc_device_name = NULL;
463 }
464
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);
469
470 opst_init();
471 disk_leds_init();
472
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);
478
479 /*
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.
485 */
486
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);
492 }
493
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);
500 }
501
502 static void
add_op_status_by_name(const char * name,const char * child_name,picl_prophdl_t * prophdl_p)503 add_op_status_by_name(const char *name, const char *child_name,
504 picl_prophdl_t *prophdl_p)
505 {
506 picl_nodehdl_t nodeh;
507
508 if (ptree_get_node_by_path(name, &nodeh) != PICL_SUCCESS) {
509 return;
510 }
511
512 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
513 &nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
514
515 if (child_name == NULL)
516 return;
517 /*
518 * create fru node of supplied name
519 */
520 if (ptree_create_and_add_node(nodeh, child_name,
521 PICL_CLASS_FRU, &nodeh) != PICL_SUCCESS)
522 return;
523 }
524
525 add_op_status_to_node(nodeh, prophdl_p);
526 }
527
528 /*
529 * function to add a volatile property to a specified node
530 */
531 static void
add_op_status_to_node(picl_nodehdl_t nodeh,picl_prophdl_t * prophdl_p)532 add_op_status_to_node(picl_nodehdl_t nodeh, picl_prophdl_t *prophdl_p)
533 {
534 int err;
535 ptree_propinfo_t info;
536 picl_prophdl_t proph;
537
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);
541
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);
547 }
548 }
549
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;
555 }
556 }
557
558 /*
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.
562 */
563 static int
read_vol_data(ptree_rarg_t * r_arg,void * buf)564 read_vol_data(ptree_rarg_t *r_arg, void *buf)
565 {
566 picl_prophdl_t proph;
567 int index;
568 int envmon_fd;
569 int err;
570 envmon_hpu_t data;
571
572 proph = r_arg->proph;
573 index = find_picl_handle(proph);
574
575 if (index < 0) {
576 /*
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.
581 */
582 (void) strlcpy(buf, str_opst_unknown, max_opst_len);
583 return (PICL_SUCCESS);
584 }
585
586 envmon_fd = open(sc_device_name, O_RDONLY);
587
588 if (envmon_fd < 0) {
589 /*
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".
594 */
595 (void) strlcpy(buf, str_opst_unknown, max_opst_len);
596 return (PICL_SUCCESS);
597 }
598
599 data.id = idprop->idp[index].envhandle;
600 err = ioctl(envmon_fd, ENVMONIOCHPU, &data);
601
602 if (err < 0) {
603 /*
604 * If we can't read the stats, "unknown" is a reasonable
605 * status to return. This one really shouldn't happen.
606 */
607 (void) strlcpy(buf, str_opst_unknown, max_opst_len);
608 (void) close(envmon_fd);
609 return (PICL_SUCCESS);
610 }
611
612 (void) close(envmon_fd);
613
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);
618 }
619
620 if (data.sensor_status != ENVMON_SENSOR_OK) {
621 (void) strlcpy(buf, str_opst_unknown, max_opst_len);
622 return (PICL_SUCCESS);
623 }
624
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);
630
631 return (PICL_SUCCESS);
632 }
633
634 /*
635 * Function for explicitly turning on system leds
636 * for a failed/degraded RMC (SC).
637 */
638 static void
solaris_setleds(const char * led_path,int leds)639 solaris_setleds(const char *led_path, int leds)
640 {
641 i2c_gpio_t gpio;
642 int fd = open(led_path, O_RDWR);
643
644 if (fd < 0)
645 return;
646
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);
653 }
654 (void) close(fd);
655 }
656
657 /*
658 * Function for explicitly turning on system leds
659 * for a failed/degraded RMC (SC) on Seattle
660 */
661 static void
seattle_setleds(void)662 seattle_setleds(void)
663 {
664 int fd;
665
666 fd = open(SEATTLE_LED_DEV, O_RDWR);
667
668 if (fd < 0)
669 return;
670
671 ioctl(fd, EPIC_SET_POWER_LED, (char *)0);
672 ioctl(fd, EPIC_SET_ALERT_LED, (char *)0);
673 (void) close(fd);
674 }
675
676 /*
677 * Function for explicitly turning on the front system leds
678 * for a failed/degraded RMC (SC) on Boston
679 */
680 static void
boston_set_frontleds(const char * led_path,int leds)681 boston_set_frontleds(const char *led_path, int leds)
682 {
683 i2c_gpio_t gpio;
684 int fd = open(led_path, O_RDWR);
685
686 if (fd < 0) {
687 return;
688 }
689
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;
696 }
697
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;
704 }
705
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);
711 }
712
713 /*
714 * Function for explicitly turning on the rear system leds
715 * for a failed/degraded RMC (SC) on Boston
716 */
717 static void
boston_set_rearleds(const char * led_path,int leds)718 boston_set_rearleds(const char *led_path, int leds)
719 {
720 i2c_gpio_t gpio;
721 int fd = open(led_path, O_RDWR);
722
723 if (fd < 0) {
724 return;
725 }
726
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;
733 }
734
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;
741 }
742
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);
748 }
749
750 static void
rmc_state_event(void)751 rmc_state_event(void)
752 {
753 envmon_hpu_t hpu;
754 int res;
755 int fd = open(sc_device_name, O_RDONLY);
756
757 if (fd < 0)
758 return;
759
760 (void) strlcpy(hpu.id.name, RMC_NAME, sizeof (hpu.id.name));
761 res = ioctl(fd, ENVMONIOCHPU, &hpu);
762 (void) close(fd);
763
764 if ((res == 0) && (hpu.sensor_status == ENVMON_SENSOR_OK) &&
765 ((hpu.fru_status & ENVMON_FRU_FAULT) != 0)) {
766 /*
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.
770 */
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);
777 /*
778 * the device name for the bezel leds GPIO device
779 * tends to vary from Unix to Unix. Search for it.
780 */
781 if (bezel_leds == NULL) {
782 bezel_leds =
783 create_bezel_leds_pathname(ENXS_LED_DIR,
784 ENXS_FRONT_LEDS);
785 }
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:
792 /*
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.
796 */
797 if (bezel_leds == NULL) {
798 bezel_leds =
799 create_bezel_leds_pathname(ENTS_LED_DIR,
800 ENTS_LEDS);
801 }
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;
826 }
827 }
828 }
829
830 static int
find_picl_handle(picl_prophdl_t proph)831 find_picl_handle(picl_prophdl_t proph)
832 {
833 int index;
834
835 if (idprop == NULL)
836 return (-1);
837
838 for (index = 0; index < idprop->num; index++) {
839 if (idprop->idp[index].volprop == proph)
840 return (index);
841 }
842
843 return (-1);
844 }
845
846 static int
find_vol_prop_by_name(const char * name)847 find_vol_prop_by_name(const char *name)
848 {
849 int index;
850
851 if (idprop == NULL)
852 return (-1);
853
854 for (index = 0; index < idprop->num; index++) {
855 if (strcmp(idprop->idp[index].envhandle.name, name) == 0)
856 return (index);
857 }
858
859 return (-1);
860 }
861
862 /*
863 * This function is the fini entry point of the plugin.
864 */
865 static void
piclfrudr_fini(void)866 piclfrudr_fini(void)
867 {
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;
876 }
877 if (sc_device_name != NULL) {
878 free(sc_device_name);
879 sc_device_name = NULL;
880 }
881 }
882
883 /*
884 * subroutine for various functions. Finds immediate child of parh with
885 * requested name if present. Otherwise returns NULL.
886 */
887 static picl_nodehdl_t
find_child_by_name(picl_nodehdl_t parh,char * name)888 find_child_by_name(picl_nodehdl_t parh, char *name)
889 {
890 picl_nodehdl_t nodeh;
891 int err;
892 char nodename[PICL_PROPNAMELEN_MAX];
893
894 err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD,
895 &nodeh, sizeof (picl_nodehdl_t));
896 if (err != PICL_SUCCESS)
897 return (0);
898 for (;;) {
899 err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename,
900 sizeof (nodename));
901 if (err != PICL_SUCCESS)
902 return (0);
903 if (strcmp(name, nodename) == 0) {
904 return (nodeh);
905 }
906 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
907 &nodeh, sizeof (picl_nodehdl_t));
908 if (err != PICL_SUCCESS)
909 return (0);
910 }
911 }
912
913 /* Creates a reference property for a given PICL node */
914 static int
add_prop_ref(picl_nodehdl_t nodeh,picl_nodehdl_t value,char * name)915 add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name)
916 {
917 picl_prophdl_t proph;
918 ptree_propinfo_t propinfo;
919 int err;
920
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);
927 }
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);
932 }
933 return (PICL_SUCCESS);
934 }
935
936 /* create an entry in the specified table */
937 static int
create_table_entry(picl_prophdl_t tblhdl,picl_nodehdl_t refhdl,char * class)938 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
939 {
940 int err;
941 ptree_propinfo_t prop;
942 picl_prophdl_t prophdl[2];
943
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);
957 }
958
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);
971 }
972
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);
978 }
979
980 /* create an empty table property */
981 static int
create_table(picl_nodehdl_t fruhdl,picl_prophdl_t * tblhdlp,char * tbl_name)982 create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
983 {
984 int err;
985 ptree_propinfo_t prop;
986 picl_prophdl_t tblprophdl;
987
988 err = ptree_create_table(tblhdlp);
989 if (err != PICL_SUCCESS) {
990 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
991 return (err);
992 }
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);
1005 }
1006
1007 /*
1008 * The size of outfilename must be PATH_MAX
1009 */
1010 static int
get_config_file(char * outfilename,char * fru)1011 get_config_file(char *outfilename, char *fru)
1012 {
1013 char nmbuf[SYS_NMLN];
1014 char pname[PATH_MAX];
1015 int dir;
1016
1017 for (dir = 0; dir < 2; dir++) {
1018 if (sysinfo(dir == 0 ? SI_PLATFORM : SI_MACHINE,
1019 nmbuf, sizeof (nmbuf)) == -1) {
1020 continue;
1021 }
1022
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);
1027
1028 if (access(pname, R_OK) == 0) {
1029 (void) strlcpy(outfilename, pname, PATH_MAX);
1030 return (0);
1031 }
1032 }
1033
1034 (void) snprintf(pname, PATH_MAX, "%s/%s%s%s",
1035 PICLD_COMMON_PLUGIN_DIR, CONFFILE_PREFIX, fru,
1036 CONFFILE_SUFFIX);
1037
1038 if (access(pname, R_OK) == 0) {
1039 (void) strlcpy(outfilename, pname, PATH_MAX);
1040 return (0);
1041 }
1042
1043 return (-1);
1044 }
1045
1046 /*
1047 * This helper function for Netra-440 fan tray removal removes
1048 * the rmclomv-rooted nodes and their properties.
1049 */
1050 static void
delete_node_and_props(picl_nodehdl_t hdl)1051 delete_node_and_props(picl_nodehdl_t hdl)
1052 {
1053 picl_prophdl_t prop;
1054 int err;
1055
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);
1061 }
1062 } while (err == PICL_SUCCESS);
1063 if (ptree_delete_node(hdl) == PICL_SUCCESS)
1064 (void) ptree_destroy_node(hdl);
1065 }
1066
1067 static void
remove_fru_parents(picl_nodehdl_t fruh)1068 remove_fru_parents(picl_nodehdl_t fruh)
1069 {
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;
1078
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;
1084 }
1085
1086 retval = ptree_get_prop_by_name(fruh, PICL_PROP_DEVICES, &tableh);
1087 if (retval != PICL_SUCCESS) {
1088 /*
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.
1095 */
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;
1113 }
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;
1122 }
1123
1124 /*
1125 * follow all reference properties in the second
1126 * column of the table and delete any _fru_parent node
1127 * at the referenced node.
1128 */
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;
1133 }
1134
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;
1140 }
1141
1142 /*
1143 * starting at next col, get every entry in the column
1144 */
1145 for (retval = ptree_get_next_by_row(tblh, &tblh);
1146 retval == PICL_SUCCESS;
1147 retval = ptree_get_next_by_col(tblh, &tblh)) {
1148 /*
1149 * should be a ref prop in our hands,
1150 * get the target node handle
1151 */
1152 retval = ptree_get_propval(tblh, &nodeh,
1153 sizeof (nodeh));
1154 if (retval != PICL_SUCCESS) {
1155 continue;
1156 }
1157 /*
1158 * got the referenced node, has it got a
1159 * _fru_parent property?
1160 */
1161 retval = ptree_get_prop_by_name(nodeh,
1162 PICL_REFPROP_FRU_PARENT, &fruph);
1163 if (retval != PICL_SUCCESS) {
1164 /*
1165 * on Boston, Seattle and Netra-440 we should
1166 * actually be looking for the _location_parent
1167 * property for fan frus
1168 */
1169 if (fanfru) {
1170 retval = ptree_get_prop_by_name(nodeh,
1171 PICL_REFPROP_LOC_PARENT, &fruph);
1172 }
1173 if (retval != PICL_SUCCESS)
1174 continue;
1175 }
1176 /*
1177 * got a _fru_parent node reference delete it
1178 */
1179 if (ptree_delete_prop(fruph) == PICL_SUCCESS)
1180 (void) ptree_destroy_prop(fruph);
1181
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);
1186 }
1187 }
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);
1197 }
1198 }
1199
1200 static void
remove_tables(picl_nodehdl_t rootnd)1201 remove_tables(picl_nodehdl_t rootnd)
1202 {
1203 picl_nodehdl_t tableh;
1204 int retval;
1205
1206 retval = ptree_get_prop_by_name(rootnd, PICL_PROP_DEVICES, &tableh);
1207
1208 if (retval == PICL_SUCCESS) {
1209 /*
1210 * found a Devices property, delete it
1211 */
1212 if ((retval = ptree_delete_prop(tableh)) == PICL_SUCCESS) {
1213 (void) ptree_destroy_prop(tableh);
1214 }
1215 }
1216
1217 /*
1218 * is there a child node?
1219 */
1220 retval = ptree_get_propval_by_name(rootnd, PICL_PROP_CHILD, &rootnd,
1221 sizeof (rootnd));
1222
1223 while (retval == PICL_SUCCESS) {
1224
1225 remove_tables(rootnd);
1226
1227 /*
1228 * any siblings?
1229 */
1230 retval = ptree_get_propval_by_name(rootnd, PICL_PROP_PEER,
1231 &rootnd, sizeof (rootnd));
1232 }
1233 }
1234
1235 /*
1236 * Event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events
1237 */
1238 /* ARGSUSED */
1239 static void
frudr_completion_handler(char * ename,void * earg,size_t size)1240 frudr_completion_handler(char *ename, void *earg, size_t size)
1241 {
1242 picl_nodehdl_t fruh;
1243 picl_nodehdl_t parh;
1244 picl_nodehdl_t peerh = 0;
1245 char nodename[PICL_PROPNAMELEN_MAX] = { '\0' };
1246 int err;
1247
1248 if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
1249 /*
1250 * now frudata has been notified that the node is to be
1251 * removed, we can actually remove it
1252 */
1253 fruh = 0;
1254 (void) nvlist_lookup_uint64(earg,
1255 PICLEVENTARG_FRUHANDLE, &fruh);
1256 if (fruh != 0) {
1257 (void) ptree_get_propval_by_name(fruh, PICL_PROP_PEER,
1258 &peerh, sizeof (peerh));
1259
1260 /*
1261 * first find name of the fru
1262 */
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));
1269 }
1270 if (err == PICL_SUCCESS) {
1271 /*
1272 * if it was a power supply, delete i2c node
1273 */
1274 if (strncmp(nodename, PS_NAME,
1275 PS_NAME_LEN) == 0) {
1276 (void) delete_i2c_node(nodename);
1277 }
1278
1279 /*
1280 * is disk node, make thread re-evaluate led
1281 * state
1282 */
1283 if (strncmp(nodename, DISK_NAME,
1284 DISK_NAME_LEN) == 0) {
1285 disk_ready[nodename[DISK_NAME_LEN] -
1286 '0'] = -1;
1287 }
1288 }
1289
1290 remove_fru_parents(fruh);
1291
1292 /*
1293 * now we can delete the node
1294 */
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);
1300 }
1301
1302 if ((sys_platform == PLAT_CHALUPA19) &&
1303 (strncmp(nodename, FT_NAME, FT_NAME_LEN) == 0) &&
1304 (peerh != 0)) {
1305 /*
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.
1312 */
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);
1319 }
1320 }
1321 }
1322 }
1323
1324 free(ename);
1325 nvlist_free(earg);
1326 }
1327
1328 /*
1329 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
1330 */
1331 static void
post_frudr_event(char * ename,picl_nodehdl_t parenth,picl_nodehdl_t fruh)1332 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
1333 {
1334 nvlist_t *nvl;
1335 char *ev_name;
1336
1337 ev_name = strdup(ename);
1338 if (ev_name == NULL)
1339 return;
1340 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) {
1341 free(ev_name);
1342 return;
1343 }
1344 if (parenth != 0L &&
1345 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
1346 free(ev_name);
1347 nvlist_free(nvl);
1348 return;
1349 }
1350 if (fruh != 0L &&
1351 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
1352 free(ev_name);
1353 nvlist_free(nvl);
1354 return;
1355 }
1356 if (ptree_post_event(ev_name, nvl, sizeof (nvl),
1357 frudr_completion_handler) != 0) {
1358 free(ev_name);
1359 nvlist_free(nvl);
1360 }
1361 }
1362
1363 static void
add_ps_to_platform(char * unit)1364 add_ps_to_platform(char *unit)
1365 {
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];
1372
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;
1384 }
1385
1386 if (res != PICL_SUCCESS)
1387 return;
1388 /*
1389 * seeprom nodes sit below this node,
1390 * is there one with the supplied unit address?
1391 */
1392 res = ptree_get_propval_by_name(parent_hdl, PICL_PROP_CHILD,
1393 &child_hdl, sizeof (picl_nodehdl_t));
1394
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 */
1405 }
1406 }
1407
1408 /*
1409 * found platform location for PS seeprom node, create it
1410 */
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);
1419 }
1420
1421 static void
get_fantray_path(char * ap_id,char * path,int bufsz)1422 get_fantray_path(char *ap_id, char *path, int bufsz)
1423 {
1424 char ft_id[FT_ID_BUFSZ];
1425
1426 (void) strlcpy(ft_id, ap_id, FT_ID_BUFSZ);
1427
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);
1440 }
1441 break;
1442
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);
1454 }
1455 break;
1456
1457 case PLAT_BOSTON:
1458 (void) snprintf(path, bufsz, SYS_BOARD_PATH, ft_id);
1459 break;
1460
1461 default:
1462 (void) snprintf(path, bufsz, CHASSIS_LOC_PATH, ft_id);
1463 break;
1464 }
1465 }
1466
1467 /*
1468 * handle EC_DR picl events
1469 */
1470 /*ARGSUSED*/
1471 static void
frudr_evhandler(const char * ename,const void * earg,size_t size,void * cookie)1472 frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
1473 {
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;
1486
1487 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0) {
1488 return;
1489 }
1490
1491 if (nvlist_unpack((char *)earg, size, &nvlp, 0)) {
1492 return;
1493 }
1494
1495 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
1496 nvlist_free(nvlp);
1497 return;
1498 }
1499
1500 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
1501 nvlist_free(nvlp);
1502 return;
1503 }
1504
1505 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
1506 nvlist_free(nvlp);
1507 return;
1508 }
1509
1510 /*
1511 * check ap_id really is a hot-plug device
1512 */
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;
1527 }
1528
1529 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
1530 nvlist_free(nvlp);
1531 return;
1532 }
1533
1534 /*
1535 * OK - so this is an EC_DR event - let's handle it.
1536 */
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;
1559 }
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);
1564 }
1565 }
1566
1567 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
1568 nvlist_free(nvlp);
1569 return;
1570 }
1571
1572 /*
1573 * now either add or delete the fru node as appropriate. If no
1574 * hint, treat as insert and update the tree if necessary.
1575 */
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) {
1579 /*
1580 * fru was there - but has gone away
1581 */
1582 post_frudr_event(PICL_FRU_REMOVED, 0, fruh);
1583 }
1584 } else if (rmc_flag) {
1585 /*
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).
1589 */
1590 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD,
1591 &fruh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
1592 fruh = 0;
1593 }
1594 post_frudr_event(PICL_FRU_ADDED, locnodeh, fruh);
1595 } else {
1596 /*
1597 * fru has been inserted (or may need to update)
1598 * if node already there, then just return
1599 */
1600 childh = find_child_by_name(locnodeh, fru_name);
1601 if (childh != 0) {
1602 nvlist_free(nvlp);
1603 return;
1604 }
1605
1606 /*
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.
1611 */
1612 if ((sys_platform != PLAT_CHALUPA19) ||
1613 (strncmp(fru_name, FT_FRU_NAME, FT_FRU_NAME_LEN) != 0)) {
1614 /*
1615 * create requested fru node
1616 */
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;
1623 }
1624 }
1625
1626 /*
1627 * power supplies have operational status and fruid -
1628 * add OperationalStatus property and create i2c device node
1629 * before posting fru_added event
1630 */
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));
1639 }
1640
1641 /*
1642 * now post event
1643 */
1644 post_frudr_event(PICL_FRU_ADDED, locnodeh, 0);
1645 }
1646 nvlist_free(nvlp);
1647 }
1648
1649 /*
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.
1663 */
1664 /*ARGSUSED*/
1665 static void
fru_add_handler(const char * ename,const void * earg,size_t size,void * cookie)1666 fru_add_handler(const char *ename, const void *earg, size_t size, void *cookie)
1667 {
1668 int retval;
1669 picl_nodehdl_t locnodeh;
1670 picl_nodehdl_t rooth;
1671 char path[MAXPATHLEN];
1672 char *fru_name;
1673
1674 if (strcmp(ename, PICL_FRU_ADDED) != 0)
1675 return;
1676
1677 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1678 PICLEVENTARG_PARENTHANDLE, &locnodeh);
1679 if (retval != PICL_SUCCESS)
1680 return;
1681
1682 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME,
1683 path, sizeof (path));
1684 if (retval != PICL_SUCCESS)
1685 return;
1686
1687 fru_name = strdup(path);
1688 if (fru_name == NULL)
1689 return;
1690
1691 /*
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.
1702 */
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);
1708 }
1709 }
1710
1711 /*
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.
1716 */
1717 opst_init();
1718
1719 /*
1720 * see if there's a .conf file for this fru
1721 */
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);
1727 }
1728 }
1729
1730 free(fru_name);
1731 }
1732
1733 /*
1734 * Handle PICLEVENT_SYSEVENT_DEVICE_ADDED events.
1735 */
1736 /*ARGSUSED*/
1737 static void
frutree_evhandler(const char * ename,const void * earg,size_t size,void * cookie)1738 frutree_evhandler(const char *ename, const void *earg, size_t size,
1739 void *cookie)
1740 {
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;
1751
1752 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) != 0)
1753 return;
1754
1755 if (nvlist_unpack((char *)earg, size, &nvlp, 0))
1756 return;
1757
1758 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
1759 nvlist_free(nvlp);
1760 return;
1761 }
1762
1763 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
1764 nvlist_free(nvlp);
1765 return;
1766 }
1767
1768 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &dpath)) {
1769 nvlist_free(nvlp);
1770 return;
1771 }
1772
1773 fru_name = strdup(dpath);
1774 if (fru_name == NULL) {
1775 nvlist_free(nvlp);
1776 return;
1777 }
1778
1779 nvlist_free(nvlp);
1780
1781 /*
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"
1787 */
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);
1798 }
1799 }
1800 }
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';
1827 }
1828 done = B_TRUE;
1829 }
1830 }
1831 }
1832 }
1833 }
1834 if (done == B_FALSE) {
1835 free(fru_name);
1836 return;
1837 }
1838
1839 /*
1840 * see if there's a .conf file for this fru
1841 */
1842
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);
1848 }
1849 }
1850 }
1851
1852 free(fru_name);
1853 }
1854
1855 static int
set_led(char * name,char * ptr,char * value)1856 set_led(char *name, char *ptr, char *value)
1857 {
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];
1869
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;
1888 }
1889
1890 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
1891 return (PICL_FAILURE);
1892 }
1893
1894 /*
1895 * if no fru node, then turn led off
1896 */
1897 if (find_child_by_name(locnodeh, DISK_FRU_NAME) != 0)
1898 value_ptr = value;
1899 else
1900 value_ptr = PICL_PROPVAL_OFF;
1901
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);
1908
1909 /* get first col, first row */
1910 if (ptree_get_next_by_col(tblh, &tblh) != PICL_SUCCESS)
1911 return (PICL_FAILURE);
1912
1913 /*
1914 * starting at next col, get every entry in the column
1915 */
1916 for (retval = ptree_get_next_by_row(tblh, &tblh);
1917 retval == PICL_SUCCESS;
1918 retval = ptree_get_next_by_col(tblh, &tblh)) {
1919 /*
1920 * get the target node handle
1921 */
1922 if (ptree_get_propval(tblh, &nodeh, sizeof (nodeh))
1923 != PICL_SUCCESS)
1924 continue;
1925
1926 /*
1927 * check it's a led
1928 */
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;
1934
1935 /*
1936 * check its the right led
1937 */
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) {
1942 /*
1943 * set it
1944 */
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);
1954 }
1955 }
1956 return (PICL_FAILURE);
1957 }
1958
1959 /*
1960 * function to find first node of specified class beneath supplied node
1961 */
1962 static int
get_node_by_class(picl_nodehdl_t nodeh,const char * classname,picl_nodehdl_t * foundnodeh)1963 get_node_by_class(picl_nodehdl_t nodeh, const char *classname,
1964 picl_nodehdl_t *foundnodeh)
1965 {
1966 int err;
1967 char clname[PICL_CLASSNAMELEN_MAX+1];
1968 picl_nodehdl_t childh;
1969
1970 /*
1971 * go through the children
1972 */
1973 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &childh,
1974 sizeof (picl_nodehdl_t));
1975
1976 while (err == PICL_SUCCESS) {
1977 err = ptree_get_propval_by_name(childh, PICL_PROP_CLASSNAME,
1978 clname, sizeof (clname));
1979
1980 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0)) {
1981 *foundnodeh = childh;
1982 return (PICL_SUCCESS);
1983 }
1984
1985 err = get_node_by_class(childh, classname, foundnodeh);
1986 if (err == PICL_SUCCESS)
1987 return (PICL_SUCCESS);
1988
1989 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER,
1990 &childh, sizeof (picl_nodehdl_t));
1991 }
1992
1993 return (PICL_NODENOTFOUND);
1994 }
1995
1996 /*
1997 * get system-controller node
1998 */
1999 static int
get_sys_controller_node(picl_nodehdl_t * nodeh)2000 get_sys_controller_node(picl_nodehdl_t *nodeh)
2001 {
2002 int err;
2003
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);
2010 }
2011
2012 /*
2013 * create pathname string for system-controller device
2014 */
2015 static char *
create_sys_controller_pathname(picl_nodehdl_t sysconh)2016 create_sys_controller_pathname(picl_nodehdl_t sysconh)
2017 {
2018 char *ptr;
2019 char namebuf[PATH_MAX];
2020 size_t len;
2021 DIR *dirp;
2022 struct dirent *dp;
2023 struct stat statbuf;
2024
2025 /*
2026 * prefix devfs-path name with /devices
2027 */
2028 (void) strlcpy(namebuf, DEV_PREFIX, PATH_MAX);
2029
2030 /*
2031 * append devfs-path property
2032 */
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);
2037 }
2038
2039 /*
2040 * locate final component of name
2041 */
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);
2050 }
2051 *ptr++ = '/'; /* restore '/' and advance to final name */
2052
2053 while ((dp = readdir(dirp)) != NULL) {
2054 /*
2055 * look for a name which starts with the string at *ptr
2056 */
2057 if (strlen(dp->d_name) < len)
2058 continue; /* skip short names */
2059 if (strncmp(dp->d_name, ptr, len) == 0) {
2060 /*
2061 * Got a match, restore full pathname and stat the
2062 * entry. Reject if not a char device
2063 */
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 */
2070 /*
2071 * go with this entry
2072 */
2073 (void) closedir(dirp);
2074 return (strdup(namebuf));
2075 }
2076 }
2077 (void) closedir(dirp);
2078 return (NULL);
2079 }
2080
2081 /*
2082 * create pathname string for bezel leds device
2083 */
2084 static char *
create_bezel_leds_pathname(const char * dirpath,const char * devname)2085 create_bezel_leds_pathname(const char *dirpath, const char *devname)
2086 {
2087 char namebuf[PATH_MAX];
2088 size_t lendirpath;
2089 size_t len;
2090 DIR *dirp;
2091 struct dirent *dp;
2092 struct stat statbuf;
2093
2094 /*
2095 * start with directory name
2096 */
2097 (void) strlcpy(namebuf, dirpath, PATH_MAX);
2098
2099 /*
2100 * append devfs-path property
2101 */
2102 lendirpath = strlen(namebuf);
2103 dirp = opendir(namebuf);
2104 if (dirp == NULL) {
2105 return (NULL);
2106 }
2107
2108 len = strlen(devname);
2109
2110 while ((dp = readdir(dirp)) != NULL) {
2111 /*
2112 * look for a name which starts with the gpio string
2113 */
2114 if (strlen(dp->d_name) < len)
2115 continue; /* skip short names */
2116 if (strncmp(dp->d_name, devname, len) == 0) {
2117 /*
2118 * Got a match, restore full pathname and stat the
2119 * entry. Reject if not a char device
2120 */
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 */
2127 /*
2128 * go with this entry
2129 */
2130 (void) closedir(dirp);
2131 return (strdup(namebuf));
2132 }
2133 }
2134 (void) closedir(dirp);
2135 return (NULL);
2136 }
2137
2138 /*
2139 * initialise structure associated with nodes requiring OperationalStatus
2140 */
2141 static void
opst_init(void)2142 opst_init(void)
2143 {
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;
2155
2156 if (idprop != NULL) {
2157 /*
2158 * This must be a restart, clean up earlier allocation
2159 */
2160 free(idprop);
2161 idprop = NULL;
2162 }
2163
2164 if (sc_device_name == NULL)
2165 err = 1;
2166 else {
2167 fd = open(sc_device_name, O_RDONLY);
2168
2169 if (fd < 0) {
2170 syslog(LOG_ERR, EM_NO_SC_DEV);
2171 err = 1;
2172 }
2173 }
2174
2175 if (err == 0) {
2176 res = ioctl(fd, ENVMONIOCSYSINFO, &sysinfo);
2177
2178 if (res < 0) {
2179 syslog(LOG_ERR, EM_NO_SYSINFO, strerror(errno));
2180 (void) close(fd);
2181 err = 1;
2182 }
2183 }
2184
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;
2192 }
2193 }
2194
2195 if (err == 0) {
2196 idprop->maxnum = entries;
2197 hpu.id.name[0] = '\0'; /* request for first name */
2198 res = ioctl(fd, ENVMONIOCHPU, &hpu);
2199
2200 /*
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.
2205 */
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);
2213 }
2214 }
2215
2216 idprop->num = index;
2217 (void) close(fd);
2218 }
2219 }
2220
2221 static void
disk_leds_init(void)2222 disk_leds_init(void)
2223 {
2224 int err = 0, i;
2225
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;
2233 }
2234 }
2235
2236 /*
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.
2240 */
2241 for (i = 0; i < N_DISKS; i++)
2242 disk_ready[i] = -1;
2243
2244 if (ledsthr_created) {
2245 /*
2246 * this is a restart, wake up sleeping threads
2247 */
2248 err = pthread_mutex_lock(&g_mutex);
2249 if (err != 0) {
2250 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno));
2251 return;
2252 }
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;
2266 }
2267 ledsthr_created = B_TRUE;
2268 }
2269 }
2270
2271 static void
disk_leds_fini(void)2272 disk_leds_fini(void)
2273 {
2274 int err, i;
2275
2276 /*
2277 * turn the leds off as we'll no longer be monitoring them
2278 */
2279 for (i = 0; i < N_DISKS; i++)
2280 (void) set_led(disk_name[i], REMOK_LED, PICL_PROPVAL_OFF);
2281
2282 /*
2283 * disk_leds_thread() never started or an error occured so
2284 * that it's not running
2285 */
2286 if (!disk_leds_thread_running)
2287 return;
2288
2289 /*
2290 * tell led thread to pause
2291 */
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;
2298 }
2299 g_finish_now = B_TRUE;
2300 disk_leds_thread_ack = B_FALSE;
2301 (void) pthread_cond_broadcast(&g_cv);
2302
2303 /*
2304 * and wait for them to acknowledge
2305 */
2306 while (!disk_leds_thread_ack) {
2307 (void) pthread_cond_wait(&g_cv_ack, &g_mutex);
2308 }
2309 (void) pthread_mutex_unlock(&g_mutex);
2310 }
2311
2312 static void
update_disk_node(char * fruname,char * devpath)2313 update_disk_node(char *fruname, char *devpath)
2314 {
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];
2323
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;
2341 }
2342
2343 if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
2344 return;
2345 }
2346 diskndh = find_child_by_name(slotndh, DISK_FRU_NAME);
2347 if (diskndh == 0) {
2348 return;
2349 }
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;
2366 }
2367 } else {
2368 /*
2369 * no mechanism for deleting row - so delete
2370 * whole table and start again
2371 */
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;
2383 }
2384 }
2385
2386 /*
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.
2390 */
2391 static int
raid_ok2rem_policy(raid_config_t config,int target)2392 raid_ok2rem_policy(raid_config_t config, int target)
2393 {
2394 int i;
2395
2396 for (i = 0; i < config.ndisks; i++) {
2397 int d = config.disk[i];
2398 int dstatus = config.diskstatus[i];
2399
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;
2408 }
2409 }
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;
2416 }
2417 }
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;
2424 }
2425 }
2426 break;
2427 default:
2428 break;
2429 }
2430 return (1);
2431 }
2432 }
2433 return (0);
2434 }
2435
2436 static int
check_raid(int target)2437 check_raid(int target)
2438 {
2439 raid_config_t config;
2440 int fd;
2441 int numvols;
2442 int i, j;
2443
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);
2458 }
2459 break;
2460 default:
2461 fd = -1;
2462 break;
2463 }
2464
2465 if (fd == -1) {
2466 return (0);
2467 }
2468
2469 if (ioctl(fd, RAID_NUMVOLUMES, &numvols)) {
2470 (void) close(fd);
2471 return (0);
2472 }
2473
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);
2479 }
2480 if (raid_ok2rem_policy(config, target)) {
2481 (void) close(fd);
2482 return (1);
2483 }
2484 }
2485
2486 (void) close(fd);
2487 return (0);
2488 }
2489
2490 /*ARGSUSED*/
2491 static void *
disk_leds_thread(void * args)2492 disk_leds_thread(void *args)
2493 {
2494 int c;
2495 int i;
2496 char **disk_dev;
2497 int fd;
2498
2499 devctl_hdl_t dhdl;
2500
2501 int n_disks = 0, do_raid = 0, err = 0;
2502 uint_t statep = 0;
2503
2504 static char *mpxu_devs[] = {
2505 "/pci@1c,600000/scsi@2/sd@0,0",
2506 "/pci@1c,600000/scsi@2/sd@1,0",
2507 "/pci@1c,600000/scsi@2/sd@2,0",
2508 "/pci@1c,600000/scsi@2/sd@3,0"
2509 };
2510
2511 static char *ents_devs[] = {
2512 "/pci@1d,700000/scsi@4/sd@0,0",
2513 "/pci@1d,700000/scsi@4/sd@1,0",
2514 "/pci@1d,700000/scsi@4/sd@2,0",
2515 "/pci@1d,700000/scsi@4/sd@3,0",
2516 "/pci@1d,700000/scsi@4/sd@8,0",
2517 "/pci@1d,700000/scsi@4/sd@9,0",
2518 "/pci@1d,700000/scsi@4/sd@a,0",
2519 "/pci@1d,700000/scsi@4/sd@b,0"
2520 };
2521
2522 static char *v440_devs[] = {
2523 "/pci@1f,700000/scsi@2/sd@0,0",
2524 "/pci@1f,700000/scsi@2/sd@1,0",
2525 "/pci@1f,700000/scsi@2/sd@2,0",
2526 "/pci@1f,700000/scsi@2/sd@3,0"
2527 };
2528
2529 static char *n210_devs[] = {
2530 "/pci@1c,600000/LSILogic,sas@1/sd@0,0",
2531 "/pci@1c,600000/LSILogic,sas@1/sd@1,0"
2532 };
2533
2534 static char *seattle_devs[] = {
2535 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@0,0",
2536 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@1,0",
2537 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@2,0",
2538 "/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@3,0"
2539 };
2540
2541 static char *boston_devs_1068e[] = {
2542 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@0,0",
2543 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@1,0",
2544 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@2,0",
2545 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@3,0",
2546 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@4,0",
2547 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@5,0",
2548 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@6,0",
2549 "/pci@1e,600000/pci@0/pci@2/scsi@0/sd@7,0"
2550 };
2551 static char *boston_devs_1068x[] = {
2552 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@0,0",
2553 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@1,0",
2554 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@2,0",
2555 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@3,0",
2556 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@4,0",
2557 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@5,0",
2558 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@6,0",
2559 "/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@7,0"
2560 };
2561
2562 char *ddev[N_DISKS]; /* "/devices" */
2563 char *pdev[N_DISKS]; /* "/platform" */
2564
2565 switch (sys_platform) {
2566
2567 case PLAT_ENTS:
2568 disk_dev = ents_devs;
2569 n_disks = N_ENTS_DISKS;
2570 break;
2571
2572 case PLAT_CHALUPA:
2573 case PLAT_CHALUPA19:
2574 do_raid = 1;
2575 disk_dev = v440_devs;
2576 n_disks = N_CHALUPA_DISKS;
2577 break;
2578
2579 case PLAT_SALSA19:
2580 disk_dev = n210_devs;
2581 n_disks = N_EN19_DISKS;
2582 break;
2583
2584 case PLAT_SEATTLE1U:
2585 case PLAT_SEATTLE2U:
2586 do_raid = 1;
2587 disk_dev = seattle_devs;
2588 n_disks = (sys_platform == PLAT_SEATTLE1U) ?
2589 N_SEATTLE1U_DISKS : N_SEATTLE2U_DISKS;
2590 break;
2591
2592 case PLAT_BOSTON:
2593 /*
2594 * If we can open the devctl path for the built-in 1068E
2595 * controller then assume we're a 1068E-equipped Boston
2596 * and make all the paths appropriate for that hardware.
2597 * Otherwise assume we are a 1068X-equipped Boston and
2598 * make all of the paths appropriate for a 1068X PCI-X
2599 * controller in PCI slot 4.
2600 *
2601 * The flag is also used in the check_raid() function.
2602 */
2603 if ((fd = open(BOSTON_DISK_DEVCTL_1068E, O_RDONLY)) != -1) {
2604 boston_1068e_flag = 1;
2605 disk_dev = boston_devs_1068e;
2606 } else {
2607 boston_1068e_flag = 0;
2608 disk_dev = boston_devs_1068x;
2609 }
2610 (void) close(fd);
2611 do_raid = 1;
2612 n_disks = N_BOSTON_DISKS;
2613 break;
2614
2615 default: /* PLAT_ENXS/PLAT_EN19 */
2616 disk_dev = mpxu_devs;
2617 n_disks = (sys_platform == PLAT_EN19) ?
2618 N_EN19_DISKS : N_MPXU_DISKS;
2619 }
2620
2621 /*
2622 * make up disk names
2623 */
2624
2625 for (i = 0; i < n_disks; i++) {
2626 char buffer[MAXPATHLEN];
2627 sprintf(buffer, "/devices%s", disk_dev[i]);
2628 ddev[i] = strdup(buffer);
2629 sprintf(buffer, "/platform%s", disk_dev[i]);
2630 pdev[i] = strdup(buffer);
2631 }
2632
2633 disk_leds_thread_running = B_TRUE;
2634
2635 for (;;) {
2636 for (i = 0; i < n_disks; i++) {
2637 /*
2638 * If it's one of the RAID disks, we have already
2639 * applied the ok2remove policy.
2640 */
2641 if (do_raid && check_raid(i)) {
2642 continue;
2643 }
2644
2645 dhdl = devctl_device_acquire(ddev[i], 0);
2646 devctl_device_getstate(dhdl, &statep);
2647 devctl_release(dhdl);
2648
2649 if (statep & DEVICE_OFFLINE) {
2650 if (disk_ready[i] != B_FALSE) {
2651 update_disk_node(disk_name[i], pdev[i]);
2652 if (set_led(disk_name[i], REMOK_LED,
2653 PICL_PROPVAL_ON) == PICL_SUCCESS)
2654 disk_ready[i] = B_FALSE;
2655 }
2656 } else if (statep & DEVICE_ONLINE) {
2657 if (disk_ready[i] != B_TRUE) {
2658 update_disk_node(disk_name[i], pdev[i]);
2659 if (set_led(disk_name[i], REMOK_LED,
2660 PICL_PROPVAL_OFF) == PICL_SUCCESS)
2661 disk_ready[i] = B_TRUE;
2662 }
2663 }
2664 }
2665
2666 /*
2667 * wait a bit until we check again
2668 */
2669
2670 (void) poll(NULL, 0, DISK_POLL_TIME);
2671
2672 /*
2673 * are we to stop?
2674 */
2675
2676 (void) pthread_mutex_lock(&g_mutex);
2677
2678 while (g_finish_now) {
2679 /*
2680 * notify _fini routine that we've paused
2681 */
2682 disk_leds_thread_ack = B_TRUE;
2683 (void) pthread_cond_signal(&g_cv_ack);
2684
2685 /*
2686 * and go to sleep in case we get restarted
2687 */
2688 (void) pthread_cond_wait(&g_cv, &g_mutex);
2689 }
2690 (void) pthread_mutex_unlock(&g_mutex);
2691 }
2692
2693 return ((void *)err);
2694 }
2695
2696 /*
2697 * Given the powersupply name, convert to addr
2698 */
2699 static int
ps_name_to_addr(char * name)2700 ps_name_to_addr(char *name)
2701 {
2702 int ps_addr = 0;
2703 if ((strcmp(name, PS0_NAME) == 0) ||
2704 (strcmp(name, PSU0_NAME) == 0)) {
2705 switch (sys_platform) {
2706 case PLAT_SEATTLE1U:
2707 case PLAT_SEATTLE2U:
2708 ps_addr = SEATTLE_PS0_ADDR;
2709 break;
2710 case PLAT_BOSTON:
2711 ps_addr = BOSTON_PS0_ADDR;
2712 break;
2713 default:
2714 ps_addr = PS0_ADDR;
2715 break;
2716 }
2717 } else if ((strcmp(name, PS1_NAME) == 0) ||
2718 (strcmp(name, PSU1_NAME) == 0)) {
2719 switch (sys_platform) {
2720 case PLAT_SEATTLE1U:
2721 case PLAT_SEATTLE2U:
2722 ps_addr = SEATTLE_PS1_ADDR;
2723 break;
2724 case PLAT_BOSTON:
2725 ps_addr = BOSTON_PS1_ADDR;
2726 break;
2727 default:
2728 ps_addr = PS1_ADDR;
2729 break;
2730 }
2731 } else if ((strcmp(name, PS2_NAME) == 0) ||
2732 (strcmp(name, PSU2_NAME) == 0)) {
2733 switch (sys_platform) {
2734 case PLAT_BOSTON:
2735 ps_addr = BOSTON_PS2_ADDR;
2736 break;
2737 default:
2738 ps_addr = PS2_ADDR;
2739 break;
2740 }
2741 } else if ((strcmp(name, PS3_NAME) == 0) ||
2742 (strcmp(name, PSU3_NAME) == 0)) {
2743 switch (sys_platform) {
2744 case PLAT_BOSTON:
2745 ps_addr = BOSTON_PS3_ADDR;
2746 break;
2747 default:
2748 ps_addr = PS3_ADDR;
2749 break;
2750 }
2751 }
2752
2753 return (ps_addr);
2754 }
2755
2756 /*
2757 * Given powersupply name, convert to unit addr
2758 */
2759 static char *
ps_name_to_unitaddr(char * name)2760 ps_name_to_unitaddr(char *name)
2761 {
2762 char *unitaddr;
2763
2764 if (strcmp(name, PS0_NAME) == 0) {
2765 switch (sys_platform) {
2766 case PLAT_SEATTLE1U:
2767 case PLAT_SEATTLE2U:
2768 unitaddr = SEATTLE_PS0_UNITADDR;
2769 break;
2770 case PLAT_BOSTON:
2771 unitaddr = BOSTON_PS0_UNITADDR;
2772 break;
2773 default:
2774 unitaddr = PS0_UNITADDR;
2775 break;
2776 }
2777 } else if (strcmp(name, PS1_NAME) == 0) {
2778 switch (sys_platform) {
2779 case PLAT_SEATTLE1U:
2780 case PLAT_SEATTLE2U:
2781 unitaddr = SEATTLE_PS1_UNITADDR;
2782 break;
2783 case PLAT_BOSTON:
2784 unitaddr = BOSTON_PS1_UNITADDR;
2785 break;
2786 default:
2787 unitaddr = PS1_UNITADDR;
2788 break;
2789 }
2790 } else if (strcmp(name, PS2_NAME) == 0) {
2791 switch (sys_platform) {
2792 case PLAT_BOSTON:
2793 unitaddr = BOSTON_PS2_UNITADDR;
2794 break;
2795 default:
2796 unitaddr = PS2_UNITADDR;
2797 break;
2798 }
2799 } else if (strcmp(name, PS3_NAME) == 0) {
2800 switch (sys_platform) {
2801 case PLAT_BOSTON:
2802 unitaddr = BOSTON_PS3_UNITADDR;
2803 break;
2804 default:
2805 unitaddr = PS3_UNITADDR;
2806 break;
2807 }
2808 }
2809 else
2810 unitaddr = NULL;
2811
2812 return (unitaddr);
2813 }
2814
2815 /*
2816 * converts apid to real FRU name in PICL tree. The
2817 * name of powersupply devices on chalupa19 are
2818 * PSU instead of PS
2819 */
2820 static char *
ps_apid_to_nodename(char * apid)2821 ps_apid_to_nodename(char *apid)
2822 {
2823 char *nodename;
2824
2825 if (sys_platform != PLAT_CHALUPA19)
2826 return (apid);
2827
2828 if (strcmp(apid, PS0_NAME) == 0)
2829 nodename = PSU0_NAME;
2830 else if (strcmp(apid, PS1_NAME) == 0)
2831 nodename = PSU1_NAME;
2832 else if (strcmp(apid, PS2_NAME) == 0)
2833 nodename = PSU2_NAME;
2834 else if (strcmp(apid, PS3_NAME) == 0)
2835 nodename = PSU3_NAME;
2836 else
2837 nodename = apid;
2838
2839 return (nodename);
2840 }
2841
2842 /*
2843 * Create SEEPROM node at insertion time.
2844 */
2845 static int
create_i2c_node(char * ap_id)2846 create_i2c_node(char *ap_id)
2847 {
2848 int nd_reg[2];
2849 devctl_ddef_t ddef_hdl;
2850 devctl_hdl_t bus_hdl;
2851 devctl_hdl_t dev_hdl;
2852 char dev_path[MAXPATHLEN];
2853 char *compatible;
2854
2855 /* create seeprom node */
2856 nd_reg[0] = 0;
2857 nd_reg[1] = ps_name_to_addr(ap_id);
2858
2859 switch (sys_platform) {
2860 case PLAT_SEATTLE1U:
2861 case PLAT_SEATTLE2U:
2862 bus_hdl = devctl_bus_acquire(SEATTLE_PSU_I2C_BUS_DEV, 0);
2863 compatible = SEATTLE_PSU_COMPATIBLE;
2864 break;
2865 case PLAT_BOSTON:
2866 bus_hdl = devctl_bus_acquire(BOSTON_PSU_I2C_BUS_DEV, 0);
2867 compatible = BOSTON_PSU_COMPATIBLE;
2868 break;
2869 default:
2870 bus_hdl = devctl_bus_acquire(PSU_I2C_BUS_DEV, 0);
2871 compatible = PSU_COMPATIBLE;
2872 break;
2873 }
2874
2875 if (bus_hdl == NULL)
2876 return (DDI_FAILURE);
2877
2878 /* device definition properties */
2879 ddef_hdl = devctl_ddef_alloc(PS_DEVICE_NAME, 0);
2880 (void) devctl_ddef_string(ddef_hdl, "compatible", compatible);
2881 (void) devctl_ddef_string(ddef_hdl, "device_type", "seeprom");
2882 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg);
2883
2884 /* create the device node */
2885 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl))
2886 return (DDI_FAILURE);
2887
2888 if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL)
2889 return (DDI_FAILURE);
2890
2891 devctl_release(dev_hdl);
2892 devctl_ddef_free(ddef_hdl);
2893 devctl_release(bus_hdl);
2894 return (DDI_SUCCESS);
2895 }
2896
2897 /*
2898 * Delete SEEPROM node at insertion time.
2899 */
2900 static void
delete_i2c_node(char * ap_id)2901 delete_i2c_node(char *ap_id)
2902 {
2903 devctl_hdl_t dev_hdl;
2904 char buf[MAXPATHLEN];
2905
2906 switch (sys_platform) {
2907 case PLAT_SEATTLE1U:
2908 case PLAT_SEATTLE2U:
2909 sprintf_buf2(buf, SEATTLE_PSU_DEV, ps_name_to_addr(ap_id));
2910 break;
2911 case PLAT_BOSTON:
2912 sprintf_buf2(buf, BOSTON_PSU_DEV, ps_name_to_addr(ap_id));
2913 break;
2914 default:
2915 sprintf_buf2(buf, PSU_DEV, ps_name_to_addr(ap_id));
2916 break;
2917 }
2918
2919 dev_hdl = devctl_device_acquire(buf, 0);
2920 if (dev_hdl == NULL) {
2921 return;
2922 }
2923
2924 /*
2925 * If the seeprom driver is not loaded, calls to
2926 * devctl_device_remove fails for seeprom devices
2927 */
2928 if (devctl_device_remove(dev_hdl)) {
2929 di_init_driver(SEEPROM_DRIVER_NAME, 0);
2930 devctl_device_remove(dev_hdl);
2931 }
2932 devctl_release(dev_hdl);
2933 }
2934
2935 static void
add_op_status(envmon_hpu_t * hpu,int * index)2936 add_op_status(envmon_hpu_t *hpu, int *index)
2937 {
2938 boolean_t rmc_flag;
2939 boolean_t ps_flag;
2940 boolean_t disk_flag;
2941 char node_name[MAXPATHLEN];
2942 boolean_t flag;
2943
2944 rmc_flag = (strcmp(hpu->id.name, RMC_NAME) == 0);
2945 ps_flag = (strncmp(hpu->id.name, PS_NAME,
2946 PS_NAME_LEN) == 0);
2947 disk_flag = (strncmp(hpu->id.name, DISK_NAME,
2948 DISK_NAME_LEN) == 0);
2949 if (rmc_flag || ps_flag) {
2950 idprop->idp[*index].envhandle = hpu->id;
2951 flag = rmc_flag && ((sys_platform != PLAT_CHALUPA) &&
2952 (sys_platform != PLAT_CHALUPA19));
2953 sprintf_buf2(node_name,
2954 flag ? SYS_BOARD_PATH : CHASSIS_LOC_PATH, ps_flag ?
2955 ps_apid_to_nodename(hpu->id.name) : hpu->id.name);
2956
2957 add_op_status_by_name(node_name, ps_flag ? PS_FRU_NAME : NULL,
2958 &idprop->idp[(*index)++].volprop);
2959 } else if (disk_flag) {
2960 idprop->idp[*index].envhandle = hpu->id;
2961 switch (sys_platform) {
2962 case PLAT_CHALUPA:
2963 case PLAT_CHALUPA19:
2964 sprintf_buf2(node_name, CHASSIS_LOC_PATH, hpu->id.name);
2965 break;
2966 case PLAT_SEATTLE1U:
2967 sprintf_buf2(node_name, SEATTLE1U_HDDBP_PATH, \
2968 hpu->id.name);
2969 break;
2970 case PLAT_SEATTLE2U:
2971 sprintf_buf2(node_name, SEATTLE2U_HDDBP_PATH, \
2972 hpu->id.name);
2973 break;
2974 case PLAT_BOSTON:
2975 sprintf_buf2(node_name, BOSTON_HDDBP_PATH, \
2976 hpu->id.name);
2977 break;
2978 default:
2979 sprintf_buf2(node_name, SYS_BOARD_PATH, hpu->id.name);
2980 break;
2981 }
2982 add_op_status_by_name(node_name, DISK_FRU_NAME,
2983 &idprop->idp[(*index)++].volprop);
2984 }
2985 }
2986