1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2000, 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/sunddi.h> 30 #include <sys/stat.h> 31 #include <sys/i2c/clients/i2c_client.h> 32 #include <sys/hpc3130_events.h> 33 #include <values.h> /* for BITSPERBYTE */ 34 #include <unistd.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <fcntl.h> 38 #include <strings.h> 39 #include <poll.h> 40 #include <libintl.h> 41 #include <errno.h> 42 #include <assert.h> 43 #include <config_admin.h> 44 #include <sys/daktari.h> 45 #include "sf880drd.h" 46 47 /* 48 * Hotplug Controller addresses. 49 */ 50 static const unsigned char controller_names[NUM_CONTROLLERS] = 51 { 0xe2, 0xe6, 0xe8, 0xec }; 52 53 #define INDEX2SLOT(INDEX) ((INDEX)%4) /* cf init_poll_events() */ 54 #define INDEX2CONTROLLER(INDEX) ((INDEX)/4) /* cf init_poll_events() */ 55 56 /* 57 * Local variables. 58 */ 59 static struct pollfd fds[NUM_FDS]; 60 static unsigned int fault_leds[2]; 61 static unsigned int ok2rem_leds[2]; 62 63 /* 64 * Local prototypes. 65 */ 66 static void init_poll_events(void); 67 static void process_event(int); 68 static void report_cfgadm_error(int, char *); 69 static void set_front_panel_led(uint8_t, boolean_t); 70 71 static int i2c_set_bit(int, int, uint8_t); 72 static void report_syscall_error(char *); 73 74 static void pushbutton_event(char *); 75 static void fault_led_event(hpc3130_event_type_t, int); 76 static void removable_led_event(hpc3130_event_type_t, int); 77 78 /* 79 * main(): loops forever looking for events. 80 */ 81 int 82 main() 83 { 84 int i; 85 int rv; 86 87 init_poll_events(); 88 for (;;) { 89 /* sleep in poll() waiting an event */ 90 rv = poll(fds, NUM_FDS, -1); 91 if (rv < 0) { 92 report_syscall_error("poll"); 93 continue; 94 } 95 96 /* woken up from poll() process the event */ 97 for (i = 0; i < NUM_FDS; ++i) { 98 if (fds[i].revents == POLLIN) 99 process_event(i); 100 } 101 } 102 /* NOTREACHED */ 103 return (0); 104 } 105 106 /* 107 * Set up poll fds. 108 */ 109 static void 110 init_poll_events() 111 { 112 int c; 113 int p; 114 int i = 0; 115 char buf[sizeof (HPC3130_DEV_FMT)+8]; 116 117 for (c = 0; c < NUM_CONTROLLERS; ++c) { 118 for (p = 0; p < SLOTS_PER_CONTROLLER; ++p) { 119 (void) sprintf(buf, HPC3130_DEV_FMT, 120 controller_names[c], p); 121 fds[i].events = POLLIN; 122 fds[i].fd = open(buf, O_RDWR); 123 if (fds[i].fd == -1) { 124 report_syscall_error(buf); 125 exit(-1); 126 } 127 i++; 128 } 129 } 130 } 131 132 /* 133 * Process poll events. 134 */ 135 static void 136 process_event(int fdi) 137 { 138 struct hpc3130_event e; 139 int rv; 140 int slot = INDEX2SLOT(fdi); 141 int cntr = INDEX2CONTROLLER(fdi); 142 143 rv = ioctl(fds[fdi].fd, HPC3130_GET_EVENT, &e); 144 if (rv == -1) { 145 report_syscall_error("HPC3130_GET_EVENT"); 146 return; 147 } 148 149 switch (e.id) { 150 case HPC3130_EVENT_INSERTION: 151 case HPC3130_EVENT_REMOVAL: 152 case HPC3130_EVENT_POWERON: 153 case HPC3130_EVENT_POWEROFF: 154 break; 155 case HPC3130_EVENT_BUTTON: 156 DPRINTF(("\nBUTTON EVENT slot (%s)\n", e.name)); 157 pushbutton_event(e.name); 158 break; 159 case HPC3130_LED_FAULT_ON: 160 DPRINTF(("\nFAULT LED ON EVENT\n")); 161 fault_led_event(e.id, fdi); 162 break; 163 case HPC3130_LED_FAULT_OFF: 164 DPRINTF(("\nFAULT LED OFF EVENT\n")); 165 fault_led_event(e.id, fdi); 166 break; 167 case HPC3130_LED_REMOVABLE_ON: 168 DPRINTF(("\nREMOVABLE LED ON EVENT\n")); 169 removable_led_event(e.id, fdi); 170 break; 171 case HPC3130_LED_REMOVABLE_OFF: 172 DPRINTF(("\nREMOVABLE LED OFF EVENT\n")); 173 removable_led_event(e.id, fdi); 174 break; 175 default: 176 (void) fprintf(stderr, "WARNING: bogus event: %x\n", e.id); 177 } 178 } 179 180 /* 181 * Button Event handler. 182 */ 183 static void 184 pushbutton_event(char *ap_id) 185 { 186 char *errstr = NULL; 187 struct cfga_list_data *stat = NULL; 188 int nlist; 189 cfga_cmd_t cmd; 190 cfga_err_t rv; 191 192 rv = config_list_ext(1, &ap_id, &stat, &nlist, 193 NULL, NULL, &errstr, 0); 194 if (rv != CFGA_OK) { 195 report_cfgadm_error(rv, errstr); 196 goto out; 197 } 198 assert(nlist == 1); 199 200 /* The only types of hotplug with buttons */ 201 assert(!(strcmp(stat->ap_class, "pci"))); 202 203 switch (stat->ap_o_state) { 204 case CFGA_STAT_UNCONFIGURED: 205 cmd = CFGA_CMD_CONFIGURE; 206 break; 207 case CFGA_STAT_CONFIGURED: 208 cmd = CFGA_CMD_DISCONNECT; 209 break; 210 default: 211 /* Should never get here */ 212 assert(0); 213 } 214 215 /* 216 * confp & msgp are NULL: when using the pushbutton, 217 * simply fail if prompting is required. 218 */ 219 rv = config_change_state(cmd, 1, &ap_id, NULL, NULL, NULL, &errstr, 0); 220 if (rv != CFGA_OK) { 221 report_cfgadm_error(rv, errstr); 222 /* FALLTHRU to "out" */ 223 } 224 225 out: 226 if (errstr) 227 free(errstr); 228 if (stat) 229 free(stat); 230 } 231 232 static void 233 fault_led_event(hpc3130_event_type_t event, int fdi) 234 { 235 int side = 0; 236 unsigned int old; 237 238 if (INDEX2CONTROLLER(fdi) != GPTWO_CONTROLLER) { 239 /* It's a PCI slot; left side of chassis */ 240 side = 1; 241 } 242 243 old = fault_leds[side]; 244 245 assert(fdi <= sizeof (fault_leds[side]) * BITSPERBYTE); 246 247 switch (event) { 248 case HPC3130_LED_FAULT_ON: 249 fault_leds[side] |= (1<<fdi); 250 DPRINTF(("fault_led_event: HPC3130_LED_FAULT_ON\n")); 251 break; 252 case HPC3130_LED_FAULT_OFF: 253 fault_leds[side] &= ~(1<<fdi); 254 DPRINTF(("fault_led_event: HPC3130_LED_FAULT_OFF\n")); 255 break; 256 } 257 258 DPRINTF(("fault_led_event: old(0x%x), fault_leds[%d](0x%x)\n", 259 old, side, fault_leds[side])); 260 261 if ((old == 0) != (fault_leds[side] == 0) && ok2rem_leds[side] == 0) { 262 /* 263 * The first FAULT LED has come on, or the last one has gone 264 * off on this side, and all the OK2REMOVE LEDS are off on this 265 * side. So we have to update the front panel ARROW LED. 266 */ 267 set_front_panel_led(side ? LEFT_DOOR_ATTEN_LED : 268 RIGHT_DOOR_ATTEN_LED, 269 fault_leds[side] ? LED_ON : LED_OFF); 270 } 271 } 272 273 static void 274 removable_led_event(hpc3130_event_type_t event, int fdi) 275 { 276 int side = 0; 277 unsigned int old; 278 279 if (INDEX2CONTROLLER(fdi) != GPTWO_CONTROLLER) { 280 /* It's a PCI slot; left side of chassis */ 281 side = 1; 282 } 283 284 old = ok2rem_leds[side]; 285 286 assert(fdi <= sizeof (ok2rem_leds[side]) * BITSPERBYTE); 287 288 switch (event) { 289 case HPC3130_LED_REMOVABLE_ON: 290 ok2rem_leds[side] |= (1<<fdi); 291 DPRINTF(("removable_led_event: HPC3130_LED_REMOVABLE_ON\n")); 292 break; 293 case HPC3130_LED_REMOVABLE_OFF: 294 ok2rem_leds[side] &= ~(1<<fdi); 295 DPRINTF(("removable_led_event: HPC3130_LED_REMOVABLE_OFF\n")); 296 break; 297 } 298 299 DPRINTF(("removable_led_event: old(0x%x), ok2rem_leds[%d](0x%x)\n", 300 old, side, ok2rem_leds[side])); 301 302 if ((old == 0) != (ok2rem_leds[side] == 0)) { 303 /* 304 * The first OKAY2REMOVE LED has come on, or the last 305 * one has gone off (on this side). We may have to update 306 * the front panel LEDs. 307 */ 308 if (ok2rem_leds[!side] == 0) { 309 /* 310 * The OK2REMOVE LEDs are all off on the other 311 * side of the chassis, so this side determines 312 * whether the front OK2REMOVE is on or off. 313 */ 314 set_front_panel_led(SYS_OK2REMOVE_LED, 315 ok2rem_leds[side] ? LED_ON : LED_OFF); 316 } 317 if (fault_leds[side] == 0) { 318 /* 319 * All the FAULT LEDs are off on this side. So the 320 * OK2REMOVE LEDs determine whether the ARROW LED is on. 321 */ 322 set_front_panel_led(side ? LEFT_DOOR_ATTEN_LED : 323 RIGHT_DOOR_ATTEN_LED, 324 ok2rem_leds[side] ? LED_ON : LED_OFF); 325 } 326 } 327 } 328 329 /* 330 * Set front panel system leds either on or off. 331 */ 332 static void 333 set_front_panel_led(uint8_t bit_num, boolean_t on_off) 334 { 335 int fd; 336 int rv; 337 i2c_bit_t arg; 338 339 fd = open(SSC050_LED_PORT, O_RDWR); 340 if (fd == -1) { 341 report_syscall_error("ssc050"); 342 return; 343 } 344 345 arg.bit_num = bit_num; 346 arg.bit_value = on_off; 347 348 rv = ioctl(fd, I2C_SET_BIT, &arg); 349 if (rv == -1) 350 report_syscall_error("LED I2C_SET_BIT"); 351 352 (void) close(fd); 353 } 354 355 static int 356 i2c_set_bit(int fp, int bit, uint8_t value) 357 { 358 int rv; 359 i2c_bit_t passin; 360 361 passin.bit_num = (uchar_t)bit; 362 passin.bit_value = value; 363 rv = ioctl(fp, I2C_SET_BIT, &passin); 364 return (rv); 365 } 366 367 static void 368 report_cfgadm_error(int cfgerrnum, char *errstr) 369 { 370 const char *ep; 371 372 ep = config_strerror(cfgerrnum); 373 374 if (ep == NULL) 375 ep = gettext("configuration administration unknown error"); 376 377 if (errstr != NULL && *errstr != '\0') { 378 (void) fprintf(stderr, "%s: %s\n", ep, errstr); 379 } else { 380 (void) fprintf(stderr, "%s\n", ep); 381 } 382 } 383 384 static void 385 report_syscall_error(char *msg) 386 { 387 if (errno != EINTR) 388 perror(msg); 389 } 390