diff options
Diffstat (limited to 'usr/src/cmd/power')
-rw-r--r-- | usr/src/cmd/power/Makefile | 22 | ||||
-rw-r--r-- | usr/src/cmd/power/conf.c | 25 | ||||
-rw-r--r-- | usr/src/cmd/power/handlers.c | 311 | ||||
-rw-r--r-- | usr/src/cmd/power/parse.c | 54 | ||||
-rw-r--r-- | usr/src/cmd/power/pmconfig.h | 9 | ||||
-rw-r--r-- | usr/src/cmd/power/power.conf.i386 | 35 | ||||
-rw-r--r-- | usr/src/cmd/power/power.conf.sparc (renamed from usr/src/cmd/power/power.conf) | 9 | ||||
-rw-r--r-- | usr/src/cmd/power/powerd.c | 172 |
8 files changed, 569 insertions, 68 deletions
diff --git a/usr/src/cmd/power/Makefile b/usr/src/cmd/power/Makefile index 9dd5337471..6fc647efc5 100644 --- a/usr/src/cmd/power/Makefile +++ b/usr/src/cmd/power/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -38,7 +38,8 @@ OBJS = $(SRCS:%.c=%.o) SCRIPTS = sysidpm.sh SYSIDPM = sysidpm PROG = $(DAEMON) $(PMCFG) $(SYSIDPM) -ETCFILES = power.conf +POWERCONF= power.conf +ETCFILES = $(POWERCONF) POWERPERM = power DEFAULTFILES = power.dfl @@ -58,13 +59,14 @@ POFILES= $(PMCFG_SRCS:%.c=%.po) # SCCS control here. OPOFILES= sysidpm.po -# -# we only need libdevinfo on sparc +# pmconfig only needs libdevinfo on sparc sparc_LDEVINFO= -ldevinfo i386_LDEVINFO= -DAEMON_LDLIBS = $(LDLIBS.cmd) -lkstat $($(MACH)_LDEVINFO) -PMCFG_LDLIBS = $(LDLIBS.cmd) $($(MACH)_LDEVINFO) +LDEVINFO= -ldevinfo + +DAEMON_LDLIBS = $(LDLIBS.cmd) -lkstat $(LDEVINFO) +PMCFG_LDLIBS = $(LDLIBS.cmd) -lcmd -lsmbios -lkstat $($(MACH)_LDEVINFO) OWNER= root ROOTUSRSBINPMCFG= $(PMCFG:%=$(ROOTUSRSBIN)/%) @@ -98,6 +100,8 @@ all: $(PROG) $(POWERPERM).dfl $(ETCFILES) $(SCRIPTS) install clean: +$(POWERCONF): $(POWERCONF).$(MACH) + $(DAEMON_OBJS): $(DAEMON_SRCS) $(CC) $(CFLAGS) -D_REENTRANT $(CPPFLAGS) -o $@ -c $< $(PROCESS_COMMENT) $@ @@ -134,7 +138,7 @@ $(POFILE): $(POFILES) $(OPOFILES) check: $(CHKMANIFEST) clean: - $(RM) $(OBJS) $(SYSIDPM) + $(RM) $(OBJS) $(SYSIDPM) $(POWERCONF) $(RM) $(POFILE) $(POFILES) lint := LINTFLAGS=-auxn @@ -145,4 +149,8 @@ lint: cstyle: $(CSTYLE) $(SRCS) +%: %.$(MACH) + $(RM) $@ + cat $< > $@ + include ../Makefile.targ diff --git a/usr/src/cmd/power/conf.c b/usr/src/cmd/power/conf.c index 5bea3f08c8..d84e3cd014 100644 --- a/usr/src/cmd/power/conf.c +++ b/usr/src/cmd/power/conf.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -83,6 +82,13 @@ static int fflag, rflag; int pm_fd; uid_t ruid; int def_src; +/* + * Until we get more graphics driver support, we only enable autopm, + * S3 support and autoS3 by default on X86 systems that are on our whitelist. + */ +int whitelist_only = 1; + +int verify = 0; static void @@ -302,7 +308,10 @@ restart_powerd(void) (void) setreuid(0, 0); (void) setregid(0, 0); (void) setgroups(0, NULL); - (void) execle(powerd, powerd, NULL, NULL); + if (debug) + (void) execle(powerd, powerd, "-d", NULL, NULL); + else + (void) execle(powerd, powerd, NULL, NULL); exit(1); } else { do { @@ -503,6 +512,12 @@ main(int cnt, char **vec) case 'r': rflag = 1; break; + case 'W': + whitelist_only = 0; + break; + case 'v': + verify = 1; + break; default: usage(); break; diff --git a/usr/src/cmd/power/handlers.c b/usr/src/cmd/power/handlers.c index 44df1f5c30..0754af4d6d 100644 --- a/usr/src/cmd/power/handlers.c +++ b/usr/src/cmd/power/handlers.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,6 +32,9 @@ #include <sys/mnttab.h> #include <syslog.h> #include <stdlib.h> +#include <sys/pm.h> +#include <kstat.h> +#include <sys/smbios.h> #define STRCPYLIM(dst, src, str) strcpy_limit(dst, src, sizeof (dst), str) @@ -44,6 +47,7 @@ static char bad_thresh_fmt[] = "bad threshold(s)\n"; static char stat_fmt[] = "cannot stat \"%s\", %s\n"; static char always_on[] = "always-on"; +#define PM_DEFAULT_ALGORITHM -1 /* * When lines in a config file (usually "/etc/power.conf") start with * a recognized keyword, a "handler" routine is called for specific @@ -54,6 +58,59 @@ static char always_on[] = "always-on"; */ +static char pm_cmd_string[32]; + +static char * +pm_map(int cmd) +{ + pm_req_t req; + + req.value = cmd; + req.data = (void *)pm_cmd_string; + req.datasize = sizeof (pm_cmd_string); + + if (ioctl(pm_fd, PM_GET_CMD_NAME, &req) < 0) { + perror("PM cmd name lookup:"); + return ("??"); + } + return (pm_cmd_string); +} + +static int +isonlist(char *listname, const char *man, const char *prod) +{ + pm_searchargs_t sl; + int ret; + + sl.pms_listname = listname; + sl.pms_manufacturer = (char *)man; + sl.pms_product = (char *)prod; + ret = ioctl(pm_fd, PM_SEARCH_LIST, &sl); + mesg(MDEBUG, "PM_SEARCH_LIST %s for %s,%s returns %d\n", + listname, man, prod, ret); + return (ret == 0); +} + +static int +do_ioctl(int ioctl_cmd, char *keyword, char *behavior, int suppress) +{ + mesg(MDEBUG, "doing ioctl %s for %s ", pm_map(ioctl_cmd), keyword); + if (ioctl(pm_fd, ioctl_cmd, NULL) == -1) { + int suppressed = suppress == -1 || suppress == errno; + mesg(MDEBUG, "%s failed, %s (%ssuppressed)\n", behavior, + strerror(errno), (suppressed ? "" : "not ")); + if (!suppressed) { + mesg(MERR, "%s %s failed, %s\n", keyword, behavior, + strerror(errno)); + return (NOUP); + } else { + return (OKUP); + } + } + mesg(MDEBUG, "succeeded\n"); + return (OKUP); +} + /* * Check for valid cpupm behavior and communicate it to the kernel. */ @@ -91,6 +148,231 @@ cpupm(void) /* + * Two decisions are identical except for the list names and ioctl commands + * inputs: whitelist, blacklist, yes, no + * if (! ("S3" kstat exists)) + * return (no) + * if (SystemInformation.Manufacturer == "Sun Microsystems" && + * (Pref_PM_Profile == Workstation || Pref_PM_Profile == Desktop)) { + * if (platform on blacklist) + * return (no) + * return (yes) + * } else { + * if (platform on whitelist) + * return (yes) + * return (no) + * } + */ + +int +S3_helper(char *whitelist, char *blacklist, int yes, int no, char *keyword, + char *behavior, int *didyes, int suppress) +{ + int oflags = SMB_O_NOCKSUM | SMB_O_NOVERS; + smbios_hdl_t *shp; + smbios_system_t sys; + id_t id; + int ret; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *dp; + smbios_info_t info; + int preferred_pm_profile = 0; + char yesstr[32], nostr[32]; /* DEBUG */ + + *didyes = 0; + + strncpy(yesstr, pm_map(yes), sizeof (yesstr)); + strncpy(nostr, pm_map(no), sizeof (nostr)); + mesg(MDEBUG, "S3_helper(%s, %s, %s, %s, %s, %s)\n", whitelist, + blacklist, yesstr, nostr, keyword, behavior); + if ((kc = kstat_open()) == NULL) { + mesg(MDEBUG, "kstat_open failed\n"); + return (OKUP); + } + ksp = kstat_lookup(kc, "acpi", -1, "acpi"); + if (ksp == NULL) { + mesg(MDEBUG, "kstat_lookup 'acpi', -1, 'acpi' failed\n"); + kstat_close(kc); + return (OKUP); + } + (void) kstat_read(kc, ksp, NULL); + dp = kstat_data_lookup(ksp, "S3"); + if (dp == NULL || dp->value.l == 0) { + mesg(MDEBUG, "kstat_data_lookup 'S3' fails\n"); + if (dp != NULL) + mesg(MDEBUG, "value.l %lx\n", dp->value.l); + kstat_close(kc); + return (do_ioctl(no, keyword, behavior, suppress)); + } + mesg(MDEBUG, "kstat indicates S3 support (%lx)\n", dp->value.l); + + if (!whitelist_only) { + /* + * We still have an ACPI ksp, search it again for + * 'preferred_pm_profile' (needs to be valid if we don't + * aren't only using a whitelist). + */ + dp = kstat_data_lookup(ksp, "preferred_pm_profile"); + if (dp == NULL) { + mesg(MDEBUG, "kstat_data_lookup 'ppmp fails\n"); + kstat_close(kc); + return (do_ioctl(no, keyword, behavior, suppress)); + } + mesg(MDEBUG, "kstat indicates preffered_pm_profile is %lx\n", + dp->value.l); + preferred_pm_profile = dp->value.l; + } + kstat_close(kc); + + if ((shp = smbios_open(NULL, + SMB_VERSION, oflags, &ret)) == NULL) { + /* we promised not to complain */ + /* we bail leaving it to the kernel default */ + mesg(MDEBUG, "smbios_open failed %d\n", errno); + return (OKUP); + } + if ((id = smbios_info_system(shp, &sys)) == SMB_ERR) { + mesg(MDEBUG, "smbios_info_system failed %d\n", errno); + smbios_close(shp); + return (OKUP); + } + if (smbios_info_common(shp, id, &info) == SMB_ERR) { + mesg(MDEBUG, "smbios_info_common failed %d\n", errno); + smbios_close(shp); + return (OKUP); + } + mesg(MDEBUG, "Manufacturer: %s\n", info.smbi_manufacturer); + mesg(MDEBUG, "Product: %s\n", info.smbi_product); + smbios_close(shp); + + if (!whitelist_only) { +#define PPP_DESKTOP 1 +#define PPP_WORKSTATION 3 + if (strcmp(info.smbi_manufacturer, "Sun Microsystems") == 0 && + (preferred_pm_profile == PPP_DESKTOP || + preferred_pm_profile == PPP_WORKSTATION)) { + if (isonlist(blacklist, + info.smbi_manufacturer, info.smbi_product)) { + return (do_ioctl(no, keyword, behavior, + suppress)); + } else { + ret = do_ioctl(yes, keyword, behavior, + suppress); + *didyes = (ret == OKUP); + return (ret); + } + } + } + if (isonlist(whitelist, + info.smbi_manufacturer, info.smbi_product)) { + ret = do_ioctl(yes, keyword, behavior, suppress); + *didyes = (ret == OKUP); + return (ret); + } else { + return (do_ioctl(no, keyword, behavior, suppress)); + } +} + +int +S3sup(void) /* S3-support keyword handler */ +{ + struct btoc { + char *behavior; + int cmd; + }; + static struct btoc blist[] = { + "default", PM_DEFAULT_ALGORITHM, + "enable", PM_ENABLE_S3, + "disable", PM_DISABLE_S3, + NULL, 0 + }; + struct btoc *bp; + char *behavior; + int dontcare; + + for (behavior = LINEARG(1), bp = blist; bp->cmd; bp++) { + if (strcmp(behavior, bp->behavior) == 0) + break; + } + if (bp->cmd == 0) { + mesg(MERR, "invalid S3-support behavior \"%s\"\n", behavior); + return (NOUP); + } + + + switch (bp->cmd) { + + case PM_ENABLE_S3: + case PM_DISABLE_S3: + return (do_ioctl(bp->cmd, "S3-support", behavior, EBUSY)); + + case PM_DEFAULT_ALGORITHM: + /* + * we suppress errors in the "default" case because we + * already did an invisible default call, so we know we'll + * get EBUSY + */ + return (S3_helper("S3-support-enable", "S3-support-disable", + PM_ENABLE_S3, PM_DISABLE_S3, "S3-support", behavior, + &dontcare, EBUSY)); + + default: + mesg(MERR, "S3-support %s failed, %s\n", behavior, + strerror(errno)); + return (NOUP); + } +} + +/* + * Check for valid autoS3 behavior and save after ioctl success. + */ +int +autoS3(void) +{ + struct btoc { + char *behavior; + int cmd; + }; + static struct btoc blist[] = { + "default", PM_DEFAULT_ALGORITHM, + "disable", PM_STOP_AUTOS3, + "enable", PM_START_AUTOS3, + NULL, 0 + }; + struct btoc *bp; + char *behavior; + int dontcare; + + for (behavior = LINEARG(1), bp = blist; bp->cmd; bp++) { + if (strcmp(behavior, bp->behavior) == 0) + break; + } + if (bp->cmd == 0) { + mesg(MERR, "invalid autoS3 behavior \"%s\"\n", behavior); + return (NOUP); + } + + switch (bp->cmd) { + default: + mesg(MERR, "autoS3 %s failed, %s\n", + behavior, strerror(errno)); + mesg(MDEBUG, "unknown command\n", bp->cmd); + return (OKUP); + + case PM_STOP_AUTOS3: + case PM_START_AUTOS3: + return (do_ioctl(bp->cmd, "autoS3", behavior, EBUSY)); + + case PM_DEFAULT_ALGORITHM: + return (S3_helper("S3-autoenable", "S3-autodisable", + PM_START_AUTOS3, PM_STOP_AUTOS3, "autoS3", behavior, + &dontcare, EBUSY)); + } +} + + +/* * Check for valid autopm behavior and save after ioctl success. */ int @@ -101,7 +383,7 @@ autopm(void) int cmd, Errno, isdef; }; static struct btoc blist[] = { - "default", PM_START_PM, EBUSY, 1, + "default", PM_START_PM, -1, 1, "disable", PM_STOP_PM, EINVAL, 0, "enable", PM_START_PM, EBUSY, 0, NULL, 0, 0, 0, @@ -121,6 +403,7 @@ autopm(void) /* * for "default" behavior, do not enable autopm if not ESTAR_V3 */ +#if defined(__sparc) if (!bp->isdef || (estar_vers == ESTAR_V3)) { if (ioctl(pm_fd, bp->cmd, NULL) == -1 && errno != bp->Errno) { mesg(MERR, "autopm %s failed, %s\n", @@ -130,6 +413,30 @@ autopm(void) } (void) strcpy(new_cc.apm_behavior, behavior); return (OKUP); +#endif +#if defined(__x86) + if (!bp->isdef) { + if (ioctl(pm_fd, bp->cmd, NULL) == -1 && errno != bp->Errno) { + mesg(MERR, "autopm %s failed, %s\n", + behavior, strerror(errno)); + return (NOUP); + } + mesg(MDEBUG, "autopm %s succeeded\n", behavior); + + return (OKUP); + } else { + int didenable; + int ret = S3_helper("autopm-enable", "autopm-disable", + PM_START_PM, PM_STOP_PM, "autopm", behavior, &didenable, + bp->Errno); + if (didenable) { + /* tell powerd to attach all devices */ + new_cc.is_autopm_default = 1; + (void) strcpy(new_cc.apm_behavior, behavior); + } + return (ret); + } +#endif } diff --git a/usr/src/cmd/power/parse.c b/usr/src/cmd/power/parse.c index 650e2154cb..e7adff4d18 100644 --- a/usr/src/cmd/power/parse.c +++ b/usr/src/cmd/power/parse.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,6 +53,8 @@ prmup_t pm_status = { 0, OKUP, "pm" }; * must appear before a substring like "dev". */ static cinfo_t conftab[] = { + "S3-support", S3sup, &pm_status, NULL, 2, 0, 1, + "autoS3", autoS3, &pm_status, NULL, 2, 0, 1, "autopm", autopm, &pm_status, NULL, 2, 0, 1, "autoshutdown", autosd, &cpr_status, as_cmt, 5, 0, 1, "cpu-threshold", cputhr, &pm_status, NULL, 2, 0, 1, @@ -373,6 +375,14 @@ parse_conf_file(char *name, vact_t action) cinfo_t *cip; int linc, cnt; size_t llen; + int dontcare; + + /* + * Do the "implied default" for autoS3 + */ + (void) S3_helper("S3-support-enable", "S3-support-disable", + PM_ENABLE_S3, PM_DISABLE_S3, "S3-support", "default", + &dontcare, -1); file_buf = get_conf_data(name); mesg(MDEBUG, "\nnow parsing \"%s\"...\n", name); @@ -446,4 +456,46 @@ parse_conf_file(char *name, vact_t action) lineno = 0; free(file_buf); + + if (verify) { + int ret = ioctl(pm_fd, PM_GET_PM_STATE, NULL); + if (ret < 0) { + mesg(MDEBUG, "Cannot get PM state: %s\n", + strerror(errno)); + } + switch (ret) { + case PM_SYSTEM_PM_ENABLED: + mesg(MDEBUG, "Autopm Enabled\n"); + break; + case PM_SYSTEM_PM_DISABLED: + mesg(MDEBUG, "Autopm Disabled\n"); + break; + } + ret = ioctl(pm_fd, PM_GET_S3_SUPPORT_STATE, NULL); + if (ret < 0) { + mesg(MDEBUG, "Cannot get PM state: %s\n", + strerror(errno)); + } + switch (ret) { + case PM_S3_SUPPORT_ENABLED: + mesg(MDEBUG, "S3 support Enabled\n"); + break; + case PM_S3_SUPPORT_DISABLED: + mesg(MDEBUG, "S3 support Disabled\n"); + break; + } + ret = ioctl(pm_fd, PM_GET_AUTOS3_STATE, NULL); + if (ret < 0) { + mesg(MDEBUG, "Cannot get PM state: %s\n", + strerror(errno)); + } + switch (ret) { + case PM_AUTOS3_ENABLED: + mesg(MDEBUG, "AutoS3 Enabled\n"); + break; + case PM_AUTOS3_DISABLED: + mesg(MDEBUG, "AutoS3 Disabled\n"); + break; + } + } } diff --git a/usr/src/cmd/power/pmconfig.h b/usr/src/cmd/power/pmconfig.h index e48c9a0289..33f26b63df 100644 --- a/usr/src/cmd/power/pmconfig.h +++ b/usr/src/cmd/power/pmconfig.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -92,6 +92,9 @@ typedef struct cinfo cinfo_t; typedef void (*vact_t)(char *, size_t, cinfo_t *); +/* Suspend/Resume flags */ +extern int whitelist_only; +extern int verify; /* * "conf.c" @@ -105,7 +108,6 @@ extern uid_t ruid; extern int def_src; extern void mesg(int, char *, ...); - /* * "parse.c" */ @@ -118,6 +120,9 @@ extern void parse_conf_file(char *, vact_t); /* * handlers.c */ +extern int S3_helper(char *, char *, int, int, char *, char *, int *, int); +extern int S3sup(void); +extern int autoS3(void); extern int autopm(void); extern int autosd(void); extern int cpupm(void); diff --git a/usr/src/cmd/power/power.conf.i386 b/usr/src/cmd/power/power.conf.i386 new file mode 100644 index 0000000000..0c1d37132b --- /dev/null +++ b/usr/src/cmd/power/power.conf.i386 @@ -0,0 +1,35 @@ +# +# 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 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Power Management Configuration File +# +# This entry keeps removable media from being powered down unless the +# console framebuffer and monitor are powered down +# (See removable-media(9P)) + +device-dependency-property removable-media /dev/fb + +autopm default +autoS3 default diff --git a/usr/src/cmd/power/power.conf b/usr/src/cmd/power/power.conf.sparc index 47068b41f9..17064e630f 100644 --- a/usr/src/cmd/power/power.conf +++ b/usr/src/cmd/power/power.conf.sparc @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -19,8 +18,8 @@ # # CDDL HEADER END # -# Copyright (c) 1996 - 2001 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" # diff --git a/usr/src/cmd/power/powerd.c b/usr/src/cmd/power/powerd.c index 19e137ce02..a559041d0a 100644 --- a/usr/src/cmd/power/powerd.c +++ b/usr/src/cmd/power/powerd.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -53,6 +53,7 @@ #include <sys/stropts.h> /* for INFTIM */ #include <sys/pbio.h> #include <sys/cpr.h> +#include <sys/srn.h> #include <stdarg.h> #include "powerd.h" @@ -73,6 +74,7 @@ extern int last_nfs_activity(hrtime_t *, int); #define TOD "/dev/tod" #define PROM "/dev/openprom" #define PB "/dev/power_button" +#define SRN "/dev/srn" #define LOGFILE "./powerd.log" #define PBM_THREAD 0 @@ -108,9 +110,7 @@ static int autoshutdown_en; static int do_idlecheck; static int got_sighup; static int estar_v2_prop; -#ifdef sparc static int estar_v3_prop; -#endif static int log_power_cycles_error = 0; static int log_system_board_date_error = 0; static int log_no_autoshutdown_warning = 0; @@ -126,6 +126,11 @@ static char *power_button_cmd[] = { "-h", "-d", ":0", NULL }; +static char *autoS3_cmd[] = { + "/usr/openwin/bin/sys-suspend", + "-n", "-d", ":0", NULL +}; + static char pidpath[] = PIDPATH; static char scratch[PATH_MAX]; static char *prog; @@ -148,11 +153,10 @@ static int open_pidfile(char *); static int write_pidfile(int, pid_t); static int read_cpr_config(void); static void system_activity_monitor(void); -#ifdef sparc +static void autos3_monitor(void); static void do_attach(void); static void *attach_devices(void *); -#endif - +static int powerd_debug; /* PRINTFLIKE1 */ static void @@ -205,8 +209,11 @@ main(int argc, char *argv[]) * Process options */ broadcast = 1; - while ((c = getopt(argc, argv, "n")) != EOF) { + while ((c = getopt(argc, argv, "nd")) != EOF) { switch (c) { + case 'd': + powerd_debug = 1; + break; case 'n': broadcast = 0; break; @@ -230,7 +237,7 @@ main(int argc, char *argv[]) */ if (mutex_init(&poweroff_mutex, USYNC_THREAD, NULL) != 0) { (void) fprintf(stderr, - "%s: Unable to initialize mutex lock\n", prog); + "%s: Unable to initialize mutex lock\n", prog); exit(EXIT_FAILURE); } @@ -296,6 +303,8 @@ main(int argc, char *argv[]) * thread to monitor the power button. */ if ((pb_fd = open(PB, O_RDONLY)) != -1) { + if (powerd_debug) + logerror("powerd starting power button monitor."); if (thr_create(NULL, NULL, (void *(*)(void *))power_button_monitor, NULL, THR_DAEMON, NULL) != 0) { @@ -303,14 +312,14 @@ main(int argc, char *argv[]) } } -#ifdef sparc do_attach(); -#endif /* * Create a new thread to monitor system activity and suspend * system if idle. */ + if (powerd_debug) + logerror("powerd starting system activity monitor."); if (thr_create(NULL, NULL, (void *(*)(void *))system_activity_monitor, NULL, THR_DAEMON, NULL) != 0) { @@ -318,6 +327,16 @@ main(int argc, char *argv[]) } /* + * Create a new thread to handle autos3 trigger + */ + if (powerd_debug) + logerror("powerd starting autos3 monitor."); + if (thr_create(NULL, NULL, + (void *(*)(void *))autos3_monitor, NULL, THR_DAEMON, NULL) != 0) { + logerror("Unable to create thread to monitor autos3 activity."); + } + + /* * Block until we receive an explicit terminate signal */ (void) sigsuspend(&sigmask); @@ -370,6 +389,68 @@ system_activity_monitor(void) } while (errno == EINTR); } +static void +autos3_monitor(void) +{ + struct pollfd poll_fd; + srn_event_info_t srn_event; /* contains suspend type */ + int fd, ret; + + fd = open(SRN, O_RDWR|O_EXCL|O_NDELAY); + if (fd == -1) { + logerror("Unable to open %s: %s", SRN, strerror(errno)); + thr_exit((void *) errno); + } + logerror("Able to open %s", SRN); + + /* + * Tell device we want the special sauce + */ + ret = ioctl(fd, SRN_IOC_AUTOSX, NULL); + if (ret == -1) { + logerror("Ioctl SRN_IOC_AUTOSX failed: %s", strerror(errno)); + close(fd); + thr_exit((void *) errno); + } + poll_fd.fd = fd; + /*CONSTCOND*/ + while (1) { + poll_fd.revents = 0; + poll_fd.events = POLLIN; + if (poll(&poll_fd, 1, -1) < 0) { + switch (errno) { + case EINTR: + case EAGAIN: + continue; + default: + logerror("Poll error: %s", strerror(errno)); + close(fd); + thr_exit((void *) errno); + } + } + + ret = ioctl(fd, SRN_IOC_NEXTEVENT, &srn_event); + if (ret == -1) { + logerror("ioctl error: %s", strerror(errno)); + close(fd); + thr_exit((void *) errno); + } + switch (srn_event.ae_type) { + case 3: /* S3 */ + if (powerd_debug) + logerror("ioctl returns type: %d", + srn_event.ae_type); + break; + default: + logerror("Unsupported target state %d", + srn_event.ae_type); + continue; + } + (void) poweroff("AutoS3", autoS3_cmd); + continue; + } +} + static int read_cpr_config(void) { @@ -482,7 +563,7 @@ work_handler(int sig) } else if (strcmp(asinfo.as_behavior, "default") == 0) { info->pd_autoshutdown = estar_v2_prop; } else if (strcmp(asinfo.as_behavior, "shutdown") == 0 || - strcmp(asinfo.as_behavior, "autowakeup") == 0) { + strcmp(asinfo.as_behavior, "autowakeup") == 0) { info->pd_autoshutdown = asinfo.is_cpr_capable; } else { logerror("autoshutdown behavior \"%s\" unrecognized.", @@ -500,14 +581,15 @@ work_handler(int sig) (strcmp(asinfo.as_behavior, "autowakeup") == 0) ? 1 : 0; } autoshutdown_en = (asinfo.as_idle >= 0 && info->pd_autoshutdown) - ? 1 : 0; + ? 1 : 0; #ifdef DEBUG (void) fprintf(stderr, "autoshutdown_en = %d, as_idle = %d, " - "pd_autoresume = %d\n", - autoshutdown_en, asinfo.as_idle, info->pd_autoresume); + "pd_autoresume = %d\n", + autoshutdown_en, asinfo.as_idle, info->pd_autoresume); + (void) fprintf(stderr, " pd_start_time=%d, pd_finish_time=%d\n", - info->pd_start_time, info->pd_finish_time); + info->pd_start_time, info->pd_finish_time); #endif got_sighup = 1; @@ -574,11 +656,10 @@ check_shutdown(time_t *now, hrtime_t *hr_now) start_calc = 1; time_since_last_resume = time(NULL) - last_resume; next_time = info->pd_idle_time * 60 - - MIN(least_idle, time_since_last_resume); + MIN(least_idle, time_since_last_resume); #ifdef DEBUG - fprintf(stderr, " check_shutdown: next_time=%d\n", - next_time); + fprintf(stderr, " check_shutdown: next_time=%d\n", next_time); #endif /* @@ -591,7 +672,7 @@ check_shutdown(time_t *now, hrtime_t *hr_now) start_calc = 1; time_since_last_resume = time(NULL) - last_resume; next_time = info->pd_idle_time * 60 - - MIN(least_idle, time_since_last_resume); + MIN(least_idle, time_since_last_resume); } /* @@ -602,8 +683,8 @@ check_shutdown(time_t *now, hrtime_t *hr_now) got_sighup = 0; idlecheck_time = run_idlecheck(); next_time = info->pd_idle_time * 60 - - MIN(idlecheck_time, MIN(least_idle, - time_since_last_resume)); + MIN(idlecheck_time, MIN(least_idle, + time_since_last_resume)); /* * If we have caught SIGTHAW or SIGHUP, need to * recalculate. @@ -613,10 +694,10 @@ check_shutdown(time_t *now, hrtime_t *hr_now) got_sighup = 0; idlecheck_time = run_idlecheck(); time_since_last_resume = time(NULL) - - last_resume; + last_resume; next_time = info->pd_idle_time * 60 - - MIN(idlecheck_time, MIN(least_idle, - time_since_last_resume)); + MIN(idlecheck_time, MIN(least_idle, + time_since_last_resume)); } } @@ -631,7 +712,7 @@ check_shutdown(time_t *now, hrtime_t *hr_now) tod_fd = open(TOD, O_RDWR); if (info->pd_autoresume && tod_fd != -1) { wakeup_time = (*now < f) ? f : - (f + DAYS_TO_SECS); + (f + DAYS_TO_SECS); /* * A software fix for hardware * bug 1217415. @@ -645,10 +726,9 @@ check_shutdown(time_t *now, hrtime_t *hr_now) return; } if (ioctl(tod_fd, TOD_SET_ALARM, - &wakeup_time) == -1) { - logerror("Unable to program " - "TOD alarm for " - "autowakeup."); + &wakeup_time) == -1) { + logerror("Unable to program TOD" + " alarm for autowakeup."); close(tod_fd); return; } @@ -659,7 +739,7 @@ check_shutdown(time_t *now, hrtime_t *hr_now) if (info->pd_autoresume && tod_fd != -1) { if (ioctl(tod_fd, TOD_CLEAR_ALARM, - NULL) == -1) + NULL) == -1) logerror("Unable to clear " "alarm in TOD device."); close(tod_fd); @@ -668,8 +748,8 @@ check_shutdown(time_t *now, hrtime_t *hr_now) (void) time(now); /* wait at least 5 mins */ shutdown_time = *now + - ((info->pd_idle_time * 60) > 300 ? - (info->pd_idle_time * 60) : 300); + ((info->pd_idle_time * 60) > 300 ? + (info->pd_idle_time * 60) : 300); } else { /* wait 5 mins */ shutdown_time = *now + 300; @@ -698,8 +778,8 @@ is_ok2shutdown(time_t *now) /* CONSTCOND */ while (1) { if ((prom_fd = open(PROM, O_RDWR)) == -1 && - (errno == EAGAIN)) - continue; + (errno == EAGAIN)) + continue; break; } @@ -760,15 +840,14 @@ is_ok2shutdown(time_t *now) * 7-year life span instead of (lifetime - date free_cycles ended). */ scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) * - (power_cycle_limit - free_cycles)); + (power_cycle_limit - free_cycles)); if (no_power_cycles) goto ckdone; #ifdef DEBUG (void) fprintf(stderr, "Actual power_cycles = %d\t" - "Scaled power_cycles = %d\n", - power_cycles, scaled_cycles); + "Scaled power_cycles = %d\n", power_cycles, scaled_cycles); #endif if (power_cycles > scaled_cycles) { if (log_no_autoshutdown_warning == 0) { @@ -807,13 +886,13 @@ check_idleness(time_t *now, hrtime_t *hr_now) #ifdef DEBUG (void) fprintf(stderr, "Idle ttychars for %d secs.\n", - info->pd_ttychars_idle); + info->pd_ttychars_idle); (void) fprintf(stderr, "Idle loadaverage for %d secs.\n", - info->pd_loadaverage_idle); + info->pd_loadaverage_idle); (void) fprintf(stderr, "Idle diskreads for %d secs.\n", - info->pd_diskreads_idle); + info->pd_diskreads_idle); (void) fprintf(stderr, "Idle nfsreqs for %d secs.\n", - info->pd_nfsreqs_idle); + info->pd_nfsreqs_idle); #endif checkidle_time = *now + IDLECHK_INTERVAL; @@ -848,7 +927,8 @@ run_idlecheck() /* * Reap any child process which has been left over. */ - while (waitpid((pid_t)-1, &status, WNOHANG) > 0); + while (waitpid((pid_t)-1, &status, WNOHANG) > 0) + ; /* * Execute the user's idlecheck script and set variable PM_IDLETIME. @@ -856,7 +936,7 @@ run_idlecheck() */ if ((child = fork1()) == 0) { (void) sprintf(pm_variable, "PM_IDLETIME=%d", - info->pd_idle_time); + info->pd_idle_time); (void) putenv(pm_variable); cp = strrchr(asinfo.idlecheck_path, '/'); if (cp == NULL) @@ -1136,7 +1216,6 @@ power_button_monitor(void *arg) } } -#ifdef sparc static void do_attach(void) { @@ -1151,6 +1230,8 @@ do_attach(void) estar_v3_prop = asinfo.is_autopm_default; if ((strcmp(asinfo.apm_behavior, "enable") == 0) || (estar_v3_prop && strcmp(asinfo.apm_behavior, "default") == 0)) { + if (powerd_debug) + logerror("powerd starting device attach thread."); if (thr_create(NULL, NULL, attach_devices, NULL, THR_DAEMON, NULL) != 0) { logerror("Unable to create thread to attach devices."); @@ -1179,7 +1260,6 @@ attach_devices(void *arg) return (NULL); } -#endif /* @@ -1199,7 +1279,7 @@ open_pidfile(char *me) const char *e3 = "%s: Cannot open /proc for pid %ld: "; const char *e4 = "%s: Cannot read /proc for pid %ld: "; const char *e5 = "%s: Another instance (pid %ld) is trying to exit" - "and may be hung. Please contact sysadmin.\n"; + "and may be hung. Please contact sysadmin.\n"; const char *e6 = "%s: Another daemon is running\n"; const char *e7 = "%s: Cannot create pid file: "; |