sccd: StorCenter Control Daemon: leds and fan control server/client
authorAndrew Wilcox <andy@protium.com>
Thu, 7 Dec 2006 19:22:25 +0000 (19:22 +0000)
committerAndrew Wilcox <andy@protium.com>
Thu, 7 Dec 2006 19:22:25 +0000 (19:22 +0000)
12 files changed:
packages/sccd/.mtn2git_empty [new file with mode: 0644]
packages/sccd/files/.mtn2git_empty [new file with mode: 0644]
packages/sccd/files/Makefile [new file with mode: 0644]
packages/sccd/files/README [new file with mode: 0644]
packages/sccd/files/init-sccd [new file with mode: 0644]
packages/sccd/files/scc-disk.c [new file with mode: 0644]
packages/sccd/files/scc-utils.c [new file with mode: 0644]
packages/sccd/files/scc.1 [new file with mode: 0644]
packages/sccd/files/scc.c [new file with mode: 0644]
packages/sccd/files/scc.h [new file with mode: 0644]
packages/sccd/files/sccd.c [new file with mode: 0644]
packages/sccd/sccd_1.0.bb [new file with mode: 0644]

diff --git a/packages/sccd/.mtn2git_empty b/packages/sccd/.mtn2git_empty
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/packages/sccd/files/.mtn2git_empty b/packages/sccd/files/.mtn2git_empty
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/packages/sccd/files/Makefile b/packages/sccd/files/Makefile
new file mode 100644 (file)
index 0000000..6504046
--- /dev/null
@@ -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 (file)
index 0000000..d2d1934
--- /dev/null
@@ -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 (file)
index 0000000..372bfea
--- /dev/null
@@ -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 (file)
index 0000000..4fd4942
--- /dev/null
@@ -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 (file)
index 0000000..ab48ecb
--- /dev/null
@@ -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 (file)
index 0000000..be27a56
--- /dev/null
@@ -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 (file)
index 0000000..b917bf1
--- /dev/null
@@ -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 (file)
index 0000000..611092f
--- /dev/null
@@ -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 (file)
index 0000000..4f74c1d
--- /dev/null
@@ -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);
+}
+
diff --git a/packages/sccd/sccd_1.0.bb b/packages/sccd/sccd_1.0.bb
new file mode 100644 (file)
index 0000000..e9c8036
--- /dev/null
@@ -0,0 +1,29 @@
+SECTION = "utility"
+DECSCRIPTION = "StorCenter Control Daemon - controls the leds, fans, softpower"
+LICENSE = "BSD"
+
+PR = "r2"
+
+SRC_URI = "file://scc.h \
+          file://scc.c \
+          file://sccd.c \
+          file://scc-utils.c \
+          file://scc-disk.c \
+          file://init-sccd \
+          file://Makefile \
+          file://README "
+
+inherit autotools update-rc.d
+
+INITSCRIPT_PARAMS = "defaults 91 20"
+INITSCRIPT_NAME = "sccd"
+
+do_unpack() {
+       mkdir -p ${S}
+       cp ${FILESDIR}/* ${S}
+}
+
+do_configure() {
+       :
+}
+