summaryrefslogtreecommitdiff
path: root/packages/sccd/files
diff options
context:
space:
mode:
authorAndrew Wilcox <andy@protium.com>2006-12-07 19:22:25 +0000
committerAndrew Wilcox <andy@protium.com>2006-12-07 19:22:25 +0000
commit21f0d4357067e495f29a752e529ee6f55a14f3d2 (patch)
treeb7f5c8b5c04ca88183af568e9fd8b4adafe50410 /packages/sccd/files
parentb76d8f80b7cb99176838281a15c4b8f8f60ae18d (diff)
sccd: StorCenter Control Daemon: leds and fan control server/client
Diffstat (limited to 'packages/sccd/files')
-rw-r--r--packages/sccd/files/.mtn2git_empty0
-rw-r--r--packages/sccd/files/Makefile52
-rw-r--r--packages/sccd/files/README220
-rw-r--r--packages/sccd/files/init-sccd38
-rw-r--r--packages/sccd/files/scc-disk.c167
-rw-r--r--packages/sccd/files/scc-utils.c376
-rw-r--r--packages/sccd/files/scc.1120
-rw-r--r--packages/sccd/files/scc.c412
-rw-r--r--packages/sccd/files/scc.h118
-rw-r--r--packages/sccd/files/sccd.c523
10 files changed, 2026 insertions, 0 deletions
diff --git a/packages/sccd/files/.mtn2git_empty b/packages/sccd/files/.mtn2git_empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/packages/sccd/files/.mtn2git_empty
diff --git a/packages/sccd/files/Makefile b/packages/sccd/files/Makefile
new file mode 100644
index 0000000000..650404643d
--- /dev/null
+++ b/packages/sccd/files/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (c) 2006
+# Protium Computing, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Protium Computing, Inc.
+# 4. The name of Protium Computing, Inc. may not be used to endorse or
+# promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+TARGETS=sccd scc
+
+all: $(TARGETS)
+
+sccd: scc-disk.o scc-utils.o sccd.o
+ $(CC) $(CFLAGS) -o sccd scc-utils.o scc-disk.o sccd.o
+
+scc: scc-utils.o scc.o
+ $(CC) $(CFLAGS) -o scc scc-utils.o scc.o
+
+install: $(TARGETS)
+ install -d $(DESTDIR)/sbin
+ install -m 755 sccd $(DESTDIR)/sbin/sccd
+ install -m 755 scc $(DESTDIR)/sbin/scc
+ install -d $(DESTDIR)/etc/init.d
+ install -m 755 init-sccd $(DESTDIR)/etc/init.d/sccd
+ install -d $(DESTDIR)/usr/share/man/man1
+ install -m 644 scc.1 $(DESTDIR)/usr/share/man/man1/scc.1
+
+clean:
+ rm -f $(TARGETS) *.o core
diff --git a/packages/sccd/files/README b/packages/sccd/files/README
new file mode 100644
index 0000000000..d2d1934dd4
--- /dev/null
+++ b/packages/sccd/files/README
@@ -0,0 +1,220 @@
+ Iomega G2 MC68HC908QY4 Support Notes
+ October 2006
+
+The Iomega G2 Version 3.x and 5.x boards have a secondary microcontroller
+aboard, a Freescale MC68HC908QY4. This microcontroller is connected to the
+board's LED, fan, digital thermometer, power switch, and main processor, the
+MPC8241. The connection to the main processor is through the 8241's second
+UART and possibly its reset lines.
+
+The microcontroller can perform the following functions:
+ o The LED can be set to off, blue, red, blue flash, red flash,
+ alternate (blue->red->blue) and some boards alternate3
+ (blue->blue->blue->red->red->red). The flash and alernate rates
+ can be be set. Alternate3 rate is fixed.
+ o Fan can be set to on or auto. Auto mode is a thermostat function
+ that turns the fan on and off based on two temprature settings:
+ Fan Temp High and Fan Temp Low.
+ o The system can be reset, causing a MPC8241 reset, or stopped,
+ causing a full power down.
+ o The microcontroller can detect if the soft power switch has been
+ activated. There appears to a 20s delay after the power switch
+ has been depressed before the microcontroller causes an actual
+ power off. This event can be detected by polling the
+ microcontroller.
+
+The running system communicates with microcontroller and ultimately controls
+the devices connected to it via the MPC8241's second UART. The connection
+settings are: 9600,8,n,1. The serial protocol is very simple, an alternating
+send and receive of data packets. Communication is done in 8 byte data packets
+and is initiated by the host processor. Once the host processor has sent 8
+bytes, the microcontroller responds with 8 bytes. The packet contains bytes
+that can affect the state of the power, led and fan. It also contains bits
+reflecting external soft power events. Both packets sent and received follow
+the same structure.
+
+The 8 bytes are decoded as follows:
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Power | LED | LED | Fan |
+ | State | State | Flash Rate | State |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Fan High Temp | Fan Low Temp | | |
+ | ON | OFF | ID | CheckSum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Hex Ascii Comments
+ --- ----- --------------------------------------------------
+Power State:
+ 0x62 b Running, nominal running state
+ 0x63 c Stop, power down immediately (ID == HOST) OR
+ Stop, the power switch has been activated, stop in 20s
+ (ID == CONTROLLERxx) OR
+ Stop, the host has advised Stop
+ (ID == CONTROLLERxx)
+ 0x64 d Advise Stop, the host is annoucing its intention
+ to stop (ID == HOST)
+ 0x65 e Restart, restart immediately (ID == HOST) OR
+ Restart, the host has advised Restart
+ (ID == CONTROLLERxx)
+ 0x66 f Advise Restart, the host is annoucing its intention
+ to restart (ID == HOST)
+ 0x67 g Reset, reset immediately (ID == HOST) OR
+ Reset, the host has advised Reset
+ (ID == CONTROLLERxx)
+ 0x68 h Advise Reset, the host is annoucing its intention
+ to reset (ID == HOST)
+
+Except for Running, the Power states are grouped in pairs: Advise [state] and
+[state], where state can be: Stop, Restart, or Reset. The Advise state lets
+the controller know that there is an intention to either stop, restart or
+reset the board. The controller responds by moving to that state and setting
+the LED to redflash, but it does not enact the power change. Instead it waits
+for the host to issue the actual state before performing the power commands.
+For example, assume the microcontroller is reporting the power state to be
+[Running, LED Blue]. After the host issues a Advise Stop, the microcontroller
+reports [Stop, LED Redflash] and then waits, indefinitely. The Host then
+issues a Stop, the microcontroller immediately turns the power off.
+
+There is nothing in the protocol that requires the Advise [state] packets. The
+Host can issue a Stop, Restart, or Reset directly from the Running state and
+the microcontroller will immediately enact the change.
+
+There is nothing in the protocol that forbids moving back to Running from the
+Stop, Restart or Reset states, i.e. undoing an Advise [state] packet.
+
+The exception to that rule is in the Stop state. The Stop state can be reached
+by either issuing a Advise Stop or from a softpower switch activation (someone
+hits the power switch). If the latter, then a request to move to any other
+state is ignored and the power will go off in approximately 20s.
+
+NOTE 1: There does not appear to be any difference in processing the Restart
+and Reset state changes. They both deliver a system restart.
+
+NOTE 2: Obvious absence of an 'a' state. Both the LED and Fan controls use 'a'
+as a state, but Power starts with 'b'. No evidence has shown 'a' to be a
+valid state.
+
+LED State:
+ 0x61 a Off
+ 0x62 b Blue
+ 0x63 c Red
+ 0x64 d Blue Flash
+ 0x65 e Red Flash
+ 0x66 f Alternate1 Blue/Red
+ 0x67 g Alternate3 3 Blue/3 Red (only on version 5.x boards)
+
+LED States are self explanatory with one exception. Although state 'g' or
+Alternate3 has been observed, it only seems to function on IOMEGA G2 Version
+5.x boards and does not respond to rate changes.
+
+LED Flash Rate:
+The flash rate seems to be 1/x seconds on, then 1/x seconds off. So one cycle
+of off and on at an LED Flash rate of 1 is almost 2s. The value spans 8 bits
+but functionally 0 is off and 36-40 is on. Testing has shown an oddity, the
+value 35 is rejected by the microcontroller software and is not set.
+
+Fan State:
+ 0x61 a Auto thermostat function
+ 0x62 b On always on
+
+Fan High Temp:
+High Temp is the temprature in Celsius where the fan is be turned on.
+
+Fan Low Temp:
+Low Temp is the temprature in Celsius where the fan is be turned off.
+
+ID:
+The real purpose of this field is not known. It is known that it is a constant
+depending upon the direction of the packets and the board rev. It has been
+designated ID as a place holder but it could as easily be defined as version
+or it may be something else entirely.
+
+ 0x00 DC2 CONTROLLER00
+ IOMEGA G2 Version 5.x Controller ID (recv'd packets)
+ 0x07 BEL HOST (sent packets)
+ 0x12 DC2 CONTROLLER12
+ IOMEGA G2 Version 3.x Controller ID (recv'd packets)
+
+Checksum:
+The check sum is an 8 bit sum of the first 7 bytes with the most significant
+bit cleared.
+
+ Sum = ((b1 + b2 + b3 +b4 +b5 +b6 + b7) & 0x7f)
+
+The bytes and their meanings were determined by watching the serial port
+chatter during specific events such as LED Blue, LED Red, Fan ON, etc. So only
+events observed have been decoded. Although all the significant events were
+observed and decoded, there are some holes in the understanding of the
+protocol.
+
+There is one special packet that causes the microcontroller to reset. This
+packet is:
+ 0x23696f6d 0x65676115
+ (or as a string "#iomega\025")
+
+The resulting packet from the microcontroller is:
+ 0x62000000 0x00000062
+
+Testing also yielded that a null packet will cause the microcontroller to
+feed back the current state. So this packet:
+ 0x00000000 0x00000000
+
+will yield something like this (this is the default state):
+ 0x62620a61 0x322d1220
+
+The default state when the board powers on is:
+ State: Run
+ LED: Red
+ LED Rate: 10
+ Fan: On
+ Fan Temp High: 50C
+ Fan Temp Low: 45C
+
+Below is some of the data collected while watching the serial port chatter:
+
+w: 0x23696f6d 0x65676115 #iomega\025
+r: 0x62000000 0x00000062 b\0\0\0\0\0\0b
+w: 0x62630a61 0x322d0716 bc\na2-\7\26 red state
+r: 0x62630a61 0x322d1221 bc\na2-\22!
+w: 0x62641161 0x322d071e bd\21a2-\7\36 blue flash
+r: 0x62641161 0x322d1229 bd\21a2-\22)
+w: 0x62641161 0x322d071e bd\21a2-\7\36 blue flash
+
+LED ok
+w: 0x62620a61 0x322d0715 bb\na2-\7\25
+r: 0x62630a61 0x322d1220 bb\na2-\22
+
+LED alt
+w: 0x626f0a61 0x322d0719 bf\na2-\7\31
+r: 0x626f0a61 0x322d1224 bf\na2-\22$
+
+reset
+w: 0x68620a61 0x322d071b hb\na2-\7\33 reset
+r: 0x67620a61 0x322d0013 gb\na2-\0\23 resetting
+
+restart
+w: 0x66620a61 0x322d0719 fb\na2-\7\31 restart
+r: 0x65620a61 0x322d1223 eb\na2-\22# restarting
+
+shutdown
+w: 0x64620a61 0x322d0717 db\na2-\7\27 shutdown
+r: 0x63620a61 0x322d1221 cb\na2-\22! power shutting down
+
+soft Power
+r: 0x63620a61 0x322d000f cb\na2-\0\17 power shutting down
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/sccd/files/init-sccd b/packages/sccd/files/init-sccd
new file mode 100644
index 0000000000..372bfeae91
--- /dev/null
+++ b/packages/sccd/files/init-sccd
@@ -0,0 +1,38 @@
+#! /bin/sh
+#
+# This is an init script for open protium for storcenter
+# Copy it to /etc/init.d/sccd and type
+# > update-rc.d sccd defaults 60
+#
+sccd=/sbin/sccd
+test -x "$sccd" || exit 0
+
+case "$1" in
+ start)
+ echo -n "Starting StorCenter Control Daemon"
+ start-stop-daemon --start --quiet --exec $sccd
+ echo "."
+ ;;
+ stop)
+ echo -n "Stopping StorCenter Control Daemon"
+ start-stop-daemon --stop --quiet --pidfile /var/run/sccd.pid
+ echo "."
+ ;;
+ reload|force-reload)
+ start-stop-daemon --stop --quiet --signal 1 --exec $sccd
+ ;;
+ restart)
+ echo -n "Stopping StorCenter Control Daemon"
+ start-stop-daemon --stop --quiet --pidfile /var/run/sccd.pid
+ echo "."
+ sleep 1
+ echo -n "Starting StorCenter Control Daemon"
+ start-stop-daemon --start --quiet --exec $sccd
+ echo "."
+ ;;
+ *)
+ echo "Usage: /etc/init.d/sccd {start|stop|reload|restart|force-reload}"
+ exit 1
+esac
+
+exit 0
diff --git a/packages/sccd/files/scc-disk.c b/packages/sccd/files/scc-disk.c
new file mode 100644
index 0000000000..4fd494203a
--- /dev/null
+++ b/packages/sccd/files/scc-disk.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2006
+ * Protium Computing, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Protium Computing, Inc.
+ * 4. The name of Protium Computing, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+
+struct watch_table {
+ char *wt_path;
+ int wt_status;
+ int wt_reads;
+ int wt_writes;
+#define WT_INVALID 0
+#define WT_VALID 1
+#define WT_CHECK 2
+} iowt[] = {
+ { "/sys/block/hda/stat", WT_CHECK, 0, 0},
+ { "/sys/block/hdb/stat", WT_CHECK, 0, 0},
+ { "/sys/block/hdc/stat", WT_CHECK, 0, 0},
+ { "/sys/block/hdd/stat", WT_CHECK, 0, 0},
+ { NULL, WT_INVALID, -1, -1}
+};
+
+/*
+ * disk_activity() returns back the total number of read and writes done
+ * by the devices listed in the io watch table since the last call to
+ * disk_activity. The number of reads and writes are determined by
+ * opening and reading each of the valid files listed in the io watch
+ * table.The number of reads and writes are stored in the io watch table so
+ * that the next call to this routine can compare the current number of read
+ * and writes to those stored in the io watch table. The difference for
+ * each device is summed in the activity variable. The routine lazy
+ * evaluates the existance of the devices in the table.
+ *
+ * For the storcenter, we are only concerned with internal drives.
+ *
+ * The wt_path element must point at a diskstat file in the sysfs filesystem.
+ * File format can be found at: /usr/src/linux/Documentation/iostats.txt
+ * For this routine:
+ * nr, nw - number read and writes
+ * nmr, nmw - number of merged reads and writes
+ * nsr, nsw - number of the sectors read and written
+ * tr, tw - time spent reading and writing
+ * nio - raw number of ios
+ * tio, wtio - time spent and weighted time spent doing io
+ */
+int
+disk_activity()
+{
+ int activity = 0;
+ char mesg[256];
+ int rc, nr, nmr, nsr, tr, nw, nmw, nsw, tw, nio, tio, wtio;
+ FILE *f;
+
+ struct stat st;
+ struct watch_table *w;
+
+ for (w = iowt; w->wt_path; w++) {
+ /*
+ * If status ids set to check, do the lazy existence
+ * evaluation. If stat fails set to invalid. Don't
+ * worry about perms here.
+ */
+ if ((w->wt_status == WT_CHECK) &&
+ (stat(w->wt_path, &st) < 0)) {
+ sprintf(mesg, "%s not available", w->wt_path);
+ syslog(LOG_INFO, mesg);
+ w->wt_status = WT_INVALID;
+ }
+
+ /*
+ * Short circuit the loop if invalid.
+ */
+ if (w->wt_status == WT_INVALID)
+ continue;
+
+ /*
+ * If it can't be opened rdonly, set to invalid
+ */
+ if ((f = fopen(w->wt_path, "r")) < 0) {
+ sprintf(mesg, "Unable to open %s, no longer watching",
+ w->wt_path);
+ syslog(LOG_INFO, mesg);
+ w->wt_status = WT_INVALID;
+ continue;
+ }
+
+ rc = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d",
+ &nr, &nmr, &nsr, &tr,
+ &nw, &nmw, &nsw, &tw,
+ &nio, &tio, &wtio);
+
+ fclose(f);
+
+ if (rc != 11) {
+ sprintf(mesg, "Unable to read %s", w->wt_path);
+ syslog(LOG_INFO, mesg);
+ continue;
+ }
+
+ /*
+ * If we haven't seen any activity on this device before
+ * then just save the values and go on. This, although
+ * not strictly necessary, prevents the initial call to
+ * disk_activity returning back the base set io activity.
+ * Remember it takes two calls to get a true difference.
+ */
+ if ((w->wt_reads == 0) && (w->wt_writes == 0)) {
+ w->wt_reads = nr;
+ w->wt_writes = nw;
+ continue;
+ }
+
+ activity += (nr - w->wt_reads);
+ activity += (nw - w->wt_writes);
+
+ w->wt_reads = nr;
+ w->wt_writes = nw;
+
+ /*
+ printf("%s: %d %d %d %d %d %d %d %d %d %d %d\n",
+ w->wt_path,
+ nr, nmr, nsr, tr,
+ nw, nmw, nsw, tw,
+ nio, tio, wtio);
+ */
+ }
+
+ return(activity);
+}
diff --git a/packages/sccd/files/scc-utils.c b/packages/sccd/files/scc-utils.c
new file mode 100644
index 0000000000..ab48ecb677
--- /dev/null
+++ b/packages/sccd/files/scc-utils.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2006
+ * Protium Computing, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Protium Computing, Inc.
+ * 4. The name of Protium Computing, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/syslog.h>
+#include <sys/resource.h>
+#include <termios.h>
+
+#include "scc.h"
+
+int scc_die = 0;
+
+char
+scc_cksum(int *i, int *j)
+{
+ unsigned char s;
+ unsigned char *b;
+
+ b = (unsigned char *)i;
+ s = b[0] + b[1] + b[2] + b[3];
+ b = (unsigned char *)j;
+ s = s + b[0] + b[1] + b[2];
+ s = (s & 0x7f);
+
+ return((char)s);
+}
+
+int
+scc_validate(int *i, int *j, int verbose)
+{
+ int r, s;
+
+ /* if (verbose) printf("Packet: [0x%08x 0x%08x]\n", *i, *j); */
+
+ switch (*i & SCC_POWERMASK) {
+ case SCC_RUN:
+ if (verbose) printf("\tPower: run\n");
+ break;
+ case SCC_STOP:
+ if (verbose) printf("\tPower: stop\n");
+ break;
+ case SCC_ADVISESTOP:
+ if (verbose) printf("\tPower: advise stop\n");
+ break;
+ case SCC_RESTART:
+ if (verbose) printf("\tPower: restart\n");
+ break;
+ case SCC_ADVISERESTART:
+ if (verbose) printf("\tPower: advise restart\n");
+ break;
+ case SCC_RESET:
+ if (verbose) printf("\tPower: reset\n");
+ break;
+ case SCC_ADVISERESET:
+ if (verbose) printf("\tPower: advise reset\n");
+ break;
+ default:
+ if (verbose) printf("validate: bad power 0x%08x\n", *i);
+ return(-1);
+ }
+
+ switch (*i & SCC_LEDMASK) {
+ case SCC_LEDOFF:
+ if (verbose) printf("\tLed: off\n");
+ break;
+ case SCC_LEDBLUE:
+ if (verbose) printf("\tLed: blue\n");
+ break;
+ case SCC_LEDRED:
+ if (verbose) printf("\tLed: red\n");
+ break;
+ case SCC_LEDBLUEFLASH:
+ if (verbose) printf("\tLed: blue flash\n");
+ break;
+ case SCC_LEDREDFLASH:
+ if (verbose) printf("\tLed: red flash\n");
+ break;
+ case SCC_LEDALTERNATE1:
+ if (verbose) printf("\tLed: alternate1\n");
+ break;
+ case SCC_LEDALTERNATE3:
+ if (verbose) printf("\tLed: alternate3\n");
+ break;
+ default:
+ if (verbose) printf("validate: bad led value 0x%08x\n", *i);
+ return(-1);
+ }
+
+ r = ((*i & SCC_LEDRATEMASK) >> SCC_LEDRATESHIFT);
+
+ if (verbose) {
+ printf("\tLed Flash Rate: %d\n", r);
+ }
+
+ if (r >= SCC_LEDRATEHI)
+ printf("warning: led rate too high - led on (%d)\n", r);
+ if (r <= SCC_LEDRATELO)
+ printf("warning: led rate too low - led off (%d)\n", r);
+
+
+ switch (*i & SCC_FANMASK) {
+ case SCC_FANAUTO:
+ if (verbose) printf("\tFan: auto\n");
+ break;
+ case SCC_FANON:
+ if (verbose) printf("\tFan: on\n");
+ break;
+ default:
+ if (verbose) printf("validate: bad fan value 0x%08x\n", *i);
+ return(-1);
+ }
+
+ r = ((*j & SCC_FANTEMPONMASK) >> SCC_FANTEMPONSHIFT);
+ s = ((*j & SCC_FANTEMPOFFMASK) >> SCC_FANTEMPOFFSHIFT);
+
+ if (verbose) {
+ printf("\tFan On Temprature: %dC\n", r);
+ printf("\tFan Off Temprature: %dC\n", s);
+ }
+
+ if (r >= SCC_FANTEMPONHI)
+ printf("warning: fan on temp too high - fan off (%dC)\n", r);
+ if (s <= SCC_FANTEMPONLO)
+ printf("warning: fan on temp too low - fan on (%dC)\n", s);
+ if ((r - s) < SCC_FANTEMPDIFF) {
+ printf("warning: fan on/off temp too close or on < off \n");
+ printf("warning:\tfan on (%dC) fan off (%dC) \n", r, s);
+ }
+
+ r = *j & SCC_IDMASK;
+ if ((r != SCC_HOST) &&
+ (r != SCC_CTLR00) &&
+ (r != SCC_CTLR12)) {
+ printf("warning: bad id %08x\n", r);
+ }
+
+ r = *j & SCC_CKSUMMASK;
+ if (r != scc_cksum(i, j)) {
+ printf("warning: checksum incorrect (%02x != %02x)\n",
+ r, scc_cksum(i, j));
+ }
+ return(0);
+}
+
+int
+scc_setval(int *i, int mask, int val)
+{
+ /* clear the field */
+ *i = (*i & (mask ^ 0xffffffff));
+
+ /* insert the field */
+ *i = (*i ^ val);
+ return(0);
+}
+
+int
+scc_setrate(int *i, int mask, int shift, int val)
+{
+ /* Assumption: val is < field width */
+
+ /* clear the field */
+ *i = (*i & (mask ^ 0xffffffff));
+
+ /* insert the field */
+ *i = (*i ^ (val << shift));
+ return(0);
+}
+
+int
+scc_defaults(int *i, int *j)
+{
+ scc_setval(i, SCC_POWERMASK, SCC_POWERDEFAULT);
+ scc_setval(i, SCC_LEDMASK, SCC_LEDDEFAULT);
+ scc_setrate(i, SCC_LEDRATEMASK, SCC_LEDRATESHIFT, SCC_LEDRATEDEFAULT);
+ scc_setval(i, SCC_FANMASK, SCC_FANDEFAULT);
+
+ scc_setrate(j, SCC_FANTEMPONMASK,
+ SCC_FANTEMPONSHIFT, SCC_FANTEMPONDEFAULT);
+ scc_setrate(j, SCC_FANTEMPOFFMASK,
+ SCC_FANTEMPOFFSHIFT, SCC_FANTEMPOFFDEFAULT);
+ return(0);
+}
+
+void
+scc_sighandler(int sig)
+{
+ /*
+ * Just catch quit and term and set die
+ */
+ switch(sig) {
+ case SIGQUIT:
+ case SIGTERM:
+ syslog(LOG_INFO, "Terminating");
+ scc_die=1;
+ break;
+ }
+}
+
+int
+scc_daemonize(int cores)
+{
+ int fd, i;
+ char pidstr[20];
+ pid_t pid;
+
+ struct rlimit limit[1] = {{ 0, 0 }};
+
+
+ if (!cores) {
+ /*
+ * No corefiles please
+ */
+ if (getrlimit(RLIMIT_CORE, limit) == -1) {
+ perror("getrlimit");
+ return -1;
+ }
+
+ limit->rlim_cur = 0;
+
+ if (setrlimit(RLIMIT_CORE, limit) != 0) {
+ perror("setrlimit");
+ return -1;
+ }
+ }
+
+ /*
+ * Must be root
+ */
+ if (getuid() != 0) {
+ fprintf(stderr, "Must be root\n");
+ return -1;
+ }
+
+ /*
+ * If parent isn't init, make it init.
+ */
+ if (getppid() != 1) {
+
+ pid = fork();
+ if (pid == -1) {
+ return -1;
+ }
+ if (pid != 0) {
+ exit(EXIT_SUCCESS);
+ }
+
+ setsid();
+
+ /*
+ * ignore sig hup so that when our new padre exits
+ * the kinder won't exit
+ */
+ signal(SIGHUP, SIG_IGN);
+
+ pid = fork();
+ if (pid == -1) {
+ return -1;
+ }
+ if (pid != 0) {
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ /*
+ * Set working dir to root
+ */
+ chdir("/");
+
+ /*
+ * Make sure file creations are created with explicit perms
+ */
+ umask(0);
+
+ /*
+ * Close all FDs
+ */
+ for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) {
+ close(i);
+ }
+
+ /*
+ * set std in, out, err to /dev/null
+ */
+ for (i = 0; i < 3; i++) {
+
+ if ((fd = open("/dev/null", (i==0?O_RDONLY:O_WRONLY))) == -1) {
+ perror("setting up stdin, stdout, stderr");
+ return -1;
+ }
+
+ if (i != fd) {
+ if (dup2(fd, i) == -1) {
+ perror("setting up stdin, stdout, stderr");
+ return -1;
+ }
+ close(fd);
+ }
+ }
+
+ /*
+ * Open and lock the pid file. Ensures only one daemon
+ * Write our pid into the file
+ */
+ fd = open(SCC_PIDFILE, O_RDWR|O_CREAT, 0640);
+ if (fd < 0) {
+ return(-1);
+
+ }
+
+ if (lockf(fd, F_TLOCK, 0) < 0) {
+ /* we are not alone */
+ close(fd);
+ return(-1);
+ }
+
+ sprintf(pidstr,"%-6d\n", getpid());
+ write(fd, pidstr, strlen(pidstr));
+
+ /*
+ * Open syslog
+ */
+ openlog("sccd", LOG_PID, LOG_DAEMON);
+ syslog(LOG_INFO, "Starting");
+
+ /*
+ * Ignore some signals and handle others
+ */
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGQUIT, scc_sighandler);
+ signal(SIGTERM, scc_sighandler);
+
+ return(0);
+}
+
+
diff --git a/packages/sccd/files/scc.1 b/packages/sccd/files/scc.1
new file mode 100644
index 0000000000..be27a569c3
--- /dev/null
+++ b/packages/sccd/files/scc.1
@@ -0,0 +1,120 @@
+.\" Copyright (c) 2006
+.\" Protium Computing, Inc. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Protium Computing, Inc.
+.\" 4. The name of Protium Computing, Inc. may not be used to endorse or
+.\" promote products derived from this software without specific prior
+.\" written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.TH SCC "1" "November 2006" "scc 1.0" "User Commands"
+.SH NAME
+scc \- StorCenter Control Utility
+.SH SYNOPSIS
+.B scc
+\fI[OPTIONS]\fR ...
+.SH DESCRIPTION
+scc controls the Iomega StorCenter's LED, fan and soft power. It does this
+either by sending a message to the StorCenter Control Daemon, if available,
+or directly communicating with the StorCenter's microcontroller responsible
+for these devices.
+.PP
+The scc utility can perform the following functions:
+.TP
+\fB\fR
+The LED can be set to off, blue, red, blue flash, red flash,
+alternate (blue->red->blue) and on some boards alternate3
+(blue->blue->blue->red->red->red). The flash and alernate rates
+can be be set. Alternate3 rate is fixed.
+.TP
+\fB\fR
+Fan can be set to on or auto. Auto mode is a thermostat function
+that turns the fan on and off based on two temprature settings:
+Fan Temp High and Fan Temp Low.
+.TP
+\fB\fR
+The system can be reset, causing a StorCenter reset, or stopped,
+causing a full power down.
+.SH OPTIONS
+.TP
+\fB\-?\fR
+display this help and exit
+.TP
+\fB\-d\fR
+send send directly, stop/restart only
+.TP
+\fB\-p POWER\fR
+control soft power
+.br
+POWER=[run|off|restart]
+.TP
+\fB\-l LED\fR
+control LED state
+.br
+LED=[off|blue|red|blueflash|redflash|alternate|alternate3]
+.TP
+\fB\-r RATE\fR
+Rate the LED flashes (0<=RATE<256)
+.TP
+\fB\-f FAN\fR
+control fan operation
+.br
+FAN=[auto|on]
+.TP
+\fB\-h TEMP\fR
+Hot temp when FAN=auto should go on (0<=TEMP<256)
+.TP
+\fB\-c TEMP\fR
+Cold temp when FAN=auto should go off (0<=TEMP<256)
+.SH NOTES
+Care should be taken when changing the LED. The boot scripts and the
+.B sccd
+daemon use LED colors to indicate boot and disk activity. Changing the LED can
+cause some of these functions to be disabled.
+.SH AUTHOR
+Written by Philip Kufeldt.
+.SH "REPORTING BUGS"
+Report bugs at www.openprotium.org.
+.SH COPYRIGHT
+Copyright \(co 2006 Protium Computing, Inc. All rights reserved.
+.br
+This is free software. Redistribution and use in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+.IP
+Redistributions of source code must retain the above copyright notice,this list of conditions and the following disclaimer.
+.br
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+.br
+All advertising materials mentioning features or use of this software must display the following acknowledgement:
+.br
+ This product includes software developed by Protium Computing, Inc.
+.br
+The name of Protium Computing, Inc. may not be used to endorse or promote products derived from this software without specific prior written permission.
+.PP
+.SH "SEE ALSO"
+The full documentation for
+.B scc
+can be found at www.openprotium.org
+
diff --git a/packages/sccd/files/scc.c b/packages/sccd/files/scc.c
new file mode 100644
index 0000000000..b917bf1ee8
--- /dev/null
+++ b/packages/sccd/files/scc.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2006
+ * Protium Computing, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Protium Computing, Inc.
+ * 4. The name of Protium Computing, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+
+#include "scc.h"
+
+char * prog;
+int initialize = 0;
+int verbose = 0;
+
+scc_cmd_t powercmds[] = {
+ { "a", 0x61000000},
+ { "run", SCC_RUN},
+ { "off", SCC_STOP},
+ { "advoff", SCC_ADVISESTOP},
+ { "restart", SCC_RESTART,},
+ { "advrestart", SCC_ADVISERESTART},
+ { "reset", SCC_RESET,},
+ { "advreset", SCC_ADVISERESET},
+ { "EOT", -1}};
+
+scc_cmd_t ledcmds[] = {
+ { "off", SCC_LEDOFF},
+ { "blue", SCC_LEDBLUE},
+ { "red", SCC_LEDRED},
+ { "blueflash", SCC_LEDBLUEFLASH},
+ { "redflash", SCC_LEDREDFLASH},
+ { "alternate", SCC_LEDALTERNATE1},
+ { "alternate3", SCC_LEDALTERNATE3},
+ { "EOT", -1}};
+
+scc_cmd_t fancmds[]= {
+ { "auto", SCC_FANAUTO},
+ { "on", SCC_FANON},
+ { "EOT", -1}};
+
+void
+usage(void)
+{
+ int i;
+ scc_cmd_t *c;
+
+ fprintf(stderr, "Usage: %s OPTIONS\n", prog);
+ fprintf(stderr,"%s controls the Iomega StorCenter's LED, fan and soft power.\n\n", prog);
+ fprintf(stderr," -?\t\tthis message\n");
+ fprintf(stderr," -v\t\tverbose, show all packets\n");
+ fprintf(stderr," -d\t\tsend send directly, stop/restart only\n");
+ fprintf(stderr,"\n -p POWER\tcontrol soft power\n");
+ fprintf(stderr,"\t\tPOWER=[");
+ for (c = powercmds,i=0; c->scc_cmdval != -1; c++,i++) {
+ if (i) fprintf(stderr,"|");
+ fprintf(stderr,"%s", c->scc_cmd);
+ }
+ fprintf(stderr,"]\n\n");
+
+ fprintf(stderr," -l LED\tcontrol LED state\n");
+ fprintf(stderr,"\t\tLED=[");
+ for (c = ledcmds,i=0; c->scc_cmdval != -1; c++,i++) {
+ if (i) fprintf(stderr,"|");
+ fprintf(stderr,"%s", c->scc_cmd);
+ }
+ fprintf(stderr,"]\n -r RATE\tRate the LED flashes (0<=RATE<256)\n\n");
+
+
+ fprintf(stderr," -f FAN\tcontrol fan operation\n");
+ fprintf(stderr,"\t\tFAN=[");
+ for (c = fancmds,i=0; c->scc_cmdval != -1; c++,i++) {
+ if (i) fprintf(stderr,"|");
+ fprintf(stderr,"%s", c->scc_cmd);
+ }
+ fprintf(stderr,"]\n -h TEMP\tHot temp when FAN=auto should go on (0<=TEMP<256)\n");
+ fprintf(stderr," -c TEMP\tCold temp when FAN=auto should go off (0<=TEMP<256)\n");
+
+ (void)exit(2);
+}
+
+int
+sendrecv(int fd, int *i, int *j)
+{
+ char buf[8];
+ int rc;
+ fd_set fds;
+ struct timeval sec = {1, 0};
+ struct timespec tenth_sec = {0, 100000000};
+
+
+ /* build the buffer */
+ *(int *)(buf) = *i;
+ *(int *)(buf + 4) = *j;
+
+ if (verbose)
+ printf("Send: [0x%08x 0x%08x]\n", *i, *j);
+
+ if ((rc = write(fd, buf, 8)) != 8) {
+ perror("write failed failed");
+ return(-1);
+ }
+
+ /* Wait for data */
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ rc = select(1024, &fds, NULL, NULL, &sec);
+
+ if (rc == -1) {
+ perror("select failed");
+ return (-1);
+ } else if (!rc) {
+ perror("select timedout");
+ return (-1);
+ }
+
+ /* Consume it */
+ if ((rc = read(fd, buf, 8)) != 8) {
+ perror("read failed failed");
+ return(-1);
+ }
+
+ *i = *(int *)(buf);
+ *j = *(int *)(buf + 4);
+
+ if (verbose)
+ printf("Recv: [0x%08x 0x%08x]\n", *i, *j);
+
+ /* Let it rest */
+ nanosleep(&tenth_sec, NULL);
+
+ return(0);
+}
+
+int
+setup_clnt()
+{
+ int s, len;
+ struct sockaddr_un remote;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ return(-1);
+ }
+
+ remote.sun_family = AF_UNIX;
+ strcpy(remote.sun_path, SCC_SOCKET);
+ len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+ if (connect(s, (struct sockaddr *)&remote, len) == -1) {
+ return(-1);
+ }
+
+ return(s);
+}
+
+int
+setup_cntlr(int *i, int *j)
+{
+ int fd;
+ char *dev = SCC_DEVICE;
+ struct termios ti;
+
+ /* setup the serial connection to 9600, 8n1 */
+ if ((fd = open(dev, O_RDWR|O_NOCTTY)) < 0) {
+ perror("Open failed");
+ return(-1);
+ }
+
+ if (ioctl(fd, TCGETS, &ti) < 0) {
+ perror("TCGETS failed");
+ return(-1);
+ }
+
+ if (ioctl(fd, TCFLSH, 0) < 0) {
+ perror("TCFLSH failed");
+ return(-1);
+ }
+
+ ti.c_iflag = IGNPAR;
+ ti.c_oflag = 0;
+ ti.c_cflag = (B9600 | CS8 | CREAD | CLOCAL);
+ ti.c_lflag = 0;
+ ti.c_line = N_TTY;
+ bzero(ti.c_cc, NCCS);
+ ti.c_cc[VMIN] = 0x08;
+
+ if (ioctl(fd, TCSETS, &ti) < 0) {
+ perror("TCSETS failed");
+ return(-1);
+ }
+
+ if (verbose) printf("Resetting microcontroller\n");
+ *i = SCC_RESETW1;
+ *j = SCC_RESETW2;
+ scc_setval(i, SCC_IDMASK, SCC_HOST);
+ scc_setval(j, SCC_CKSUMMASK, (int)scc_cksum(i, j));
+ if (sendrecv(fd, i, j) < 0)
+ return(-1);
+
+ return(fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ int devfd, w1, w2, h1, h2;
+ int coldtemp, hottemp, fancmd;
+ int ledrate, ledcmd;
+ int powercmd;
+ int direct;
+ int c;
+ char buf[SCC_PACKETLEN];
+ scc_cmd_t *ct;
+
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+
+ prog = argv[0];
+ fancmd = coldtemp = hottemp = -1;
+ ledcmd = ledrate = -1;
+ powercmd = -1;
+ direct = 0;
+
+ while ((c = getopt(argc, argv, "c:df:h:l:p:r:wv?")) != EOF) {
+ switch (c) {
+ case 'c':
+ if (coldtemp != -1) /* more than one -c arg */
+ usage();
+
+ coldtemp = atoi(optarg);
+ if ((coldtemp > 255) || (coldtemp < 0))
+ usage();
+ break;
+ case 'd':
+ direct = 1;
+ break;
+ case 'f':
+ if (fancmd != -1) /* more than one -f arg */
+ usage();
+
+ for (ct = fancmds; ct->scc_cmdval != -1; ct++) {
+ if (!strcmp(ct->scc_cmd, optarg)) {
+ fancmd = ct->scc_cmdval;
+ }
+ }
+
+ if (fancmd == -1) /* Failed to find the req */
+ usage();
+
+ break;
+ case 'h':
+ if (hottemp != -1) /* more than one -h arg */
+ usage();
+
+ hottemp = atoi(optarg);
+ if ((hottemp > 255) || (hottemp < 0))
+ usage();
+ break;
+ case 'l':
+ if (ledcmd != -1) /* more than one -l arg */
+ usage();
+
+ for (ct = ledcmds; ct->scc_cmdval != -1; ct++) {
+ if (!strcmp(ct->scc_cmd, optarg)) {
+ ledcmd = ct->scc_cmdval;
+ }
+ }
+
+ if (ledcmd == -1) /* Failed to find the req */
+ usage();
+ break;
+ case 'p':
+ if (powercmd != -1) /* more than one -p arg */
+ usage();
+
+ for (ct = powercmds; ct->scc_cmdval != -1; ct++) {
+ if (!strcmp(ct->scc_cmd, optarg)) {
+ powercmd = ct->scc_cmdval;
+ }
+ }
+
+ if (powercmd == -1) /* Failed to find the req */
+ usage();
+ break;
+ case 'r':
+ if (ledrate != -1) /* more than one -h arg */
+ usage();
+
+ ledrate = atoi(optarg);
+ if ((ledrate > 255) || (ledrate < 0))
+ usage();
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case '?':
+ usage();
+ break;
+
+ }
+ }
+
+ if (direct) {
+ /*
+ * Setup the cntlr connection
+ */
+ if ((devfd = setup_cntlr(&w1, &w2)) < 0)
+ exit(1);
+ scc_defaults(&w1, &w2);
+ } else {
+ /*
+ * Setup the clnt connection, if we get an connection
+ * refused that means the daemon isn't listening.
+ * so go direct
+ */
+ w1 = 0;
+ w2 = 0;
+ if ((devfd = setup_clnt()) < 0) {
+ /* log it */
+ if ((devfd = setup_cntlr(&w1, &w2)) < 0)
+ exit(1);
+ direct = 1;
+ scc_defaults(&w1, &w2);
+ }
+ }
+
+ /*
+ * Direct (direct to the cntlr):
+ * w1 and w2 are setup with the default cntlr packet.
+ * Now lets poke the command line args into the packet.
+ *
+ * Nondirect (via the daemon):
+ * w1 and w2 are setup with nulls. The packet sent to the daemon
+ * contains only the changes to the current state.
+ */
+ if (powercmd != -1)
+ scc_setval(&w1, SCC_POWERMASK, powercmd);
+ if (ledcmd != -1)
+ scc_setval(&w1, SCC_LEDMASK, ledcmd);
+ if (ledrate != -1)
+ scc_setrate(&w1, SCC_LEDRATEMASK, SCC_LEDRATESHIFT, ledrate);
+ if (fancmd != -1)
+ scc_setval(&w1, SCC_FANMASK, fancmd);
+
+ if (coldtemp != -1)
+ scc_setrate(&w2,
+ SCC_FANTEMPOFFMASK, SCC_FANTEMPOFFSHIFT, coldtemp);
+ if (hottemp != -1)
+ scc_setrate(&w2,
+ SCC_FANTEMPONMASK, SCC_FANTEMPONSHIFT, hottemp);
+
+ scc_setval(&w2, SCC_IDMASK, SCC_HOST);
+ scc_setval(&w2, SCC_CKSUMMASK, (int)scc_cksum(&w1, &w2));
+
+
+ if (direct) {
+ if (verbose) {
+ printf("New State: \n");
+ scc_validate(&w1, &w2, verbose);
+ }
+
+ if (sendrecv(devfd, &w1, &w2) < 0)
+ exit(1);
+ } else {
+ *(int *)(&buf[0]) = w1;
+ *(int *)(&buf[4]) = w2;
+
+ if (send(devfd, buf, SCC_PACKETLEN, 0) == -1) {
+ perror("send");
+ exit(1);
+ }
+ }
+
+ close(devfd);
+ exit(0);
+}
diff --git a/packages/sccd/files/scc.h b/packages/sccd/files/scc.h
new file mode 100644
index 0000000000..611092fd9c
--- /dev/null
+++ b/packages/sccd/files/scc.h
@@ -0,0 +1,118 @@
+#ifndef _SCC_H
+#define _SCC_H
+/*
+ * Copyright (c) 2006
+ * Protium Computing, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Protium Computing, Inc.
+ * 4. The name of Protium Computing, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define SCC_PIDFILE "/var/run/sccd.pid"
+#define SCC_DEVICE "/dev/tts/1"
+#define SCC_SOCKET "/dev/sccd"
+
+#define SCC_PACKETLEN 8
+
+#define SCC_RESETW1 0x23696f6d
+#define SCC_RESETW2 0x65676100
+#define SCC_QUERYW1 0x00000000
+#define SCC_QUERYW2 QUERYW1
+
+/* word 1 defines */
+#define SCC_RUN 0x62000000
+#define SCC_STOP 0x63000000
+#define SCC_ADVISESTOP 0x64000000
+#define SCC_RESTART 0x65000000
+#define SCC_ADVISERESTART 0x66000000
+#define SCC_RESET 0x67000000
+#define SCC_ADVISERESET 0x68000000
+#define SCC_POWERMASK 0xFF000000
+
+#define SCC_LEDOFF 0x00610000
+#define SCC_LEDBLUE 0x00620000
+#define SCC_LEDRED 0x00630000
+#define SCC_LEDBLUEFLASH 0x00640000
+#define SCC_LEDREDFLASH 0x00650000
+#define SCC_LEDALTERNATE1 0x00660000
+#define SCC_LEDALTERNATE3 0x00670000
+#define SCC_LEDMASK 0x00FF0000
+
+#define SCC_LEDRATEMASK 0x0000FF00
+#define SCC_LEDRATESHIFT 8
+#define SCC_LEDRATEHI 40 /* limit: where flash == on */
+#define SCC_LEDRATELO 0 /* limit: where flash == off */
+#define SCC_LEDIORATE 20
+
+#define SCC_FANAUTO 0x00000061
+#define SCC_FANON 0x00000062
+#define SCC_FANMASK 0x000000FF
+
+/* word 2 defines */
+#define SCC_FANTEMPONMASK 0xFF000000
+#define SCC_FANTEMPONSHIFT 24
+#define SCC_FANTEMPONHI 60 /* limit: board on fire 140F */
+
+#define SCC_FANTEMPOFFMASK 0x00FF0000
+#define SCC_FANTEMPOFFSHIFT 16
+#define SCC_FANTEMPONLO 15 /* limit: never turn off 60F */
+#define SCC_FANTEMPDIFF 2 /* limit: if the diff between
+ hi and lo is < then this the
+ fan could rapidly sccillate
+ or never turn on */
+#define SCC_HOST 0x00000700
+#define SCC_CTLR00 0x00000000
+#define SCC_CTLR12 0x00001200
+#define SCC_IDMASK 0x0000FF00
+
+#define SCC_CKSUMMASK 0x000000FF
+
+#define SCC_POWERDEFAULT SCC_RUN
+#define SCC_LEDDEFAULT SCC_LEDRED
+#define SCC_LEDRATEDEFAULT 10
+#define SCC_FANDEFAULT SCC_FANAUTO
+#define SCC_FANTEMPONDEFAULT 50
+#define SCC_FANTEMPOFFDEFAULT 45
+
+struct scc_cmd_table {
+ char *scc_cmd;
+ int scc_cmdval;
+};
+
+typedef struct scc_cmd_table scc_cmd_t;
+
+char scc_cksum(int *, int *);
+int scc_validate(int *, int *, int);
+int scc_setval(int *, int, int);
+int scc_setrate(int *, int, int, int);
+int scc_defaults(int *, int *);
+int scc_daemonize(int);
+int disk_activity(void);
+
+
+#endif /* _SCC_H */
+
diff --git a/packages/sccd/files/sccd.c b/packages/sccd/files/sccd.c
new file mode 100644
index 0000000000..4f74c1d49c
--- /dev/null
+++ b/packages/sccd/files/sccd.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2006
+ * Protium Computing, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Protium Computing, Inc.
+ * 4. The name of Protium Computing, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <utmp.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/param.h>
+#include <termios.h>
+
+#include "scc.h"
+
+#define HALT "/sbin/halt"
+#define REBOOT "/sbin/reboot"
+
+char * prog;
+int verbose = 0;
+
+extern int scc_die;
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s OPTIONS\n", prog);
+ fprintf(stderr,
+ "StorCenter Control Daemon manages the StorCenter's LED, fan and soft power.\n\n");
+ fprintf(stderr," -?\t\tthis message\n");
+ fprintf(stderr," -h\t\tthis message\n");
+ fprintf(stderr," -c\t\tallow core files\n");
+ fprintf(stderr," -f\t\trun in the foreground\n");
+ fprintf(stderr," -v\t\tverbose, show all packets (must be used with -f)\n");
+ (void)exit(2);
+}
+
+int
+sendrecv(int fd, int *i, int *j)
+{
+ char buf[8];
+ int rc;
+ fd_set fds;
+ struct timeval sec = {1, 0};
+ struct timespec tenth_sec = {0, 100000};
+
+
+ /* build the buffer */
+ *(int *)(buf) = *i;
+ *(int *)(buf + 4) = *j;
+
+ if (verbose)
+ printf("Send: [0x%08x 0x%08x]\n", *i, *j);
+
+ if ((rc = write(fd, buf, 8)) != 8) {
+ syslog(LOG_ERR, "Write failed to controller");
+ return(-1);
+ }
+
+ /* Wait for data */
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ rc = select(1024, &fds, NULL, NULL, &sec);
+
+ if (rc == -1) {
+ syslog(LOG_ERR, "Controller select failed");
+ return (-1);
+ } else if (!rc) {
+ syslog(LOG_ERR, "Controller timeout");
+ return (-1);
+ }
+
+ /* Consume it */
+ if ((rc = read(fd, buf, 8)) != 8) {
+ syslog(LOG_ERR, "Read from controller failed");
+ return(-1);
+ }
+
+ *i = *(int *)(buf);
+ *j = *(int *)(buf + 4);
+
+ if (verbose)
+ printf("Recv: [0x%08x 0x%08x]\n", *i, *j);
+
+ /* Let it rest */
+ nanosleep(&tenth_sec, NULL);
+
+ return(0);
+}
+
+int
+setup_clnt()
+{
+ int s;
+ struct sockaddr_un local;
+ int len;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ perror("socket");
+ return(-1);
+ }
+
+ local.sun_family = AF_UNIX;
+ strcpy(local.sun_path, SCC_SOCKET);
+ unlink(local.sun_path);
+
+ len = strlen(local.sun_path) + sizeof(local.sun_family);
+ if (bind(s, (struct sockaddr *)&local, len) == -1) {
+ perror("bind");
+ close(s);
+ return(-1);
+ }
+
+ if (listen(s, 5) == -1) {
+ perror("listen");
+ close(s);
+ return(-1);
+ }
+
+ /* Force the permission on the unix socket */
+ if (chmod(SCC_SOCKET, (S_IWUSR | S_IRUSR)) < 0) {
+ perror("chmod socket");
+ }
+
+ return(s);
+}
+
+int
+setup_cntlr()
+{
+ int i, j, fd;
+ char *dev = SCC_DEVICE;
+ struct termios ti;
+
+ /* setup the serial connection to 9600, 8n1 */
+ if ((fd = open(dev, O_RDWR|O_NOCTTY)) < 0) {
+ perror("Open failed");
+ return(-1);
+ }
+
+ if (ioctl(fd, TCGETS, &ti) < 0) {
+ perror("TCGETS failed");
+ return(-1);
+ }
+
+ if (ioctl(fd, TCFLSH, 0) < 0) {
+ perror("TCFLSH failed");
+ return(-1);
+ }
+
+ ti.c_iflag = IGNPAR;
+ ti.c_oflag = 0;
+ ti.c_cflag = (B9600 | CS8 | CREAD | CLOCAL);
+ ti.c_lflag = 0;
+ ti.c_line = N_TTY;
+ bzero(ti.c_cc, NCCS);
+ ti.c_cc[VMIN] = 0x08;
+
+ if (ioctl(fd, TCSETS, &ti) < 0) {
+ perror("TCSETS failed");
+ return(-1);
+ }
+
+ if (verbose) printf("Resetting microcontroller\n");
+ i = SCC_RESETW1;
+ j = SCC_RESETW2;
+ scc_setval(&j, SCC_CKSUMMASK, (int)scc_cksum(&i, &j));
+ if (sendrecv(fd, &i, &j) < 0) {
+ return(-1);
+ }
+
+ return(fd);
+}
+
+int
+handle_clnt(int clnt, int *w1, int *w2)
+{
+ char buf[SCC_PACKETLEN];
+ int s, t, i, j, *x, *y;
+ struct sockaddr_un remote;
+
+ t = sizeof(remote);
+ s = accept(clnt, (struct sockaddr *)&remote, &t);
+ if (s < 0) {
+ syslog(LOG_ERR, "Unable to accept client");
+ return(-1);
+ }
+
+ if (recv(s, buf, SCC_PACKETLEN, 0) != SCC_PACKETLEN) {
+ return(-1);
+ }
+ close(s);
+
+ x = (int *)&buf[0];
+ y = (int *)&buf[4];
+
+ /*
+ * Clients only send fields they want enacted. This allows this daemon
+ * to keep the other values constant without informing the clients
+ * of the current setting. It allows the protocol to unidirectional.
+ *
+ * Take the data from the client and add it to the current
+ * state then validate the resulting state. If valid, return
+ * the new state. If not don't corrupt the existing state.
+ */
+ i = *w1;
+ j = *w2;
+
+ if (*x & SCC_POWERMASK)
+ scc_setval(&i, SCC_POWERMASK, (*x & SCC_POWERMASK));
+ if (*x & SCC_LEDMASK)
+ scc_setval(&i, SCC_LEDMASK, (*x & SCC_LEDMASK));
+ if (*x & SCC_LEDRATEMASK)
+ scc_setval(&i, SCC_LEDRATEMASK, (*x & SCC_LEDRATEMASK));
+ if (*x & SCC_FANMASK)
+ scc_setval(&i, SCC_FANMASK, (*x & SCC_FANMASK));
+
+ if (*y & SCC_FANTEMPONMASK)
+ scc_setval(&j, SCC_FANTEMPONMASK, (*y & SCC_FANTEMPONMASK));
+ if (*y & SCC_FANTEMPOFFMASK)
+ scc_setval(&j, SCC_FANTEMPOFFMASK, (*y & SCC_FANTEMPOFFMASK));
+ scc_setval(&j, SCC_IDMASK, SCC_HOST);
+ scc_setval(&j, SCC_CKSUMMASK, (int)scc_cksum(&i, &j));
+
+ if (scc_validate(&i, &j, verbose) < 0) {
+ /* log it and return */
+ return(-1);
+ }
+
+ /*
+ * If we are here we got a good packet, return it.
+ */
+ *w1 = i;
+ *w2 = j;
+ return(0);
+}
+
+#ifdef NOTUSED
+char
+runlevel()
+{
+ struct utmp *ut;
+ time_t boot;
+
+ /*
+ * Find last boot time
+ */
+ time(&boot);
+ boot -= (times(NULL) / HZ);
+
+ setutent();
+ while ((ut = getutent()) != NULL) {
+ /*
+ * Find runlevel after our last boot
+ */
+ if (ut->ut_type == RUN_LVL && ut->ut_time > boot)
+ return(ut->ut_pid & 0xff);
+ }
+ endutent();
+
+ return(0xff);
+}
+#endif
+
+int
+work_loop(int cntlr, int clnt)
+{
+
+ int rc, w1, w2, c1, c2, saverate;
+ int shutdown_called = 0;
+ pid_t pid;
+ fd_set fds;
+ struct timeval tv;
+
+ /*
+ * If we are booting set to red flash and
+ * wait for someone to change it.
+ * If we are already in runlevel 5 then set it to blue
+ */
+ scc_defaults(&w1, &w2);
+ scc_setval(&w1, SCC_LEDMASK, SCC_LEDREDFLASH);
+ scc_setval(&w2, SCC_IDMASK, SCC_HOST);
+ scc_setval(&w2, SCC_CKSUMMASK, (int)scc_cksum(&w1, &w2));
+
+ if (verbose) {
+ printf("New State: \n");
+ scc_validate(&w1, &w2, verbose);
+ }
+
+ if (sendrecv(cntlr, &w1, &w2) < 0) {
+ /* log then carry on */
+ }
+
+ while (!scc_die) {
+ /*
+ * Wait for data. How long? Well detecting soft power
+ * events should happen fairly quickly, 1 second between
+ * probes should be enough, but detecting disk activity
+ * probably needs to be a little faster. So we try 0.5s or
+ * 500,000 micro seconds. If that steals too much CPU
+ * then we backoff here.
+ */
+ FD_ZERO(&fds);
+ FD_SET(clnt, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000;
+ rc = select(1024, &fds, NULL, NULL, &tv);
+
+ if (rc < 0) {
+ /* Select failed try again */
+ continue;
+ } else if (rc) {
+ /* Got a clnt request */
+ if (handle_clnt(clnt, &w1, &w2) < 0)
+ continue;
+ } else {
+ /* timeout - just fallthrough to refresh ctlr */
+ }
+
+ /*
+ * Here's how we do blinking lights for disk activity.
+ * If there is disk activity and the LED is blue, then
+ * set the led to blueflash and the rate to io rate.
+ * Next time through if there is still activity, the
+ * LED is unchanged. If no activity and the led is flashing
+ * blue then return it to solid blue and restore the rate.
+ */
+ if (disk_activity()) {
+ if ((w1 & SCC_LEDMASK) == SCC_LEDBLUE) {
+ saverate = (w1 & SCC_LEDRATEMASK);
+ scc_setval(&w1, SCC_LEDMASK, SCC_LEDBLUEFLASH);
+ scc_setrate(&w1, SCC_LEDRATEMASK,
+ SCC_LEDRATESHIFT, SCC_LEDIORATE);
+ }
+ } else {
+ if ((w1 & SCC_LEDMASK) == SCC_LEDBLUEFLASH) {
+ scc_setval(&w1, SCC_LEDMASK, SCC_LEDBLUE);
+ scc_setval(&w1, SCC_LEDRATEMASK, saverate);
+ }
+ }
+
+ /*
+ * Getting here because of a timeout or client request
+ * in either case refresh the cntlr. Don't use w1 and w2
+ * to refresh, cause the daemon should not incorporate
+ * the controller's view of the state into the daemon's
+ * view. Only a client should alter w1 and w2.
+ */
+ c1 = w1;
+ c2 = w2;
+ if (sendrecv(cntlr, &c1, &c2) < 0) {
+ continue;
+ }
+
+ /*
+ * Now examine the packet from the controller to see
+ * if action needs to be taken.
+ * If the power state is either: stop, restart or reset
+ * start shutting down the box. Once shutdown (reboot or halt)
+ * has beed call don't do it again.
+ */
+ if (shutdown_called)
+ continue;
+
+ switch (c1 & SCC_POWERMASK) {
+ case SCC_STOP:
+ /* exec halt */
+ syslog(LOG_INFO, "Halt requested");
+ if ((pid = fork()) == -1) {
+ break;
+ }
+
+ if (pid == 0) {
+ /* i am child */
+ char *argv[] = {HALT, NULL};
+ execv(HALT, argv);
+ exit(EXIT_FAILURE);
+ }
+
+ shutdown_called = 1;
+ break;
+
+ case SCC_RESTART:
+ case SCC_RESET:
+ /* exec reboot */
+ syslog(LOG_INFO, "Reboot requested");
+ if ((pid = fork()) == -1) {
+ break;
+ }
+ if (pid == 0) {
+ /* i am child */
+ char *argv[] = {REBOOT, NULL};
+ execv(REBOOT, argv);
+ exit(EXIT_FAILURE);
+ }
+
+ shutdown_called = 1;
+ break;
+
+ default:
+ /* Nothing to do */
+ break;
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ int cntlr, clnt, w1, w2;
+ int c, daemon, cores;
+
+ struct stat st;
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+
+ prog = argv[0];
+ daemon = 1;
+ cores = 0;
+
+ while ((c = getopt(argc, argv, "cfhv?")) != EOF) {
+ switch (c) {
+ case 'h':
+ usage();
+ break;
+ case 'c':
+ cores=1;
+ break;
+ case 'f':
+ daemon=0;
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case '?':
+ usage();
+ break;
+
+ }
+ }
+
+ if (verbose && daemon)
+ usage();
+
+ if (stat(HALT, &st) < 0) {
+ perror("Couldn't find halt");
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(REBOOT, &st) < 0) {
+ perror("Couldn't find reboot");
+ exit(EXIT_FAILURE);
+ }
+
+ if (daemon) {
+ if (scc_daemonize(cores) < 0)
+ exit(EXIT_FAILURE);
+ } else {
+ /*
+ * Open syslog
+ */
+ openlog("sccd", LOG_PID, LOG_DAEMON);
+ syslog(LOG_INFO, "Starting");
+ }
+
+ /*
+ * Setup the controller connection
+ */
+ if ((cntlr = setup_cntlr()) < 0)
+ exit(EXIT_FAILURE);
+
+ /*
+ * Setup the client connection
+ */
+ if ((clnt = setup_clnt()) < 0)
+ exit(EXIT_FAILURE);
+
+ work_loop(cntlr, clnt);
+
+ close(cntlr);
+ close(clnt);
+ unlink(SCC_PIDFILE);
+ exit(EXIT_SUCCESS);
+}
+