# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # # Copyright (c) 2010, Intel Corporation. # All rights reserved. # # # cmd/acpihpd/Makefile # # Hammerhead: platform renamed from i86pc to amd64 PLATFORM = amd64 MANIFEST = acpihpd.xml SVCMETHOD = svc-acpihpd include ../Makefile.cmd # Hammerhead: amd64-only SUBDIRS= $(MACH64) ROOTMANIFESTDIR = $(ROOTSVCPLATFORM)/${PLATFORM} all : TARGET = all install : TARGET = install clean : TARGET = clean clobber : TARGET = clobber lint : TARGET = lint .KEEP_STATE: CLOBBERFILES += THIRDPARTYLICENSE all: $(SUBDIRS) install: $(SUBDIRS) $(ROOTMANIFEST) $(ROOTSVCMETHOD) all install: THIRDPARTYLICENSE THIRDPARTYLICENSE: acpihpd.c $(SED) -e '/sys\/param.h/,$$ d' acpihpd.c > $@ clean clobber lint: $(SUBDIRS) check: $(CHKMANIFEST) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include ../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2010, Intel Corporation. # All rights reserved. # # cmd/acpihpd/Makefile.com # LIBS = acpihpd include ../../Makefile.cmd include ../../../Makefile.psm OBJS = acpihpd.o notify.o SRCS = $(OBJS:%.o=../%.c) LINTFILES = $(SRCS:%.c=%.ln) CLOBBERFILES = $(LIBS) CFLAGS += $(CCVERBOSE) CPPFLAGS += -I$(USR_PSM_INCL_DIR) LDLIBS += -lsysevent -lnvpair -lcfgadm FILEMODE = 0755 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2010, Intel Corporation. # All rights reserved. # # cmd/acpihpd/Makefile.targ # .KEEP_STATE: all: $(LIBS) clean: $(RM) $(OBJS) lint: $(LINT.c) $(SRCS) $(LDLIBS) $(LIBS): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) %.o: ../%.c $(COMPILE.c) $< $(POST_PROCESS_O) $(USR_PLAT_DIR): -$(INS.dir) $(USR_PSM_DIR): $(USR_PLAT_DIR) -$(INS.dir) $(USR_PSM_LIB_DIR): $(USR_PSM_DIR) -$(INS.dir) $(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR) $(INS.file) include ../../Makefile.targ INTEL ACPI HOTPLUG DAEMON /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2010, Intel Corporation. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Signal handler type */ typedef void (sig_handler_t)(int); #define ACPIHPD_PID_FILE "/var/run/acpihpd.pid" /* lock file path */ /* Program Name */ char *g_prog_name; int g_debuglevel = 0; static int s_pid_fd; static sysevent_handle_t *s_acpihpd_hdl; static int daemon_init(void); static void daemon_quit(int); static int set_sig_handler(int, sig_handler_t *); static int acpihpd_init(void); static void acpihpd_fini(void); static void acpihpd_event(sysevent_t *); extern void notify_hotplug(sysevent_t *ev); void debug_print(int, const char *, ...); int main(int argc, char *argv[]) { int c; /* Get Program Name */ if ((g_prog_name = strrchr(argv[0], '/')) == NULL) { g_prog_name = argv[0]; } else { g_prog_name++; } while ((c = getopt(argc, argv, ":d:")) != -1) { switch (c) { case 'd': g_debuglevel = atoi(optarg); if ((g_debuglevel < 0) || (g_debuglevel > 2)) { g_debuglevel = 0; } break; case ':': syslog(LOG_ERR, "missed argument for option %c.", optopt); break; case '?': syslog(LOG_ERR, "unrecognized option %c.", optopt); break; } } s_acpihpd_hdl = NULL; /* Check the daemon running lock and initialize the signal */ if (daemon_init() != 0) { debug_print(0, "%s could not startup!", g_prog_name); exit(SMF_EXIT_ERR_FATAL); } /* Subscribe to the hotplug event */ if (acpihpd_init() != 0) { debug_print(0, "%s could not startup!", g_prog_name); daemon_quit(SMF_EXIT_ERR_FATAL); } debug_print(2, "daemon is running."); /*CONSTCOND*/ while (1) { (void) pause(); } return (SMF_EXIT_OK); } static int daemon_init(void) { int i, ret; pid_t pid; char pid_str[32]; if (geteuid() != 0) { debug_print(0, "must be root to execute %s", g_prog_name); return (1); } if ((pid = fork()) < 0) { return (1); } if (pid > 0) { /* Parent to exit. */ exit(SMF_EXIT_OK); } (void) setsid(); (void) chdir("/"); (void) umask(0); (void) closefrom(0); (void) open("/dev/null", O_RDONLY); (void) open("/dev/null", O_WRONLY); (void) dup(1); (void) openlog(g_prog_name, LOG_PID, LOG_DAEMON); /* * Create the lock file for singleton */ if ((s_pid_fd = open(ACPIHPD_PID_FILE, O_RDWR | O_CREAT, 0644)) < 0) { debug_print(0, "could not create pid file: %s", strerror(errno)); return (1); } if (lockf(s_pid_fd, F_TLOCK, 0L) < 0) { if (errno == EACCES || errno == EAGAIN) { debug_print(0, "another acpihpd is already running"); } else { debug_print(0, "could not lock pid file"); } return (1); } (void) ftruncate(s_pid_fd, 0); i = sprintf(pid_str, "%ld", (long)getpid()); while ((ret = write(s_pid_fd, pid_str, i)) != i) { if (errno == EINTR) { continue; } if (ret < 0) { debug_print(0, "pid file write failed: %s", strerror(errno)); return (1); } } if (set_sig_handler(SIGTERM, (sig_handler_t *)daemon_quit) != 0) { debug_print(2, "could not set signal handler(SIGTERM)"); return (1); } if (set_sig_handler(SIGQUIT, (sig_handler_t *)daemon_quit) != 0) { debug_print(2, "could not set signal handler(SIGQUIT)"); return (1); } if (set_sig_handler(SIGINT, (sig_handler_t *)daemon_quit) != 0) { debug_print(2, "could not set signal handler(SIGINT)"); return (1); } if (set_sig_handler(SIGCHLD, SIG_IGN) != 0) { debug_print(2, "could not set signal handler(SIGCHLD)"); return (1); } return (0); } static void daemon_quit(int signo) { int status = 0; id_t pgid; debug_print(1, "daemon quit [signal#:%d].", signo); acpihpd_fini(); (void) set_sig_handler(SIGTERM, SIG_IGN); pgid = getpgrp(); (void) kill(-pgid, SIGTERM); (void) close(s_pid_fd); (void) unlink(ACPIHPD_PID_FILE); if (signo < 0) { status = signo; } _exit(status); } static int set_sig_handler(int sig, sig_handler_t *handler) { struct sigaction act; act.sa_handler = handler; act.sa_flags = 0; if (sig == SIGCHLD && handler == SIG_IGN) { act.sa_flags |= SA_NOCLDWAIT; } (void) sigemptyset(&act.sa_mask); if (sigaction(sig, &act, NULL) < 0) { return (1); } return (0); } static int acpihpd_init(void) { const char *subclass = ESC_DR_REQ; debug_print(2, "acpihpd_init"); if ((s_acpihpd_hdl = sysevent_bind_handle(acpihpd_event)) == NULL) { debug_print(2, "could not bind to sysevent."); return (-1); } if (sysevent_subscribe_event(s_acpihpd_hdl, EC_DR, &subclass, 1) != 0) { debug_print(2, "could not subscribe an event."); sysevent_unbind_handle(s_acpihpd_hdl); s_acpihpd_hdl = NULL; return (-1); } return (0); } static void acpihpd_fini(void) { debug_print(2, "acpihpd_fini"); if (s_acpihpd_hdl != NULL) { sysevent_unsubscribe_event(s_acpihpd_hdl, EC_DR); sysevent_unbind_handle(s_acpihpd_hdl); } } static void acpihpd_event(sysevent_t *ev) { debug_print(2, "*** got an event ***"); /* Inform cfgadm of the hot-plug event. */ notify_hotplug(ev); } void debug_print(int level, const char *fmt, ...) { va_list ap; int pri, pr_out = 0; if (level <= g_debuglevel) { switch (level) { case 0: pri = LOG_ERR; pr_out = 1; break; case 1: pri = LOG_NOTICE; pr_out = 1; break; case 2: pri = LOG_DEBUG; pr_out = 1; break; } if (pr_out) { va_start(ap, fmt); vsyslog(pri, fmt, ap); va_end(ap); } } } # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2025 Hammerhead Project # include ../Makefile.com include $(SRC)/cmd/Makefile.cmd.64 include ../Makefile.targ install: all $(USR_PSM_LIB_DIR)/$(LIBS) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Intel Corporation. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PMCONFIG_PATH "/usr/sbin/pmconfig" #define CFGADM_CMD_ASSIGN "assign" #define CFGADM_CMD_POWERON "poweron" #define CFGADM_CMD_PASSTHRU "passthru" #define STATUS_INPROGRESS 0 #define STATUS_SUCCESS 1 #define STATUS_FAILURE 2 #define STATUS_NOOP 3 static char *s_status_array[] = { ACPIDEV_CMD_OST_INPROGRESS, ACPIDEV_CMD_OST_SUCCESS, ACPIDEV_CMD_OST_FAILURE, ACPIDEV_CMD_OST_NOOP }; extern void debug_print(int, const char *, ...); /*ARGSUSED*/ static int confirm_no(void *appdata_ptr, const char *message) { return (0); } /*ARGSUSED*/ static int message_output(void *appdata_ptr, const char *message) { debug_print(2, "cfgadm message: %s", message); return (CFGA_OK); } static char * plat_opt_str_alloc(int cmd, char *acpi_event_type, int status) { char *opt; size_t len; if (cmd == SBD_CMD_PASSTHRU) { len = strlen(s_status_array[status]) + strlen(ACPIDEV_EVENT_TYPE_ATTR_NAME) + strlen(acpi_event_type) + 10; if ((opt = malloc(len)) != NULL) { (void) snprintf(opt, len, "%s %s=%s", s_status_array[status], ACPIDEV_EVENT_TYPE_ATTR_NAME, acpi_event_type); debug_print(2, "plat_opt_str_alloc = '%s'", opt); } } else { len = strlen("platform=''") + strlen(s_status_array[status]) + strlen(ACPIDEV_EVENT_TYPE_ATTR_NAME) + strlen(acpi_event_type) + 10; if ((opt = malloc(len)) != NULL) { (void) snprintf(opt, len, "platform='%s %s=%s'", s_status_array[status], ACPIDEV_EVENT_TYPE_ATTR_NAME, acpi_event_type); debug_print(2, "plat_opt_str_alloc = '%s'", opt); } } return (opt); } static int cfgadm_cmd_wrapper(int cmd, int apid_num, char **apids, char *acpi_event_type, int status, struct cfga_confirm *confirm, struct cfga_msg *message) { cfga_err_t ret; char *plat_opts; char *estrp = NULL; assert(apid_num == 1); assert(apids != NULL); plat_opts = plat_opt_str_alloc(cmd, acpi_event_type, status); if (plat_opts == NULL) { debug_print(0, "failed to generate platform option string for cfgadm"); return (-1); } switch (cmd) { case SBD_CMD_CONNECT: ret = config_change_state(CFGA_CMD_CONNECT, apid_num, apids, plat_opts, confirm, message, &estrp, 0); if (ret != CFGA_OK) { debug_print(0, "cfgadm('connect', '%s') failed, " "ret = %d, errstr = '%s'", apids[0], ret, estrp); } break; case SBD_CMD_CONFIGURE: ret = config_change_state(CFGA_CMD_CONFIGURE, apid_num, apids, plat_opts, confirm, message, &estrp, 0); if (ret != CFGA_OK) { debug_print(0, "cfgadm('configure', '%s') failed, " "ret = %d, errstr = '%s'", apids[0], ret, estrp); } break; case SBD_CMD_ASSIGN: ret = config_private_func(CFGADM_CMD_ASSIGN, apid_num, apids, plat_opts, confirm, message, &estrp, 0); if (ret != CFGA_OK) { debug_print(0, "cfgadm('assign', '%s') failed, " "ret = %d, errstr = '%s'", apids[0], ret, estrp); } break; case SBD_CMD_POWERON: ret = config_private_func(CFGADM_CMD_POWERON, apid_num, apids, plat_opts, confirm, message, &estrp, 0); if (ret != CFGA_OK) { debug_print(0, "cfgadm('poweron', '%s') failed, " "ret = %d, errstr = '%s'", apids[0], ret, estrp); } break; case SBD_CMD_PASSTHRU: ret = config_private_func(CFGADM_CMD_PASSTHRU, apid_num, apids, plat_opts, confirm, message, &estrp, 0); if (ret != CFGA_OK) { debug_print(0, "cfgadm('passthru', '%s') failed, " "ret = %d, errstr = '%s'", apids[0], ret, estrp); } break; default: debug_print(2, "unknown command (%d) to cfgadm_cmd_wrapper()"); ret = CFGA_ERROR; break; } if (plat_opts != NULL) free(plat_opts); return (ret == CFGA_OK ? 0 : -1); } static int event_process(char *ap_id, char *req, char *acpi_event_type) { char *apids[1]; struct cfga_msg message; struct cfga_confirm confirm; if (strcmp(req, DR_REQ_INCOMING_RES) != 0) { debug_print(2, "Event is not supported (ap_id = %s, req = %s)", ap_id, req); return (-1); } apids[0] = ap_id; (void) memset(&confirm, 0, sizeof (confirm)); confirm.confirm = confirm_no; (void) memset(&message, 0, sizeof (message)); message.message_routine = message_output; if (cfgadm_cmd_wrapper(SBD_CMD_ASSIGN, 1, apids, acpi_event_type, STATUS_NOOP, &confirm, &message) != 0) { goto L_ERR; } syslog(LOG_NOTICE, "board '%s' has been assigned successfully", ap_id); (void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids, acpi_event_type, STATUS_INPROGRESS, &confirm, &message); if (cfgadm_cmd_wrapper(SBD_CMD_POWERON, 1, apids, acpi_event_type, STATUS_NOOP, &confirm, &message) != 0) { goto L_ERR_SIG; } syslog(LOG_NOTICE, "board '%s' has been powered on successfully", ap_id); (void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids, acpi_event_type, STATUS_INPROGRESS, &confirm, &message); if (cfgadm_cmd_wrapper(SBD_CMD_CONNECT, 1, apids, acpi_event_type, STATUS_INPROGRESS, &confirm, &message) != 0) { goto L_ERR_SIG; } syslog(LOG_NOTICE, "board '%s' has been connected successfully", ap_id); (void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids, acpi_event_type, STATUS_INPROGRESS, &confirm, &message); if (cfgadm_cmd_wrapper(SBD_CMD_CONFIGURE, 1, apids, acpi_event_type, STATUS_INPROGRESS, &confirm, &message) != 0) { goto L_ERR_SIG; } syslog(LOG_NOTICE, "board '%s' has been configured successfully", ap_id); (void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids, acpi_event_type, STATUS_SUCCESS, &confirm, &message); (void) system(PMCONFIG_PATH); syslog(LOG_NOTICE, "board '%s' has been added into system successfully", ap_id); return (0); L_ERR_SIG: (void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids, acpi_event_type, STATUS_FAILURE, &confirm, &message); L_ERR: syslog(LOG_ERR, "failed to add board '%s' into system", ap_id); return (-1); } void notify_hotplug(sysevent_t *ev) { char *vendor = NULL; nvlist_t *attr_list = NULL; char *class, *subclass; char *ap_id, *req, *acpi_event_type; vendor = sysevent_get_vendor_name(ev); debug_print(2, "message_vendor = '%s'", vendor ? vendor : "unknown"); if (vendor == NULL || strcmp(vendor, SUNW_VENDOR) != 0) { debug_print(2, "vendor id of message is not '%s'", SUNW_VENDOR); goto L_EXIT; } class = sysevent_get_class_name(ev); debug_print(2, "message_class = '%s'", class ? class : "unknown"); if (class == NULL || strcmp(class, EC_DR) != 0) { debug_print(2, "class of message is not '%s'", EC_DR); goto L_EXIT; } subclass = sysevent_get_subclass_name(ev); debug_print(2, "message_subclass = '%s'", subclass ? subclass : "unknown"); if (subclass == NULL || strcmp(subclass, ESC_DR_REQ) != 0) { debug_print(2, "subclass of message is not '%s'", ESC_DR_REQ); goto L_EXIT; } if (sysevent_get_attr_list(ev, &attr_list) != 0) { debug_print(2, "can't retrieve attribute list from DR message"); goto L_EXIT; } if (nvlist_lookup_string(attr_list, DR_AP_ID, &ap_id) != 0) { debug_print(2, "can't retrieve '%s' property from attribute list", DR_AP_ID); goto L_EXIT; } debug_print(2, "%s = '%s'", DR_AP_ID, ap_id ? ap_id : ""); if ((ap_id == NULL) || (strlen(ap_id) == 0)) { debug_print(2, "'%s' property in message is NULL", DR_AP_ID); goto L_EXIT; } if (nvlist_lookup_string(attr_list, DR_REQ_TYPE, &req) != 0) { debug_print(2, "can't retrieve '%s' property from attribute list", DR_REQ_TYPE); goto L_EXIT; } debug_print(2, "%s = '%s'", DR_REQ_TYPE, req ? req : ""); if ((req == NULL) || (strlen(req) == 0)) { debug_print(2, "'%s' property in message is NULL", DR_REQ_TYPE); goto L_EXIT; } if (nvlist_lookup_string(attr_list, ACPIDEV_EVENT_TYPE_ATTR_NAME, &acpi_event_type) != 0) { debug_print(2, "can't retrieve '%s' property from attribute list", ACPIDEV_EVENT_TYPE_ATTR_NAME); goto L_EXIT; } debug_print(2, "%s = '%s'", ACPIDEV_EVENT_TYPE_ATTR_NAME, acpi_event_type ? acpi_event_type : ""); if ((acpi_event_type == NULL) || (strlen(acpi_event_type) == 0)) { debug_print(2, "'%s' property in message is NULL", ACPIDEV_EVENT_TYPE_ATTR_NAME); goto L_EXIT; } (void) event_process(ap_id, req, acpi_event_type); L_EXIT: if (vendor != NULL) { free(vendor); } if (attr_list != NULL) { nvlist_free(attr_list); } /* No need to free class & subclass. */ } #!/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2010, Intel Corporation. # All rights reserved. # . /lib/svc/share/smf_include.sh PLATFORM="i86pc" ACPIHPD=/usr/platform/${PLATFORM}/lib/acpihpd /sbin/prtconf -D /devices/fw/acpidr@0 > /dev/null 2>&1 if [ $? -ne 0 ]; then svcadm disable -t $SMF_FMRI sleep 5& exit $SMF_EXIT_OK fi $ACPIHPD && exit $SMF_EXIT_OK || exit $SMF_EXIT_ERR_FATAL