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