summaryrefslogtreecommitdiff
path: root/usr/src/cmd/power
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/power')
-rw-r--r--usr/src/cmd/power/Makefile22
-rw-r--r--usr/src/cmd/power/conf.c25
-rw-r--r--usr/src/cmd/power/handlers.c311
-rw-r--r--usr/src/cmd/power/parse.c54
-rw-r--r--usr/src/cmd/power/pmconfig.h9
-rw-r--r--usr/src/cmd/power/power.conf.i38635
-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.c172
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: ";