summaryrefslogtreecommitdiffstats
path: root/meta-facebook/meta-wedge
diff options
context:
space:
mode:
Diffstat (limited to 'meta-facebook/meta-wedge')
-rw-r--r--meta-facebook/meta-wedge/conf/machine/wedge.conf5
-rw-r--r--meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc6
-rw-r--r--meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down27
-rw-r--r--meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up28
-rw-r--r--meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend16
-rw-r--r--meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb50
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile24
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c559
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h46
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh77
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend64
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py318
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py223
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py19
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py12
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh163
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh24
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh168
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh11
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh73
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh56
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh61
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend95
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend6
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh10
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c52
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c94
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb17
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb17
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile34
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py174
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c181
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h47
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c152
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c2
-rwxr-xr-xmeta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py269
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py93
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c637
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h46
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c58
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh20
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb33
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py88
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py10
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py28
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py4
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py33
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb19
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb15
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c4
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile16
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c2
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb18
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb15
82 files changed, 4335 insertions, 299 deletions
diff --git a/meta-facebook/meta-wedge/conf/machine/wedge.conf b/meta-facebook/meta-wedge/conf/machine/wedge.conf
index 69f3a90..3ed8ec1 100644
--- a/meta-facebook/meta-wedge/conf/machine/wedge.conf
+++ b/meta-facebook/meta-wedge/conf/machine/wedge.conf
@@ -5,3 +5,8 @@
UBOOT_MACHINE_wedge = "wedge_config"
require conf/machine/include/ast1250.inc
+
+# configuration for preferred version of packages
+PREFERRED_VERSION_libipmi = "0.1"
+PREFERRED_VERSION_ipmid = "0.1"
+PREFERRED_VERSION_rest-api = "0.1"
diff --git a/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc b/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc
index 15a4252..7cd89de 100644
--- a/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc
+++ b/meta-facebook/meta-wedge/recipes-core/images/wedge-image.inc
@@ -39,9 +39,8 @@ NTP_PKGS = " \
# Include modules in rootfs
IMAGE_INSTALL += " \
kernel-modules \
- u-boot \
u-boot-fw-utils \
- fbutils \
+ openbmc-utils \
fan-ctrl \
rackmon \
watchdog-ctrl \
@@ -49,6 +48,8 @@ IMAGE_INSTALL += " \
sensor-setup \
usb-console \
oob-nic \
+ lldp-util \
+ bmc-log \
lmsensors-sensors \
wedge-eeprom \
sms-kcsd \
@@ -61,6 +62,7 @@ IMAGE_INSTALL += " \
${NTP_PKGS} \
iproute2 \
dhcp-client \
+ spatula \
"
IMAGE_FEATURES += " \
diff --git a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down
new file mode 100644
index 0000000..a44deb4
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_down
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+pid="/var/run/dhclient6.${IFACE}.pid"
+
+if [ -f "${pid}" ]; then
+ kill -9 `cat ${pid}` 2>/dev/null
+fi
+
+exit 0
diff --git a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up
new file mode 100644
index 0000000..6469b9f
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/files/dhcpv6_up
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+# only care about 'eth0' and 'oob' intf
+[ "$IFACE" != "eth0" ] && [ "$IFACE" != "oob" ] && exit 0
+
+pid="/var/run/dhclient6.${IFACE}.pid"
+
+dhclient -6 -nw -pf ${pid} ${IFACE}
+
+exit 0
diff --git a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
index 7d74521..e715c27 100644
--- a/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
+++ b/meta-facebook/meta-wedge/recipes-core/init-ifupdown/init-ifupdown_%.bbappend
@@ -1,2 +1,18 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+
+SRC_URI += "file://dhcpv6_up \
+ file://dhcpv6_down \
+ "
+
+do_install_append() {
+ # rules to request dhcpv6
+ install -d ${D}/${sysconfdir}/network/if-up.d
+ install -m 755 ${WORKDIR}/dhcpv6_up ${D}${sysconfdir}/network/if-up.d/dhcpv6_up
+ install -d ${D}/${sysconfdir}/network/if-down.d
+ install -m 755 ${WORKDIR}/dhcpv6_down ${D}${sysconfdir}/network/if-down.d/dhcpv6_down
+}
+
+FILES_${PN} += "${sysconfdir}/network/if-up.d/dhcpv6_up \
+ ${sysconfdir}/network/if-down.d/dhcpv6_down \
+ "
diff --git a/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend b/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
index 6bf04da..3c5b71c 100644
--- a/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
+++ b/meta-facebook/meta-wedge/recipes-kernel/linux/linux-aspeed_2.6%.bbappend
@@ -2,4 +2,4 @@ LINUX_VERSION_EXTENSION = "-wedge"
COMPATIBLE_MACHINE = "wedge"
-KERNEL_DEFCONFIG_aspeed = "wedge_defconfig"
+KERNEL_CONFIG_COMMAND = "oe_runmake wedge_defconfig && oe_runmake oldconfig"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb
new file mode 100644
index 0000000..2788a36
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/bmc-log_0.1.bb
@@ -0,0 +1,50 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+SUMMARY = "Logging Utility"
+DESCRIPTION = "Util for logging"
+SECTION = "base"
+PR = "r1"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://bmc-log.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://bmc-log.c \
+ file://bmc-log.h \
+ file://Makefile \
+ file://bmc-log-config \
+ file://bmc-log.sh \
+ "
+
+S = "${WORKDIR}"
+
+do_install() {
+ install -d ${D}${sbindir}
+ install -m 755 bmc-log ${D}${sbindir}/bmc-log
+ install -d ${D}${sysconfdir}/default
+ install -m 755 bmc-log-config ${D}${sysconfdir}/default/bmc-log
+ install -d ${D}${sysconfdir}/init.d
+ install -m 755 bmc-log.sh ${D}${sysconfdir}/init.d/bmc-log.sh
+ update-rc.d -r ${D} bmc-log.sh start 92 S .
+}
+
+FILES_${PN} = "${sbindir} ${sysconfdir} "
+
+# Inhibit complaints about .debug directories
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile
new file mode 100644
index 0000000..5004556
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/Makefile
@@ -0,0 +1,24 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+LIBS = -lutil
+
+all:
+ ${CC} ${CFLAGS} -o bmc-log bmc-log.c ${LIBS}
+
+clean:
+ rm -rf *.o bmc-log
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config
new file mode 100644
index 0000000..529adf2
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log-config
@@ -0,0 +1,16 @@
+# Configuration used by bmc-log script
+
+#Serial port connected to the micro-server
+US_TTY=""
+
+#IP version of the log collecting server
+LOG_SERVER_IP_VERSION=""
+
+#Host name of the log collecting server
+LOG_SERVER_NAME=""
+
+#Port number of the log collecting server
+LOG_SERVER_PORT=""
+
+#Baud rate to set for the US_TTY
+TTY_BAUD_RATE=""
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
new file mode 100644
index 0000000..078db7b
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <linux/serial.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <pty.h>
+#include <errno.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "bmc-log.h"
+
+FILE *error_file = NULL;
+
+bool kill_received = false; // To check if a killing interrupt is received
+
+speed_t baud_rate = B57600; // Default baud rate - change if user inputs a different one
+
+int fd_tty = -1, fd_soc = -1;
+
+/* Hostname and port of the server */
+char *hostname;
+int port;
+
+struct termios orig_tty_state;
+
+char *get_time()
+{
+ static char mytime[TIME_FORMAT_SIZE];
+ memset(mytime, 0, sizeof(mytime));
+ time_t this_time;
+ struct tm *this_tm;
+ this_time = time(NULL);
+ this_tm = localtime(&this_time);
+
+ snprintf(mytime, sizeof(mytime), "%04d-%02d-%02d %02d:%02d:%02d",
+ 1900 + this_tm->tm_year, this_tm->tm_mon + 1,
+ this_tm->tm_mday, this_tm->tm_hour,
+ this_tm->tm_min, this_tm->tm_sec);
+ return mytime;
+}
+
+void errlog(char *frmt, ...)
+{
+ va_list args;
+ va_start(args, frmt);
+ struct stat st;
+
+ char *time_now = get_time();
+
+ fprintf(stderr, "[%s] ", time_now);
+ vfprintf(stderr, frmt, args);
+
+ if (error_file) {
+ stat(error_log_file, &st);
+ if (st.st_size >= MAX_LOG_FILE_SIZE) {
+ truncate(error_log_file, 0);
+ }
+ fprintf(error_file, "[%s] ", time_now);
+ vfprintf(error_file, frmt, args);
+ fflush(error_file);
+ }
+}
+
+/* Get the address info of netcons server */
+struct addrinfo *get_addr_info(int ip_version)
+{
+ int ip_family = (ip_version == IPV4) ? AF_INET : AF_INET6;
+ struct addrinfo hints;
+
+ struct addrinfo *result;
+ result = malloc(sizeof(*result));
+ if (!result) {
+ errlog("Error: Unable to allocate memory - %m\n");
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = ip_family; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
+ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
+ hints.ai_protocol = 0; /* Any protocol */
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if (getaddrinfo(hostname, NULL, &hints, &result)) {
+ errlog("Error: getaddrinfo failed - %m\n");
+ return NULL;
+ }
+
+ return result;
+}
+
+/* Prepare Ipv4 Socket */
+bool prepare_sock(struct sockaddr_in * tgt_addr)
+{
+ struct addrinfo *addr_info;
+ memset(tgt_addr, 0, sizeof(*tgt_addr));
+
+ if ((addr_info = get_addr_info(IPV4)) == NULL) {
+ errlog("Error: Unable to get address info\n");
+ return false;
+ }
+
+ tgt_addr->sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;
+ tgt_addr->sin_port = htons(port);
+ tgt_addr->sin_family = AF_INET;
+
+ return true;
+}
+
+/* Prepare Ipv6 Socket */
+bool prepare_sock6(struct sockaddr_in6 * tgt_addr6)
+{
+ struct addrinfo *addr_info;
+ memset(tgt_addr6, 0, sizeof(*tgt_addr6));
+
+ if ((addr_info = get_addr_info(IPV6)) == NULL) {
+ errlog("Erorr: Unable to get address info\n");
+ return false;
+ }
+
+ tgt_addr6->sin6_addr = ((struct sockaddr_in6 *)addr_info->ai_addr)->sin6_addr;
+ tgt_addr6->sin6_port = htons(port);
+ tgt_addr6->sin6_family = AF_INET6;
+
+ return true;
+}
+
+/* Set TTY to raw mode */
+bool set_tty(int fd)
+{
+ struct termios tty_state;
+
+ if (tcgetattr(fd, &tty_state) < 0) {
+ return false;
+ }
+
+ if (tcgetattr(fd, &orig_tty_state) < 0) // Save original settings
+ {
+ return false;
+ }
+
+ if (cfsetspeed(&tty_state, baud_rate) == -1) {
+ errlog("Error: Baud Rate not set - %m\n");
+ return false;
+ }
+
+ tty_state.c_lflag &= ~(ICANON | IEXTEN | ISIG | ECHO);
+ tty_state.c_iflag &= ~(IGNCR | ICRNL | INPCK | ISTRIP | IXON | BRKINT);
+ tty_state.c_iflag |= (IGNCR | ICRNL);
+ tty_state.c_oflag &= ~OPOST;
+ tty_state.c_cflag |= CS8;
+
+ tty_state.c_cc[VMIN] = 1;
+ tty_state.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSAFLUSH, &tty_state) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Create a pseudo terminal for other process to use (as this program is using up the actual TTY) */
+int create_pseudo_tty()
+{
+ int amaster, aslave;
+ int flags;
+
+ if (openpty(&amaster, &aslave, NULL, NULL, NULL) == -1) {
+ errlog("Error: Openpty failed - %m\n");
+ return -1;
+ }
+
+ /* Set to non blocking mode */
+ flags = fcntl(amaster, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(amaster, F_SETFL, flags);
+
+ FILE *pseudo_save_file = fopen(pseudo_tty_save_file, "w+");
+ if (!pseudo_save_file) {
+ errlog("Error: Unable to open the pseudo info file - %m\n");
+ return -1;
+ }
+ /* Save the name of the created pseudo tty in a text file for other processes to use */
+ if (fprintf(pseudo_save_file, "%s\n", ttyname(aslave)) == -1) {
+ errlog("Error writing to the pseudo info file\n");
+ fclose(pseudo_save_file);
+ return -1;
+ }
+ fclose(pseudo_save_file);
+
+ if (set_tty(aslave) == -1) {
+ errlog("Error: Slave TTY not set properly\n");
+ return -1;
+ }
+
+ return amaster;
+}
+
+/* Prepare logs from the read_buf and send them to the server */
+bool prepare_log_send(char *read_buf, int max_read, int fd_socket)
+{
+ size_t buff_index = 0; // Index for the read_buf string
+
+ static char line[LINE_LEN] = { 0 };
+ static size_t line_index = 0; // Index for the line string
+
+ char msg[MSG_LEN] = { 0 }; // Message to be sent to the server
+
+ /* Kernel Version */
+ static char kernel_version[KERNEL_VERSION_LEN] = "dummy_kernel";
+ static int kernel_search_pos = 0;
+
+ while (buff_index < max_read && read_buf[buff_index] != '\0') {
+ if (read_buf[buff_index] == 'L') // Check if there is a possibility of new kernel version
+ {
+ kernel_search_pos = line_index;
+ }
+
+ /* Send the log when a line is read */
+ if (read_buf[buff_index] == '\n') {
+ if (kernel_search_pos > 0) {
+ if (strncmp(line + kernel_search_pos, "Linux version ", kernel_search_len) == 0) {
+ sscanf(line + kernel_search_pos + kernel_search_len, "%s", kernel_version);
+ }
+ kernel_search_pos = 0;
+ }
+
+ /* Prepare the message */
+ memset(msg, 0, sizeof(msg));
+ if (snprintf(msg, sizeof(msg), "%s %s %s %s", "kernel:", kernel_version, "- msg", line) < 0) {
+ errlog("Error copying the message - %m\n");
+ return false;
+ }
+
+ /* Send message to the server */
+ if (write(fd_socket, msg, strlen(msg)) < 0) {
+ errlog("Error: Write to socket failed - %m\n");
+ return false;
+ }
+
+ /* Reset the line buffer */
+ line_index = 0;
+ memset(line, 0, sizeof(line));
+
+ buff_index++;
+ continue;
+ }
+
+ /* If line is too big, send only the first few bytes and discard others. */
+ if (line_index >= sizeof(line)) {
+ line[line_index - 1] = 0;
+ buff_index++;
+ continue;
+ }
+
+ line[line_index++] = read_buf[buff_index++];
+ }
+
+ return true;
+}
+
+/* Read text from the TTY and send to send as logs */
+bool read_send(int fd_tty, int fd_socket)
+{
+ char read_buf[LINE_LEN] = { 0 }; // Buffer to be read into.
+ int read_size = 0;
+ fd_set readset;
+ int sel;
+ int fdmax;
+
+ int pseudo_tty = create_pseudo_tty();
+
+ if (pseudo_tty == -1) {
+ errlog("Error: Cannot create a psuedo terminal\n");
+ return false;
+ }
+
+ fdmax = MAX(fd_tty, pseudo_tty);
+
+ while (!kill_received) {
+ do {
+ FD_ZERO(&readset);
+ FD_SET(fd_tty, &readset);
+ FD_SET(pseudo_tty, &readset);
+
+ sel = select(fdmax + 1, &readset, NULL, NULL, NULL);
+ }
+ while (sel == -1 && errno == EINTR && !kill_received);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ if (FD_ISSET(fd_tty, &readset)) {
+ read_size = read(fd_tty, read_buf, sizeof(read_buf) - 1);
+
+ if (read_size == 0) {
+ continue;
+ }
+ if (read_size < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
+ errlog("Error: Read from tty failed - %m\n");
+ return false;
+ }
+
+ /* Send the read data to the pseudo terminal */
+ if (write(pseudo_tty, read_buf, read_size) < 0) {
+ if (errno == EAGAIN) // Output buffer full - flush it.
+ {
+ tcflush(pseudo_tty, TCIOFLUSH);
+ continue;
+ }
+
+ errlog("Error: Write to pseudo tty failed - %m\n");
+ return false;
+ }
+
+ /* Prepare log message and send to the server */
+ if (!prepare_log_send(read_buf, sizeof(read_buf), fd_socket)) {
+ errlog("Error: Sending log failed - %m\n");
+ return false;
+ }
+ }
+ /*if (FD_ISSET(fd_tty, &readset)) */
+ if (kill_received) {
+ break;
+ }
+
+ /* Check if there is an data in the pseudo terminal's buffer */
+ if (FD_ISSET(pseudo_tty, &readset)) {
+ read_size = read(pseudo_tty, read_buf, sizeof(read_buf) - 1);
+
+ if (read_size == 0) {
+ continue;
+ }
+ if (read_size < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
+ errlog("Error: Read from pseudo tty failed - %m\n");
+ return false;
+ }
+
+ if (write(fd_tty, read_buf, read_size) < 0) {
+ if (errno == EAGAIN) // Output buffer full - flush it.
+ {
+ tcflush(fd_tty, TCIOFLUSH);
+ continue;
+ }
+
+ errlog("Error: Write to tty failed - %m\n");
+ return false;
+ }
+ } /*if (FD_ISSET(pseudo_tty,&readset)) */
+ } /*while (!kill_received) */
+
+ return true;
+}
+
+void cleanup()
+{
+ remove(pseudo_tty_save_file);
+ tcsetattr(fd_tty, TCSAFLUSH, &orig_tty_state); //Restore original settings
+ close(fd_tty);
+ close(fd_soc);
+ fclose(error_file);
+}
+
+void sig_kill(int signum)
+{
+ kill_received = true;
+}
+
+void register_kill()
+{
+ struct sigaction sigact;
+ sigset_t sigset;
+
+ sigemptyset(&sigset);
+ memset(&sigact, 0, sizeof sigact);
+ sigact.sa_handler = sig_kill;
+ sigact.sa_mask = sigset;
+
+ sigaction(SIGHUP, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGPIPE, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+ sigaction(SIGKILL, &sigact, NULL);
+ sigaction(SIGABRT, &sigact, NULL);
+}
+
+void usage(char *prog_name)
+{
+ printf("Usage:\n");
+ printf("\t%s TTY ip_version(4 or 6) hostname port [baud rate (like 57600)]\n", prog_name);
+ printf("\t%s -h : For this help\n", prog_name);
+ printf("Example:\n\t./bmc-log /dev/ttyS1 4 netcons.any.facebook.com 1514\n");
+ printf("\tOR\n\t./bmc-log /dev/ttyS1 6 netcons6.any.facebook.com 1514 57600\n");
+}
+
+bool parse_user_input(int nargs, char **args, char *read_tty, int read_tty_size, int *ip_version)
+{
+ if (nargs < 5) {
+ if ((nargs > 1) && ((strcmp(args[1], "-h") == 0) || (strcmp(args[1], "--help") == 0))) {
+ usage(args[0]);
+ return false; // Not an error but returning -1 for the main function to return
+ }
+ fprintf(stderr, "Error: Invalid number of arguments\n");
+ usage(args[0]);
+ return false;
+ }
+
+ if (strlen(args[1]) > read_tty_size) {
+ fprintf(stderr, "Error: TTY too long\n");
+ usage(args[0]);
+ return false;
+ }
+
+ /* TTT to read the logs from */
+ strncpy(read_tty, args[1], read_tty_size);
+
+ /* IP Version, IP Address and Port of the netcons server */
+ *ip_version = atoi(args[2]);
+ if (*ip_version != IPV4 && *ip_version != IPV6) {
+ fprintf(stderr, "Error: Invalid IP Version input\n");
+ usage(args[0]);
+ return false;
+ }
+
+ hostname = args[3];
+ port = atoi(args[4]);
+
+ baud_rate = B57600;
+ if (nargs == 6)
+ baud_rate = atoi(args[5]);
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ char read_tty[TTY_LEN] = { 0 };
+ int ip_version;
+ int socket_domain = AF_UNSPEC;
+ char cmd[COMMAND_LEN] = { 0 };
+
+ /* Open the error log file */
+ error_file = fopen(error_log_file, "a+");
+ if (!error_file) {
+ printf("Error: Unable to open log file - %m\n");
+ return 1;
+ }
+
+ /* Register actions upon interrupts */
+ register_kill();
+
+ /* Parse the user input */
+ if (!parse_user_input(argc, argv, read_tty, sizeof(read_tty), &ip_version)) {
+ return 2;
+ }
+
+ snprintf(cmd, sizeof(cmd), "%s %s", uS_console, "connect");
+ if (system(cmd) == -1) {
+ errlog("Error: Unable to connect to the micro-server\n");
+ return 3;
+ }
+
+ /* Create a socket to communicate with the netcons server */
+ socket_domain = (ip_version == IPV4) ? AF_INET : AF_INET6;
+ fd_soc = socket(socket_domain, SOCK_DGRAM, 0);
+ if (fd_soc == -1) {
+ errlog("Error: Socket creation failed - %m\n");
+ return 4;
+ }
+
+ if (ip_version == IPV4) { /* IPv4 */
+ struct sockaddr_in tgt_addr;
+ if (!prepare_sock(&tgt_addr)) {
+ close(fd_soc);
+ errlog("Error: Socket not valid\n");
+ return 5;
+ }
+
+ if (connect(fd_soc, (struct sockaddr *)&tgt_addr, sizeof(tgt_addr)) == -1) {
+ close(fd_soc);
+ errlog("Error: Socket connection failed - %m\n");
+ return 6;
+ }
+
+ } else { /* IPv6 */
+
+ struct sockaddr_in6 tgt_addr6;
+ if (!prepare_sock6(&tgt_addr6)) {
+ close(fd_soc);
+ errlog("Error: Socket not valid\n");
+ return 5;
+ }
+
+ if (connect(fd_soc, (struct sockaddr *)&tgt_addr6, sizeof(tgt_addr6)) == -1) {
+ close(fd_soc);
+ errlog("Error: Socket connection failed - %m\n");
+ return 6;
+ }
+ }
+
+ /* TTY Operations */
+ if ((fd_tty = open(read_tty, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) {
+ close(fd_soc);
+ errlog("Error: Serial Port %s open failed - %m\n", read_tty);
+ return 7;
+ }
+
+ if (!set_tty(fd_tty)) {
+ errlog("Error: tty not set properly\n");
+ cleanup();
+ return 8;
+ }
+
+ /* Read, prepare and send the logs */
+ if (!read_send(fd_tty, fd_soc)) {
+ errlog("Error: Sending logs failed\n");
+ cleanup();
+ return 9;
+ }
+
+ cleanup();
+ return 0;
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h
new file mode 100644
index 0000000..5795e6a
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef BMC_LOG_H_
+#define BMC_LOG_H_
+
+/* IP Version */
+#define IPV4 (4)
+#define IPV6 (6)
+
+/* Search string for the kernel version */
+#define KERNEL_SEARCH_STR "Linux version "
+
+/* Size constants */
+#define TIME_FORMAT_SIZE (100)
+#define MAX_LOG_FILE_SIZE (1024*1024*5) //5MB
+#define TTY_LEN (50)
+#define LINE_LEN (257)
+#define MSG_LEN (1025)
+#define COMMAND_LEN (100)
+#define KERNEL_VERSION_LEN (100)
+
+static char *uS_console = "/usr/local/fbpackages/utils/us_console.sh";
+
+static char *error_log_file = "/var/log/bmc-log";
+
+static char *pseudo_tty_save_file = "/etc/us_pseudo_tty";
+
+static int kernel_search_len = sizeof(KERNEL_SEARCH_STR) - 1;
+
+#endif
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh
new file mode 100755
index 0000000..00bf63c
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+#
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+### BEGIN INIT INFO
+# Provides: bmc-log
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop:
+# Short-Description: Collect micro-server kernel logs through serial port
+### END INIT INFO
+
+. /etc/default/bmc-log
+. /etc/init.d/functions
+
+DAEMON=/usr/sbin/bmc-log
+NAME=bmc-log
+DESC="Micro-Server log collection"
+
+TTY=${US_TTY:-/dev/ttyS1}
+IP=${LOG_SERVER_IP_VERSION:-4}
+LOG_SERVER=${LOG_SERVER_NAME:-}
+PORT=${LOG_SERVER_PORT:-}
+BAUD_RATE=${TTY_BAUD_RATE:-}
+
+if [ -z "$LOG_SERVER" ] || [ -z "$PORT" ]
+then
+ echo "Error: Server and/or port not set"
+ exit 0
+fi
+
+
+ACTION="$1"
+
+case "$ACTION" in
+ start)
+ echo -e "Starting $DESC"
+ $DAEMON $TTY $IP $LOG_SERVER $PORT $BAUD_RATE
+ ;;
+ stop)
+ echo -e "Stopping $DESC: "
+ start-stop-daemon --stop --quiet --exec $DAEMON
+ ;;
+ restart|force-reload)
+ echo -e "Restarting $DESC: "
+ start-stop-daemon --stop --quiet --exec $DAEMON
+ sleep 1
+ $DAEMON $TTY $IP $LOG_SERVER $PORT $BAUD_RATE
+ ;;
+ status)
+ stat $DAEMON
+ exit $?
+ ;;
+ *)
+ N=${0##*/}
+ N=${N#[SK]??}
+ echo "Usage: $N {start|stop|status|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh
index 0cbdb24..146a787 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl/setup-fan.sh
@@ -2,6 +2,22 @@
#
# Copyright 2014-present Facebook. All Rights Reserved.
#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
### BEGIN INIT INFO
# Provides: setup-fan
# Required-Start: board-id
@@ -11,7 +27,7 @@
# Short-Description: Set fan speed
### END INIT INFO
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# Enable the isolation buffer
wedge_iso_buf_enable
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend
new file mode 100644
index 0000000..ef2932e
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fan-ctrl/fan-ctrl_0.1.bbappend
@@ -0,0 +1,64 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+DEPENDS_append = "libwedge-eeprom update-rc.d-native"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI += "file://get_fan_speed.sh \
+ file://init_pwm.sh \
+ file://set_fan_speed.sh \
+ file://setup-fan.sh \
+ "
+
+S = "${WORKDIR}"
+
+binfiles += "get_fan_speed.sh \
+ init_pwm.sh \
+ set_fan_speed.sh \
+ "
+
+LDFLAGS_append = " -lwedge_eeprom"
+CXXFLAGS_prepend = "-DCONFIG_WEDGE "
+
+pkgdir = "fan_ctrl"
+
+do_install() {
+ dst="${D}/usr/local/fbpackages/${pkgdir}"
+ bin="${D}/usr/local/bin"
+ install -d $dst
+ install -d $bin
+ for f in ${binfiles}; do
+ install -m 755 $f ${dst}/$f
+ ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f
+ done
+ for f in ${otherfiles}; do
+ install -m 644 $f ${dst}/$f
+ done
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${sysconfdir}/rcS.d
+ install -m 755 setup-fan.sh ${D}${sysconfdir}/init.d/setup-fan.sh
+ update-rc.d -r ${D} setup-fan.sh start 91 S .
+}
+
+FBPACKAGEDIR = "${prefix}/local/fbpackages"
+
+FILES_${PN} = "${FBPACKAGEDIR}/fan_ctrl ${prefix}/local/bin ${sysconfdir} "
+
+# Inhibit complaints about .debug directories for the fand binary:
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INHIBIT_PACKAGE_STRIP = "1"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile
index 74ce8f3..2f27a8c 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/alert_control/Makefile
@@ -1,8 +1,24 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
lib: libalert_control.so
libalert_control.so: alert_control.c
- $(CC) $(CCFLAGS) -fPIC -c -o alert_control.o alert_control.c
+ $(CC) $(CFLAGS) -fPIC -c -o alert_control.o alert_control.c
$(CC) -shared -o libalert_control.so alert_control.o -lc
.PHONY: clean
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile
index 8cb69e7..369819c 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/files/ipmi/Makefile
@@ -1,8 +1,24 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
lib: libipmi.so
libipmi.so: ipmi.c
- $(CC) $(CCFLAGS) -fPIC -c -o ipmi.o ipmi.c
+ $(CC) $(CFLAGS) -fPIC -c -o ipmi.o ipmi.c
$(CC) -shared -o libipmi.so ipmi.o -lc
.PHONY: clean
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb
index 2ae4ea7..ec02d04 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libalert-control_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Wedge Alert Control Library"
DESCRIPTION = "library for Wedge Alert Control"
SECTION = "base"
@@ -20,5 +35,4 @@ do_install() {
}
FILES_${PN} = "${libdir}/libalert_control.so"
-FILES_${PN}-dbg = "${libdir}/.debug"
FILES_${PN}-dev = "${includedir}/facebook/alert_control.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb
index 0b6f3d3..83292be 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/fblibs/libipmi_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Wedge IPMI Client Library"
DESCRIPTION = "library for Wedge IPMI Client"
SECTION = "base"
@@ -21,5 +36,4 @@ do_install() {
}
FILES_${PN} = "${libdir}/libipmi.so"
-FILES_${PN}-dbg = "${libdir}/.debug"
FILES_${PN}-dev = "${includedir}/facebook/ipmi.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py
new file mode 100644
index 0000000..514a06b
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6.py
@@ -0,0 +1,318 @@
+# Copyright 2004-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+import subprocess
+import struct
+import sys
+
+
+AT93C46 = 'at93c46'
+AT93C56 = 'at93c56'
+AT93C66 = 'at93c66'
+AT93C86 = 'at93c86'
+
+
+class VerboseLogger:
+ def __init__(self, verbose=False):
+ self.verbose = verbose
+
+ def _verbose_print(self, caption, bytestream=None):
+ '''
+ Print a bytestream to stdout if verbose is enabled.
+ '''
+ if self.verbose:
+ if bytestream is not None:
+ sys.stderr.write(
+ "{}: {}\n" .format(
+ caption, " ".join(['{:02X}'.format(ord(x))
+ for x in bytestream])))
+ else:
+ sys.stderr.write("{}\n".format(caption))
+
+
+class AT93CX6SPI(VerboseLogger):
+ '''The class to access AT93CX6 through SPI intf'''
+ SPI_CMD = 'spi-bb'
+
+ def __init__(self, bus_width, gpio_cs, gpio_ck, gpio_do, gpio_di,
+ model, verbose=False):
+ addr_bits_map = {
+ AT93C46 : 6,
+ AT93C56 : 8,
+ AT93C66 : 8,
+ AT93C86 : 10,
+ }
+ if bus_width != 8 and bus_width != 16:
+ raise Exception("Invalid bus width for AT93CX6!")
+ if model not in addr_bits_map:
+ raise Exception("Invalid model '%s'" % model)
+
+ self.bus_width = bus_width
+ self.gpio_cs = gpio_cs
+ self.gpio_ck = gpio_ck
+ self.gpio_do = gpio_do
+ self.gpio_di = gpio_di
+ self.verbose = verbose
+
+ self.addr_bits = addr_bits_map[model] \
+ + (0 if self.bus_width == 16 else 1)
+ self.addr_mask = (1 << self.addr_bits) - 1
+
+ def __shift(self, bytestream, value):
+ '''
+ Shift an entire byte stream by value bits.
+ '''
+ binary = "".join(['{:08b}'.format(ord(x)) for x in bytestream])
+ if value > 0:
+ binary = binary[value:] + '0' * value
+ else:
+ binary = '0' * (-value) + binary[:value]
+ return "".join([chr(int(binary[x:x+8],2))
+ for x in range(0, len(binary), 8)])
+
+ def __io(self, op, addr, data=None):
+ '''
+ Perform an IO operation against the EEPROM
+ '''
+ write_bits = self.addr_bits + 3
+ if data is not None:
+ # If giving data, we are doing a write command so
+ # no need to read any data.
+ write_bits = write_bits + self.bus_width
+ read_bits = 0
+ else:
+ # If not giving data, we are doing either a read
+ # command or a set command, so read the result.
+ # We pad with an extra bit due to a dummy bit introduced
+ # by a delay for address decoding on chip.
+ read_bits = self.addr_bits + 4 + self.bus_width
+
+ # Format the command itself
+ instruction = addr & self.addr_mask
+ instruction = instruction | ((0x4 | (op & 0x3)) << self.addr_bits)
+ if data is not None:
+ if self.bus_width == 16:
+ write_data = struct.pack(">HH", instruction, data & 0xFFFF)
+ else:
+ write_data = struct.pack(">HB", instruction, data & 0xFF)
+ else:
+ write_data = struct.pack(">H", instruction)
+ write_data = self.__shift(write_data, 16 - (self.addr_bits + 3))
+
+ self._verbose_print("Write data", write_data)
+
+ # Run the command with the bitbang driver
+ if read_bits > 0:
+ data_portion = "-r {} -w {}".format(read_bits, write_bits)
+ else:
+ data_portion = "-w {}".format(write_bits)
+
+ cmd = "{} -s {} -c {} -o {} -i {} -b {}".format(
+ self.SPI_CMD, self.gpio_cs, self.gpio_ck, self.gpio_do,
+ self.gpio_di, data_portion
+ )
+
+ self._verbose_print("Command: {}".format(cmd))
+
+ out = subprocess.Popen(cmd.split(),
+ stdout=subprocess.PIPE,
+ stdin = subprocess.PIPE)\
+ .communicate(input=write_data)
+
+ # Format the response
+ read_data = self.__shift(out[0], self.addr_bits + 4)
+ if self.bus_width == 16:
+ read_data = read_data[:2]
+ self._verbose_print("Read data", read_data)
+ return struct.unpack(">H", read_data)[0]
+ else:
+ read_data = read_data[:1]
+ self._verbose_print("Read data", read_data)
+ return struct.unpack(">B", read_data)[0]
+
+ def read(self, addr):
+ return self.__io(0x2, addr)
+
+ def ewen(self):
+ self.__io(0x0, 0x3 << (self.addr_bits - 2))
+
+ def erase(self, addr):
+ self.__io(0x3, addr)
+
+ def write(self, addr, data):
+ self.__io(0x1, addr, data)
+
+ def eral(self):
+ self.__io(0x0, 0x2 << (self.addr_bits - 2))
+
+ def wral(self, data):
+ self.__io(0x0, 0x1 << (self.addr_bits - 2), data)
+
+ def ewds(self):
+ self.__io(0x0, 0x0)
+
+
+class AT93CX6(VerboseLogger):
+ '''
+ The class which handles accessing memory on the AT93CX6 chip.
+ '''
+
+ def __init__(self, bus_width, gpio_cs, gpio_ck, gpio_do, gpio_di,
+ byte_swap, model=AT93C46, verbose=False):
+ mem_size_map = {
+ # in bytes
+ AT93C46 : 128,
+ AT93C56 : 256,
+ AT93C66 : 512,
+ AT93C86 : 2048,
+ }
+ self.bus_width = bus_width
+ self.verbose = verbose
+ self.byte_swap = byte_swap
+ self.model = model
+ self.memory_size = mem_size_map[model]
+
+ self.spi = AT93CX6SPI(bus_width=bus_width, gpio_cs=gpio_cs,
+ gpio_ck=gpio_ck, gpio_do=gpio_do,
+ gpio_di=gpio_di, model=model,
+ verbose=verbose)
+
+ def __swap(self, value):
+ '''
+ Swap bytes for a 16-bit integer if instructed to do so.
+ '''
+ if self.bus_width == 16:
+ if self.byte_swap:
+ return ((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)
+ else:
+ return value
+ else:
+ return value
+
+ def get_memory_size(self):
+ return self.memory_size
+
+ def erase(self, offset=None, limit=None):
+ '''
+ Erase the chip.
+ '''
+ if offset is None:
+ offset = 0
+ if limit is None:
+ limit = self.memory_size
+
+ if offset < 0 or offset + limit > self.memory_size:
+ raise Exception("Erase would be out of bounds!")
+ if self.bus_width == 16 and \
+ ((offset & 1) != 0 or ((offset + limit) & 1) != 0):
+ raise Exception("Erase can't start or end on odd boundary in "
+ "16-bit mode!")
+
+ if offset == 0 and limit == self.memory_size:
+ # Special case when we are erasing the entire chip
+ self.spi.ewen()
+ self.spi.eral()
+ self.spi.ewds()
+
+ self._verbose_print("Erased entire chip")
+ else:
+ # Regular case
+ if self.bus_width == 16:
+ real_offset = offset / 2
+ real_limit = limit / 2
+ else:
+ real_offset = offset
+ real_limit = limit
+
+ self.spi.ewen()
+ for addr in range(real_offset, real_offset + real_limit):
+ self.spi.erase(addr)
+ self.spi.ewds()
+
+ self._verbose_print("Erased {} bytes from offset {}"
+ .format(limit, offset))
+
+ def read(self, offset=None, limit=None):
+ '''
+ Read the chip into a memory buffer.
+ '''
+ if offset is None:
+ offset = 0
+ if limit is None:
+ limit = self.memory_size
+
+ if offset < 0 or offset + limit > self.memory_size:
+ raise Exception("Read would be out of bounds!")
+ if self.bus_width == 16 and \
+ ((offset & 1) != 0 or ((offset + limit) & 1) != 0):
+ raise Exception("Read can't start or end on odd boundary in 16-bit "
+ "mode!")
+
+ output = ""
+ if self.bus_width == 16:
+ real_offset = offset / 2
+ real_limit = limit / 2
+ pack_instruction = "=H"
+ else:
+ real_offset = offset
+ real_offset
+ pack_instruction = "=B"
+
+ for addr in range(real_offset, real_offset + real_limit):
+ output = output + struct.pack(pack_instruction,
+ self.__swap(self.spi.read(addr)))
+
+ self._verbose_print("Read {} bytes from offset {}".format(limit, offset)
+ , output)
+
+ return output
+
+ def write(self, data, offset=None):
+ '''
+ Write a memory buffer to the chip.
+ '''
+ if offset is None:
+ offset = 0
+
+ if offset < 0 or offset + len(data) > self.memory_size:
+ raise Exception("Write would be out of bounds!")
+ if self.bus_width == 16 and \
+ ((offset & 1) != 0 or ((offset + len(data)) & 1) != 0):
+ raise Exception("Write can't start or end on odd boundary in "
+ "16-bit mode!")
+
+ if self.bus_width == 16:
+ offset_divisor = 2
+ pack_instruction = "=H"
+ else:
+ offset_divisor = 1
+ pack_instruction = "=B"
+
+ self.spi.ewen()
+ for addr in range(offset, offset + len(data), offset_divisor):
+ actual_addr = addr / offset_divisor
+ value = self.__swap(struct.unpack(
+ pack_instruction, data[(addr - offset):(addr - offset)
+ + offset_divisor])[0])
+
+ self.spi.erase(actual_addr)
+ self.spi.write(actual_addr, value)
+ self.spi.ewds()
+
+ self._verbose_print("Wrote {} bytes from offset {}"
+ .format(len(data), offset), data)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py
new file mode 100755
index 0000000..8ae7664
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/at93cx6_util.py
@@ -0,0 +1,223 @@
+#!/usr/bin/python -S
+# Copyright 2004-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+
+from argparse import ArgumentParser
+import at93cx6
+import sys
+
+
+def get_raw(args):
+ return at93cx6.AT93CX6SPI(
+ args.bus_width, args.cs, args.clk, args.mosi, args.miso,
+ args.model, args.verbose)
+
+def get_chip(args):
+ return at93cx6.AT93CX6(
+ args.bus_width, args.cs, args.clk, args.mosi, args.miso,
+ args.byte_swap if hasattr(args, 'byte_swap') else None,
+ args.model, args.verbose)
+
+def model_parser(ap):
+ # Default, based on currenct HW configuration
+ MODEL_DEFAULT = at93cx6.AT93C46
+
+ ap.add_argument('--model', default=at93cx6.AT93C46,
+ choices=[at93cx6.AT93C46, at93cx6.AT93C56,
+ at93cx6.AT93C66, at93cx6.AT93C86],
+ help='The chip model (default: %(default)s)')
+
+def access_parser(ap):
+ # Default, based on currenct HW configuration
+ SPI_CS_DEFAULT = 68
+ SPI_CLK_DEFAULT = 69
+ SPI_MOSI_DEFAULT = 70
+ SPI_MISO_DEFAULT = 71
+
+ spi_group = ap.add_argument_group('SPI Access')
+ spi_group.add_argument('--cs', type=int, default=SPI_CS_DEFAULT,
+ help='The GPIO number for SPI CS pin '
+ '(default: %(default)s)')
+ spi_group.add_argument('--clk', type=int, default=SPI_CLK_DEFAULT,
+ help='The GPIO number for SPI CLK pin '
+ '(default: %(default)s)')
+ spi_group.add_argument('--mosi', type=int, default=SPI_MOSI_DEFAULT,
+ help='The GPIO number for SPI MOSI pin '
+ '(default: %(default)s)')
+ spi_group.add_argument('--miso', type=int, default=SPI_MISO_DEFAULT,
+ help='The GPIO number for SPI MISO pin '
+ '(default: %(default)s)')
+
+def bus_width_parser(ap):
+ # Default, based on currenct HW configuration
+ AT83C46_BUS_WIDTH = 16
+
+ bus_group = ap.add_argument_group('Bus Width')
+ bus_group.add_argument('--bus-width', type=int, default=AT83C46_BUS_WIDTH,
+ help='The configured bus width '
+ '(default: %(default)s)')
+
+def read_raw(args):
+ raw = get_raw(args)
+ val = raw.read(args.address)
+
+ if args.int:
+ print "{}".format(val)
+ else:
+ if args.bus_width == 16:
+ print "0x{:04X}".format(val)
+ else:
+ print "0x{:02X}".format(val)
+
+def write_raw(args):
+ if args.value[:2] == "0x":
+ value = int(args.value, 16)
+ else:
+ value = int(args.value)
+
+ raw = get_raw(args)
+ raw.ewen()
+ raw.erase(args.address)
+ raw.write(args.address, value)
+ raw.ewds()
+
+def erase_raw(args):
+ raw = get_raw(args)
+ raw.ewen()
+ raw.erase(args.address)
+ raw.ewds()
+
+def raw_subparser(subparsers):
+ raw_parser = subparsers.add_parser(
+ 'raw', help='Raw memory access')
+ raw_sub = raw_parser.add_subparsers()
+
+ read_parser = raw_sub.add_parser(
+ 'read', help='Read a single memory address')
+ read_parser.add_argument(
+ 'address', type=int, help='The memory address')
+ read_parser.add_argument('--int', action='store_true',
+ help='Display output as an integer')
+ read_parser.set_defaults(func=read_raw)
+
+ write_parser = raw_sub.add_parser(
+ 'write', help='Write a single memory address')
+ write_parser.add_argument(
+ 'address', type=int, help='The memory address')
+ write_parser.add_argument(
+ 'value', type=str, help='The value to write, either integer or hex')
+ write_parser.set_defaults(func=write_raw)
+
+ erase_parser = raw_sub.add_parser(
+ 'erase', help='Erase a single memory address')
+ erase_parser.add_argument('address', type=int, help='The memory address')
+ erase_parser.set_defaults(func=erase_raw)
+
+def read_chip(args):
+ chip = get_chip(args)
+ data = chip.read(args.start, args.length)
+
+ if args.file is None:
+ sys.stdout.write(data)
+ else:
+ with open(args.file, "wb") as fp:
+ fp.write(data)
+
+def write_chip(args):
+ chip = get_chip(args)
+
+ # Either way, limit reads to the size of the chip
+ if args.file is None:
+ data = sys.stdin.read(chip.get_memory_size())
+ else:
+ with open(args.file, "rb") as fp:
+ data = fp.read(chip.get_memory_size())
+
+ if args.length is not None:
+ # Make sure length is correct
+ if len(data) < args.length:
+ data = data + '\x00' * (args.length - len(data))
+ if len(data) > args.length:
+ data = data[:args.length]
+
+ chip.write(data, args.start)
+
+def erase_chip(args):
+ chip = get_chip(args)
+ chip.erase(args.start, args.length)
+
+def chip_subparser(subparsers):
+ chip_parser = subparsers.add_parser('chip', help='Chip-level access')
+ chip_sub = chip_parser.add_subparsers()
+
+ read_parser = chip_sub.add_parser('read', help='Read from the chip')
+ read_parser.add_argument('--start', type=int,
+ help='The memory address to start at (default: 0)')
+ read_parser.add_argument('--length', type=int,
+ help='The number of bytes to read '
+ '(default: whole chip)')
+ read_parser.add_argument('--file', type=str,
+ help='File to operate on (default: stdout)')
+ read_parser.add_argument('--byte-swap', default=False, action='store_true',
+ help='Byte swap values for 16-bit reads/writes '
+ '(default: %(default)s)')
+ read_parser.set_defaults(func=read_chip)
+
+ write_parser = chip_sub.add_parser('write', help='Write to the chip')
+ write_parser.add_argument('--start', type=int,
+ help='The memory address to start at '
+ '(default: 0)')
+ write_parser.add_argument('--length', type=int,
+ help='The number of bytes to write '
+ '(default: file length)')
+ write_parser.add_argument('--file', type=str,
+ help='File to operate on (default: stdin)')
+ write_parser.add_argument('--byte-swap', default=False, action='store_true',
+ help='Byte swap values for 16-bit reads/writes '
+ '(default: %(default)s)')
+ write_parser.set_defaults(func=write_chip)
+
+ erase_parser = chip_sub.add_parser('erase', help='Erase the chip')
+ erase_parser.add_argument('--start', type=int,
+ help='The memory address to start at '
+ '(default: 0)')
+ erase_parser.add_argument('--length', type=int,
+ help='The number of bytes to erase '
+ '(default: whole chip)')
+ erase_parser.set_defaults(func=erase_chip)
+
+if __name__ == "__main__":
+ # General arguments
+ ap = ArgumentParser()
+ ap.add_argument('--verbose', action='store_true',
+ help='Print verbose debugging information')
+
+ # Model, SPI, and bus width arguments
+ model_parser(ap)
+ access_parser(ap)
+ bus_width_parser(ap)
+
+ # Functionality
+ subparsers = ap.add_subparsers()
+ raw_subparser(subparsers)
+ chip_subparser(subparsers)
+
+ # Command runner
+ args = ap.parse_args()
+ args.func(args)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py
index e1aba47..91d9a85 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396.py
@@ -16,10 +16,13 @@
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#
+from __future__ import print_function
+
import subprocess
import time
+
class Bcm5396MDIO:
'''The class to access BCM5396 through MDIO intf'''
MDIO_CMD = 'mdio-bb'
@@ -254,23 +257,35 @@ class Bcm5396SPI:
except Exception as e:
print(e)
+
class Bcm5396:
'''The class for BCM5396 Switch'''
MDIO_ACCESS = 0
SPI_ACCESS = 1
- def __init__(self, access, **kwargs):
+ def __init__(self, access, verbose=False, **kwargs):
+ self.verbose = verbose
if access == self.MDIO_ACCESS:
self.access = Bcm5396MDIO(**kwargs)
else:
self.access = Bcm5396SPI(**kwargs)
def write(self, page, reg, value, n_bytes):
+ if self.verbose:
+ print('WRITE {:2x} {:2x} {:2x} '.format(page, reg, n_bytes), end='')
+ bytes = '{:2x}'.format(value)
+ print([bytes[i:i+2] for i in range(0, len(bytes), 2)][-n_bytes:])
return self.access.write(page, reg, value, n_bytes)
def read(self, page, reg, n_bytes):
- return self.access.read(page, reg, n_bytes)
+ if self.verbose:
+ print('READ {:2x} {:2x} {:2x} '.format(page, reg, n_bytes), end='')
+ result = self.access.read(page, reg, n_bytes)
+ if self.verbose:
+ bytes = '{:2x}'.format(result)
+ print([bytes[i:i+2] for i in range(0, len(bytes), 2)][-n_bytes:])
+ return result
def __add_remove_vlan(self, add, vid, untag, fwd, spt):
VLAN_PAGE = 0x5
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py
index 1496412..0759b08 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/bcm5396_util.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python -tt
# Copyright 2004-present Facebook. All rights reserved.
#
# This program file is free software; you can redistribute it and/or modify it
@@ -29,9 +29,11 @@ def auto_int(x):
def get_bcm(args):
if args.spi:
return Bcm5396(Bcm5396.SPI_ACCESS, cs=args.cs, clk=args.clk,
- mosi=args.mosi, miso=args.miso)
+ mosi=args.mosi, miso=args.miso,
+ verbose=args.verbose)
else:
- return Bcm5396(Bcm5396.MDIO_ACCESS, mdc=args.mdc, mdio=args.mdio)
+ return Bcm5396(Bcm5396.MDIO_ACCESS, mdc=args.mdc, mdio=args.mdio,
+ verbose=args.verbose)
def read_register(args):
@@ -249,6 +251,10 @@ def access_parser(ap):
if __name__ == '__main__':
ap = ArgumentParser()
+ ap.add_argument('-v', '--verbose', action='store_true',
+ help='Dump the switch page, register, and value '
+ 'for each operation')
+
access_parser(ap)
subparsers = ap.add_subparsers()
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh
new file mode 100644
index 0000000..e4d34aa
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/board-utils.sh
@@ -0,0 +1,163 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+wedge_iso_buf_enable() {
+ # GPIOC2 (18) to low, SCU90[0] and SCU90[24] must be 0
+ devmem_clear_bit $(scu_addr 90) 0
+ devmem_clear_bit $(scu_addr 90) 24
+ gpio_set 18 0
+}
+
+wedge_iso_buf_disable() {
+ # GPIOC2 (18) to low, SCU90[0] and SCU90[24] must be 0
+ devmem_clear_bit $(scu_addr 90) 0
+ devmem_clear_bit $(scu_addr 90) 24
+ gpio_set 18 1
+}
+
+wedge_is_us_on() {
+ local val n retries prog
+ if [ $# -gt 0 ]; then
+ retries="$1"
+ else
+ retries=1
+ fi
+ if [ $# -gt 1 ]; then
+ prog="$2"
+ else
+ prog=""
+ fi
+ if [ $# -gt 2 ]; then
+ default=$3 # value 0 means defaul is 'ON'
+ else
+ default=1
+ fi
+ n=1
+ while true; do
+ val=$(cat /sys/class/i2c-adapter/i2c-4/4-0040/gpio_inputs 2>/dev/null)
+ if [ -n "$val" ]; then
+ break
+ fi
+ n=$((n+1))
+ if [ $n -gt $retries ]; then
+ echo -n " failed to read GPIO. "
+ return $default
+ break
+ fi
+ echo -n "$prog"
+ sleep 1
+ done
+ if [ "$((val & (0x1 << 14)))" != "0" ]; then
+ # powered on already
+ return 0
+ else
+ return 1
+ fi
+}
+
+
+# Return the board type, 'LC', 'FC-LEFT', 'FC-RIGHT', or, 'WEDGE'
+wedge_board_type() {
+ local pn
+ pn=$(/usr/bin/weutil 2> /dev/null | grep -i '^Location on Fabric:')
+ case "$pn" in
+ *LEFT*)
+ echo 'FC-LEFT'
+ ;;
+ *RIGHT*)
+ echo 'FC-RIGHT'
+ ;;
+ *LC*)
+ echo 'LC'
+ ;;
+ *)
+ echo 'WEDGE'
+ ;;
+ esac
+}
+
+# On FC,
+# board rev < 2:
+# FAB_SLOT_ID (GPIOU0), low == FC0; high == FC1
+# else:
+# FAB_SLOT_ID (GPIOU6), low == FC0; high == FC1
+## On LC, Wedge,
+# board rev < 3:
+# GPIOU0(ID0), GPIOU1(ID1), GPIOU2(ID2), GPIOU3(ID3)
+# else:
+# GPIOU6(ID0), GPIOU7(ID1), GPIOV0(ID2), GPIOV1(ID3)
+#
+# ID[2:0] ID3 Slot#
+# 000 0 1
+# 000 1 2
+# 001 0 3
+# 001 1 4
+# 010 0 5
+# 010 1 6
+# 011 0 7
+# 011 1 8
+
+wedge_slot_id() {
+ local type slot id3 id2 id1 id0 FC_CARD_BASE board_rev
+ FC_CARD_BASE=65
+ # need to check the board rev
+ board_rev=$(wedge_board_rev)
+ case "$1" in
+ FC-LEFT|FC-RIGHT)
+ # On FC
+ if [ $board_rev -lt 2 ]; then
+ slot=$(gpio_get U0)
+ else
+ slot=$(gpio_get U6)
+ fi
+ if [ "$1" = "FC-LEFT" ]; then
+ # fabric card left
+ slot=$((FC_CARD_BASE + slot * 2))
+ else
+ # fabric card right
+ slot=$((FC_CARD_BASE + slot * 2 + 1))
+ fi
+ ;;
+ *)
+ # either edge or LC
+ if [ $board_rev -lt 3 ]; then
+ id0=$(gpio_get U0)
+ id1=$(gpio_get U1)
+ id2=$(gpio_get U2)
+ id3=$(gpio_get U3)
+ else
+ id0=$(gpio_get U6)
+ id1=$(gpio_get U7)
+ id2=$(gpio_get V0)
+ id3=$(gpio_get V1)
+ fi
+ slot=$(((id2 * 4 + id1 * 2 + id0) * 2 + id3 + 1))
+ esac
+ echo "$slot"
+}
+
+# wedge_board_rev() is only valid after GPIO Y0, Y1, and Y2 are enabled
+wedge_board_rev() {
+ local val0 val1 val2
+ val0=$(cat /sys/class/gpio/gpio192/value 2>/dev/null)
+ val1=$(cat /sys/class/gpio/gpio193/value 2>/dev/null)
+ val2=$(cat /sys/class/gpio/gpio194/value 2>/dev/null)
+ echo $((val0 | (val1 << 1) | (val2 << 2)))
+}
+
+# Should we enable OOB interface or not
+wedge_should_enable_oob() {
+ board_rev=$(wedge_board_rev)
+ board_type=$(wedge_board_type)
+ case "$board_type" in
+ FC-LEFT|FC-RIGHT)
+ if [ $board_rev -lt 2 ]; then
+ return 0
+ fi
+ ;;
+ *)
+ if [ $board_rev -lt 3 ]; then
+ return 0
+ fi
+ ;;
+ esac
+ return -1
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf
index 2cf7a9a..8c7e74b 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/create_vlan_intf
@@ -21,7 +21,7 @@
# only care about 'eth0' and 'oob' intf
[ "$IFACE" != "eth0" ] && [ "$IFACE" != "oob" ] && exit 0
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
board=$(wedge_board_type)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh
index 1cdbcb6..f244bd0 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/eth0_mac_fixup.sh
@@ -29,13 +29,27 @@
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
+# get the MAC from EEPROM
mac=$(weutil 2>/dev/null | grep '^Local MAC' 2>/dev/null | cut -d' ' -f3 2>/dev/null)
+# get the MAC from u-boot environment
+ethaddr=$(fw_printenv ethaddr 2>/dev/null | cut -d'=' -f2 2>/dev/null)
+
+if [ -z "$mac" ] && [ -n "$ethaddr" ]; then
+ # no MAC from EEPROM, use the one from u-boot environment
+ mac="$ethaddr"
+fi
+
if [ -n "$mac" ]; then
ifconfig eth0 hw ether $mac
- # compare the 'ethaddr' from u-boot env
- ethaddr=$(fw_printenv ethaddr 2>/dev/null | cut -d'=' -f2 2>/dev/null)
- if [ "$ethaddr" != "$mac" ]; then
- fw_setenv "ethaddr" "$mac"
- fi
+else
+ # no MAC from either EEPROM or u-boot environment
+ mac=$(ifconfig eth0 2>/dev/null |grep HWaddr 2>/dev/null |awk '{ print $5 }')
+
+fi
+
+if [ "$ethaddr" != "$mac" ]; then
+ # set the MAC from EEPROM or ifconfig back to u-boot environment so that u-boot
+ # can use it
+ fw_setenv "ethaddr" "$mac"
fi
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh
index c23349f..b653cb3 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/post_led.sh
@@ -24,7 +24,7 @@ usage() {
echo "Usage: $0 <value>"
}
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# Function to set the less significant hex digit
display_lower() {
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh
index 843b79a..ace3c6a 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power-on.sh
@@ -25,7 +25,7 @@
# Default-Stop:
# Short-Description: Power on micro-server
### END INIT INFO
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh
index 20206a1..066646e 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/power_led.sh
@@ -23,7 +23,7 @@ usage() {
exit -1
}
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh
index 7d1c2c6..c63ed10 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/reset_usb.sh
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301 USA
#
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
echo -n "Reset USB Switch ... "
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh
index 9f0b543..717bcd8 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup-gpio.sh
@@ -39,7 +39,7 @@
# When defined, the system doesn't reboot cleanly. We're still
# investigating this.
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# Set up to read the board revision pins, Y0, Y1, Y2
devmem_set_bit $(scu_addr 70) 19
@@ -182,8 +182,8 @@ devmem_set_bit $(scu_addr 70) 13
# GPIOQ5 is ISO_FLASH_HOLD, must be 1 to be out of reset
# To use GPIOQ4 and GPIOQ5, SCU90[27] must be 0
devmem_clear_bit $(scu_addr 90) 27
-gpio_set 134 1
-gpio_set 135 1
+gpio_set Q4 1
+gpio_set Q5 1
# GPIOD6 is ISO_FL_PRG_SEL, set it to 0 so that BMC does not have control
# on the EEPROM by default.
# To use GPIOD6, SCU90[1] must be 0, SCU8C[21] must be 0, and Strap[21] must be 0
@@ -244,31 +244,139 @@ board_type=$(wedge_board_type)
case "$board_type" in
FC-LEFT|FC-RIGHT)
# On FC
- # FAB_SLOT_ID is GPIOU0
- # PEER_FAB_PRSNT is GPIOU1
- devmem_set_bit $(scu_addr a0) 8
- devmem_set_bit $(scu_addr a0) 9
- gpio_export U0
- gpio_export U1
- # T2_POWER_UP is GPIOT6
- devmem_set_bit $(scu_addr a0) 6
- gpio_export T6
- # HS_FAULT_N is GPIOT7
- devmem_set_bit $(scu_addr a0) 7
- gpio_export T7
- if [ "$board_type" = "FC-LEFT" ]; then
- # GPIOE2 is CPU_EEPROM_SEL, on FC-LEFT
- devmem_clear_bit $(scu_addr 80) 18
- devmem_clear_bit $(scu_addr 8c) 13
- devmem_clear_bit $(scu_addr 70) 22
- gpio_export E2
- # GPIOA6 and GPIOA7 are MAC2 MDIO pins, we use them as
- # GPIO for bitbang driver
- devmem_clear_bit $(scu_addr 90) 2
- devmem_clear_bit $(scu_addr 80) 6
- devmem_clear_bit $(scu_addr 80) 7
- gpio_export A6
- gpio_export A7
+ if [ $board_rev -lt 2 ]; then
+ # EVT board
+ # FAB_SLOT_ID is GPIOU0
+ # PEER_FAB_PRSNT is GPIOU1
+ devmem_set_bit $(scu_addr a0) 8
+ devmem_set_bit $(scu_addr a0) 9
+ gpio_export U0
+ gpio_export U1
+ # T2_POWER_UP is GPIOT6
+ devmem_set_bit $(scu_addr a0) 6
+ gpio_export T6 T2_POWER_UP
+ # HS_FAULT_N is GPIOT7
+ devmem_set_bit $(scu_addr a0) 7
+ gpio_export T7
+ if [ "$board_type" = "FC-LEFT" ]; then
+ # GPIOE2 is CPU_EEPROM_SEL, on FC-LEFT
+ devmem_clear_bit $(scu_addr 80) 18
+ devmem_clear_bit $(scu_addr 8c) 13
+ devmem_clear_bit $(scu_addr 70) 22
+ gpio_export E2
+ # GPIOA6 and GPIOA7 are MAC2 MDIO pins, we use them as
+ # GPIO for bitbang driver
+ devmem_clear_bit $(scu_addr 90) 2
+ devmem_clear_bit $(scu_addr 80) 6
+ devmem_clear_bit $(scu_addr 80) 7
+ gpio_export A6
+ gpio_export A7
+ fi
+ else
+ # DVT board
+ if [ "$board_type" = "FC-LEFT" ]; then # Left FC
+ # BMC_SW_RST is GPIOL0, 16p switch
+ # SCU84[16] must be 0
+ devmem_clear_bit $(scu_addr 84) 16
+ gpio_set L0 1
+
+ # MDC|MDIO_CONT are GPIOR6 and GPIOR7, 16p switch
+ # SCU88[30:31] must be 0
+ devmem_clear_bit $(scu_addr 88) 30
+ devmem_clear_bit $(scu_addr 88) 31
+ gpio_set R6 1
+ gpio_set R7 1
+
+ # SWITCH_EEPROM1_WRT is GPIOE2, 16p switch EEPROM (U61)
+ # SCU80[18], SCU8C[13], and SCU70[22] must be 0
+ devmem_clear_bit $(scu_addr 80) 18
+ devmem_clear_bit $(scu_addr 8C) 13
+ devmem_clear_bit $(scu_addr 70) 22
+ gpio_export E2
+
+ # SPI bus to 16p switch EEPROM
+ # GPIOI4 <--> BMC_EEPROM1_SPI_SS
+ # GPIOI5 <--> BMC_EEPROM1_SPI_SCK
+ # GPIOI6 <--> BMC_EEPROM1_SPI_MOSI
+ # GPIOI7 <--> BMC_EEPROM1_SPI_MISO
+ # The EEPROM SPI clk does not match with the BMC SPI master.
+ # Have to configure these pins as GPIO to use with
+ # SPI bitbang driver.
+ # SCU70[13:12,5] must be 0
+ devmem_clear_bit $(scu_addr 70) 5
+ devmem_clear_bit $(scu_addr 70) 12
+ devmem_clear_bit $(scu_addr 70) 13
+ gpio_export I4
+ gpio_export I5
+ gpio_export I6
+ gpio_export I7
+
+ # BMC_PHY_RST is GPIOT0, Front Panel Port PHY on the 16p switch
+ # SCUA0[0] must be 1
+ devmem_set_bit $(scu_addr a0) 0
+ gpio_set T0 1
+
+ # BMC_5PORTSW_RST is GPIOT1, 5p switch
+ # SCUA0[1] must be 1
+ devmem_set_bit $(scu_addr a0) 1
+ gpio_set T1 1
+
+ # ISO_SWITCH1_MDC|MDIO are GPIOT4 and GPIOT5, 5p switch
+ # SCUA0[4:5] must be 1
+ devmem_set_bit $(scu_addr a0) 4
+ devmem_set_bit $(scu_addr a0) 5
+ gpio_set T4 1
+ gpio_set T5 1
+
+ # ISO_SWITCH_EEPROM2_WRT is GPIOV0, 5p switch EEPROM (U114)
+ # SCUA0[16] must be 1
+ devmem_set_bit $(scu_addr a0) 16
+ gpio_export V0
+
+ # SPI bus to 5p switch EEPROM (U114)
+ # GPIOI0 <--> ISO_BMC_EEPROM2_SPI_SS
+ # GPIOI1 <--> ISO_BMC_EEPROM2_SPI_SCK
+ # GPIOI2 <--> ISO_BMC_EEPROM2_SPI_MOSI
+ # GPIOI3 <--> ISO_BMC_EEPROM2_SPI_MISO
+ # The EEPROM SPI clk does not match with the BMC SPI master.
+ # Have to configure these pins as GPIO to use with
+ # SPI bitbang driver.
+ # SCU70[13] must be 0, has already been set when
+ # preparing for GPIOI4-GPIOI7
+ gpio_export I0
+ gpio_export I1
+ gpio_export I2
+ gpio_export I3
+
+ # BMC_PHYL_RST is GPIOF0, Left BMC PHY
+ # SCU80[24] must be 0
+ devmem_clear_bit $(scu_addr 80) 24
+ gpio_set F0 1
+ else # Right FC
+ # BMC_PHYR_RST is GPIOL1, Right BMC PHY
+ # SCU84[17] must be 0
+ devmem_clear_bit $(scu_addr 84) 17
+ gpio_set L1 1
+ fi
+ # T2_POWER_UP is GPIOU4
+ # SCUA0[12] must be 1
+ devmem_set_bit $(scu_addr a0) 12
+ gpio_export U4 T2_POWER_UP
+
+ # HS_FAULT_N is GPIOU5
+ # SCUA0[13] must be 1
+ devmem_set_bit $(scu_addr a0) 13
+ gpio_export U5
+
+ # FAB_SLOT_ID is GPIOU6
+ # SCUA0[14] must be 1
+ devmem_set_bit $(scu_addr a0) 14
+ gpio_export U6
+
+ # PEER_FAB_PRSNT is GPIOU7
+ # SCUA0[15] must be 1
+ devmem_set_bit $(scu_addr a0) 15
+ gpio_export U7
fi
;;
*)
@@ -289,7 +397,7 @@ case "$board_type" in
gpio_export U3
# T2_POWER_UP is GPIOT6
devmem_set_bit $(scu_addr a0) 6
- gpio_export T6
+ gpio_export T6 T2_POWER_UP
# HS_FAULT_N is GPIOT7
devmem_set_bit $(scu_addr a0) 7
gpio_export T7
@@ -307,7 +415,7 @@ case "$board_type" in
gpio_export V1
# T2_POWER_UP is GPIOU4
devmem_set_bit $(scu_addr a0) 12
- gpio_export U4
+ gpio_export U4 T2_POWER_UP
# HS_FAULT_N is GPIOU5
devmem_set_bit $(scu_addr a0) 13
gpio_export U5
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh
index 749fe65..1400464 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/setup_rov.sh
@@ -24,7 +24,7 @@
# outgoing voltage on the first buck converter, and bring T2 up out of
# reset.
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
# read the T2 ROV after the GPIOs are enabled
t2_rov() {
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh
index ccbdc61..2998c81 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/sol.sh
@@ -18,7 +18,14 @@
# Boston, MA 02110-1301 USA
#
-CONSOLE_SH=/usr/local/fbpackages/utils/us_console.sh
+CONSOLE_SH=/usr/local/bin/us_console.sh
+FILE=/etc/us_pseudo_tty
+TTY=/dev/ttyS1
+
+if [ -a $FILE ]
+ then
+ read -r TTY<$FILE
+fi
$CONSOLE_SH connect
@@ -29,7 +36,7 @@ echo
trap '"$CONSOLE_SH" disconnect' INT TERM QUIT EXIT
-/usr/bin/microcom -s 57600 /dev/ttyS1
+/usr/bin/microcom -s 57600 $TTY
echo
echo
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh
new file mode 100644
index 0000000..19f3198
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/start_us_monitor.sh
@@ -0,0 +1,73 @@
+#! /bin/sh
+#
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+### BEGIN INIT INFO
+# Provides: us-monitor
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Start the microserver reset monitoring script
+#
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+NAME="us_monitor"
+DESC="monitoring microserver reset"
+DAEMON="us_monitor.sh"
+
+# source function library
+. /etc/init.d/functions
+
+. /usr/local/bin/openbmc-utils.sh
+
+STOPPER=
+ACTION="$1"
+
+case "$ACTION" in
+ start)
+ echo -n "Starting $DESC: "
+ /usr/local/bin/${DAEMON} > /dev/null 2>&1 &
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ killall ${DAEMON}
+ echo "$NAME."
+ ;;
+ restart|force-reload)
+ echo -n "Restarting $DESC: "
+ killall ${DAEMON}
+ /usr/local/bin/${DAEMON} > /dev/null 2>&1 &
+ echo "$NAME."
+ ;;
+ status)
+ status ${DAEMON}
+ exit $?
+ ;;
+ *)
+ N=${0##*/}
+ N=${N#[SK]??}
+ echo "Usage: $N {start|stop|status|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh
index 6f445ee..75bbcea 100755
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_console.sh
@@ -22,7 +22,7 @@ usage() {
echo "$0 <connect | disconnect>"
}
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
if [ $# -ne 1 ]; then
usage
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh
new file mode 100644
index 0000000..b7a9cb6
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/us_monitor.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Copyright 2015-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+. /usr/local/bin/openbmc-utils.sh
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
+
+# Because the voltage leak from uS COM pins could cause uS to struck when
+# transitting from S5 to S0, we will need to explicitely pull down uS COM
+# pins before powering off/reset and restoring COM pins after
+
+pull_down_us_com() {
+ # set GPIOL6 and GPIOL7 low
+ devmem_clear_bit $(scu_addr 84) 22
+ devmem_clear_bit $(scu_addr 84) 23
+ gpio_set 94 0
+ gpio_set 95 0
+ # now, connect uart from BMC to the uS
+ gpio_set 32 1
+}
+
+restore_us_com() {
+ devmem_set_bit $(scu_addr 84) 22
+ devmem_set_bit $(scu_addr 84) 23
+ # if sol.sh is running, keep uart from uS connected with BMC
+ if pidof -x sol.sh > /dev/null 2>&1; then
+ gpio_set 32 1
+ else
+ gpio_set 32 0
+ fi
+}
+
+while true; do
+ if ! wedge_is_us_on 1 '' 0 > /dev/null 2>&1; then
+ pull_down_us_com
+ else
+ restore_us_com
+ fi
+ usleep 400000 # 400ms
+done
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh
index 5ba5311..ce734ef 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/files/wedge_power.sh
@@ -18,7 +18,7 @@
# Boston, MA 02110-1301 USA
#
-. /usr/local/fbpackages/utils/ast-functions
+. /usr/local/bin/openbmc-utils.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
@@ -43,31 +43,6 @@ usage() {
echo
}
-# Because the voltage leak from uS COM pins could cause uS to struck when transitting
-# from S5 to S0, we will need to explicitely pull down uS COM pins before powering off/reset
-# and restoring COM pins after
-
-pull_down_us_com() {
- # set GPIOL6 and GPIOL7 low
- devmem_clear_bit $(scu_addr 84) 22
- devmem_clear_bit $(scu_addr 84) 23
- gpio_set 94 0
- gpio_set 95 0
- # now, connect uart from BMC to the uS
- gpio_set 32 1
-}
-
-restore_us_com() {
- devmem_set_bit $(scu_addr 84) 22
- devmem_set_bit $(scu_addr 84) 23
- # if sol.sh is running, keep uart from uS connected with BMC
- if ps | grep sol.sh > /dev/null 2>&1; then
- gpio_set 32 1
- else
- gpio_set 32 0
- fi
-}
-
do_status() {
echo -n "Microserver power is "
if wedge_is_us_on; then
@@ -79,7 +54,7 @@ do_status() {
}
do_on() {
- local force opt
+ local force opt pulse_us n retries
force=0
while getopts "f" opt; do
case $opt in
@@ -103,14 +78,31 @@ do_on() {
fi
# first make sure, GPIOD1 (25) is high
gpio_set 25 1
+ sleep 1
# then, put GPIOP7 (127) to low
gpio_set 127 0
- # generate the power on pulse
- gpio_set 25 0
- sleep 1
- gpio_set 25 1
- sleep 1
- restore_us_com
+ pulse_us=500000 # 500ms
+ retries=3
+ n=1
+ while true; do
+ # first make sure, GPIOD1 (25) is high
+ gpio_set 25 1
+ usleep $pulse_us
+ # generate the power on pulse
+ gpio_set 25 0
+ usleep $pulse_us
+ gpio_set 25 1
+ sleep 3
+ if wedge_is_us_on 1 '' 1; then
+ break
+ fi
+ n=$((n+1))
+ if [ $n -gt $retries ]; then
+ echo " Failed"
+ return 1
+ fi
+ echo -n "..."
+ done
# Turn on the power LED (GPIOE5)
/usr/local/bin/power_led.sh on
echo " Done"
@@ -119,7 +111,6 @@ do_on() {
do_off() {
echo -n "Power off microserver ..."
- pull_down_us_com
# first make sure, GPIOD1 (25) is high
gpio_set 25 1
# then, put GPIOP7 (127) to low
@@ -158,14 +149,12 @@ do_reset() {
return -1
fi
echo -n "Power reset microserver ..."
- pull_down_us_com
# then, put GPIOP7 (127) to low
gpio_set 127 0
gpio_set 17 0
sleep 1
gpio_set 17 1
sleep 1
- restore_us_com
fi
echo " Done"
return 0
diff --git a/meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend b/meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend
new file mode 100644
index 0000000..d6641c9
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/fbutils/openbmc-utils_%.bbappend
@@ -0,0 +1,95 @@
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+
+SRC_URI += "file://board-utils.sh \
+ file://us_console.sh \
+ file://sol.sh \
+ file://power_led.sh \
+ file://post_led.sh \
+ file://reset_usb.sh \
+ file://setup-gpio.sh \
+ file://setup_rov.sh \
+ file://mdio.py \
+ file://bcm5396.py \
+ file://bcm5396_util.py \
+ file://at93cx6.py \
+ file://at93cx6_util.py \
+ file://mount_data0.sh \
+ file://eth0_mac_fixup.sh \
+ file://wedge_power.sh \
+ file://power-on.sh \
+ file://wedge_us_mac.sh \
+ file://setup_switch.py \
+ file://create_vlan_intf \
+ file://rc.early \
+ file://rc.local \
+ file://src \
+ file://start_us_monitor.sh \
+ file://us_monitor.sh \
+ "
+
+OPENBMC_UTILS_FILES += " \
+ board-utils.sh us_console.sh sol.sh power_led.sh post_led.sh \
+ reset_usb.sh mdio.py setup_rov.sh wedge_power.sh wedge_us_mac.sh \
+ bcm5396.py bcm5396_util.py setup_switch.py us_monitor.sh \
+ at93cx6.py at93cx6_util.py \
+ "
+
+DEPENDS_append = "update-rc.d-native"
+
+do_install_board() {
+ # for backward compatible, create /usr/local/fbpackages/utils/ast-functions
+ olddir="/usr/local/fbpackages/utils"
+ install -d ${D}${olddir}
+ ln -s "/usr/local/bin/openbmc-utils.sh" ${D}${olddir}/ast-functions
+
+ # common lib and include files
+ install -d ${D}${includedir}/facebook
+ install -m 0644 src/include/i2c-dev.h ${D}${includedir}/facebook/i2c-dev.h
+
+ # init
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${sysconfdir}/rcS.d
+ # the script to mount /mnt/data
+ install -m 0755 ${WORKDIR}/mount_data0.sh ${D}${sysconfdir}/init.d/mount_data0.sh
+ update-rc.d -r ${D} mount_data0.sh start 03 S .
+ install -m 0755 ${WORKDIR}/rc.early ${D}${sysconfdir}/init.d/rc.early
+ update-rc.d -r ${D} rc.early start 04 S .
+ install -m 755 setup-gpio.sh ${D}${sysconfdir}/init.d/setup-gpio.sh
+ update-rc.d -r ${D} setup-gpio.sh start 59 S .
+ # create VLAN intf automatically
+ install -d ${D}/${sysconfdir}/network/if-up.d
+ install -m 755 create_vlan_intf ${D}${sysconfdir}/network/if-up.d/create_vlan_intf
+ # networking is done after rcS, any start level within rcS
+ # for mac fixup should work
+ install -m 755 eth0_mac_fixup.sh ${D}${sysconfdir}/init.d/eth0_mac_fixup.sh
+ update-rc.d -r ${D} eth0_mac_fixup.sh start 70 S .
+ install -m 755 start_us_monitor.sh ${D}${sysconfdir}/init.d/start_us_monitor.sh
+ update-rc.d -r ${D} start_us_monitor.sh start 84 S .
+ install -m 755 power-on.sh ${D}${sysconfdir}/init.d/power-on.sh
+ update-rc.d -r ${D} power-on.sh start 85 S .
+ install -m 0755 ${WORKDIR}/rc.local ${D}${sysconfdir}/init.d/rc.local
+ update-rc.d -r ${D} rc.local start 99 2 3 4 5 .
+}
+
+do_install_append() {
+ do_install_board
+}
+
+FILES_${PN} += "${sysconfdir}"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile
index 8282964..c21df07 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/Makefile
@@ -1,4 +1,20 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
all: ipmid
ipmid: ipmid.c \
diff --git a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh
index b1fbbb1..b724d70 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/ipmid/files/setup-ipmid.sh
@@ -2,6 +2,22 @@
#
# Copyright 2014-present Facebook. All Rights Reserved.
#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
### BEGIN INIT INFO
# Provides: setup-ipmid
# Required-Start:
diff --git a/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb
index 3f9c4a7..7d8fd37 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/ipmid/ipmid_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "IPMI Daemon"
DESCRIPTION = "Daemon to handle IPMI Messages."
diff --git a/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend b/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend
index 35433ae..90a3954 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend
+++ b/meta-facebook/meta-wedge/recipes-wedge/lm_sensors/lmsensors_%.bbappend
@@ -4,7 +4,11 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
SRC_URI += "file://wedge.conf \
"
-do_install_append() {
+do_install_board_config() {
install -d ${D}${sysconfdir}/sensors.d
install -m 644 ../wedge.conf ${D}${sysconfdir}/sensors.d/wedge.conf
}
+
+do_install_append() {
+ do_install_board_config
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile
index 0c9f49f..00464e5 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/Makefile
@@ -1,4 +1,20 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
all: oob-nic i2craw
oob-nic: main.o nic.o intf.o ll_map.o libnetlink.o
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh
index 35e1a2a..7eaf581 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/etc/oob-nic.sh
@@ -40,14 +40,12 @@ DESC="OOB NIC Driver"
test -f $DAEMON || exit 0
# enable the isolation buffer
-. /usr/local/fbpackages/utils/ast-functions
-wedge_iso_buf_enable
+. /usr/local/bin/openbmc-utils.sh
fix_etc_interfaces() {
- local intf_conf rev
- intf_conf="/etc/network/interfaces"
- rev=$(wedge_board_rev)
- if [ $rev -lt 3 ]; then
+ local intf_conf board_rev board_type enable_oob
+ if wedge_should_enable_oob; then
+ intf_conf="/etc/network/interfaces"
if ! grep oob $intf_conf > /dev/null 2>&1; then
echo >> $intf_conf
echo "auto oob" >> $intf_conf
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c
index f9d499b..83f03b7 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/i2craw.c
@@ -27,7 +27,7 @@
#include <stdint.h>
#include "facebook/i2c-dev.h"
-#include "facebook/log.h"
+#include "openbmc/log.h"
void usage(const char *prog) {
printf("Usage: %s [options] <bus number> <slave address>\n", prog);
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c
index 5bf8480..81834b9 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/intf.c
@@ -32,7 +32,7 @@
#include <linux/if_tun.h>
#include <linux/fib_rules.h>
-#include "facebook/log.h"
+#include "openbmc/log.h"
#include "libnetlink.h"
#include "ll_map.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c
index 4312402..2dc1917 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/main.c
@@ -24,7 +24,7 @@
#include "nic.h"
#include "intf.h"
-#include "facebook/log.h"
+#include "openbmc/log.h"
#include "facebook/wedge_eeprom.h"
#define WAIT4PACKET_TIMEOUT 10000 /* 10ms */
@@ -129,28 +129,40 @@ int main(int argc, const char **argv) {
/* read EEPROM for the MAC */
if (wedge_eeprom_parse(NULL, &eeprom) == 0) {
- if (eeprom.fbw_mac_size <= 0) {
+ uint16_t carry;
+ int pos;
+ int adj;
+ /*
+ * OOB MAC comes from this range. We pick the last MAC from the range to
+ * use as OOB MAC.
+ */
+ if (eeprom.fbw_mac_size > 128) {
+ LOG_ERR(EFAULT, "Extended MAC size (%d) is too large.",
+ eeprom.fbw_mac_size);
+ carry = 128;
+ } else {
+ carry = eeprom.fbw_mac_size;
+ }
+
+ /*
+ * Due to various manufacture issues, some FC boards have MAC range overlap
+ * between LEFT and RIGHT sides. A SW workaround is done below to use the
+ * 8th (or 7th for right side FC) last MAC from the range for FC.
+ */
+ if (strncmp(eeprom.fbw_location, "LEFT", FBW_EEPROM_F_LOCATION) == 0) {
+ adj = 8;
+ } else if (strncmp(eeprom.fbw_location, "RIGHT", FBW_EEPROM_F_LOCATION)
+ == 0) {
+ adj = 7;
+ } else {
+ adj = 1;
+ }
+
+ if (carry < adj) {
LOG_ERR(EFAULT, "Invalid extended MAC size: %d", eeprom.fbw_mac_size);
} else {
- uint16_t carry;
- int pos;
- /* use the last MAC address from the extended MAC range */
+ carry -= adj;
memcpy(mac, eeprom.fbw_mac_base, sizeof(mac));
- if (eeprom.fbw_mac_size > 128) {
- LOG_ERR(EFAULT, "Extended MAC size (%d) is too large.",
- eeprom.fbw_mac_size);
- carry = 127;
- } else {
- /*
- * hack around bug device which have the same MAC address on
- * left and right.
- */
- if (strncmp(eeprom.fbw_location, "LEFT", FBW_EEPROM_F_LOCATION) == 0) {
- carry = eeprom.fbw_mac_size - 2;
- } else {
- carry = eeprom.fbw_mac_size - 1;
- }
- }
for (pos = sizeof(mac) - 1; pos >= 0 && carry; pos--) {
uint16_t tmp = mac[pos] + carry;
mac[pos] = tmp & 0xFF;
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c
index a4dc071..c5fa422 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic.c
@@ -17,6 +17,7 @@
*/
#include "nic.h"
+#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -26,7 +27,9 @@
#include <sys/types.h>
#include "facebook/i2c-dev.h"
-#include "facebook/log.h"
+#include "openbmc/log.h"
+
+#define ETHERTYPE_LLDP 0x88cc
struct oob_nic_t {
int on_bus;
@@ -334,12 +337,25 @@ static int oob_nic_set_force_up(oob_nic *dev, int enable) {
static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
int rc;
- int i;
uint32_t cmd32;
uint8_t buf[32];
uint8_t *cmd;
/*
+ * There are 8 filters in total (MDEF0-MDEF7). Any filter that has a
+ * configuration will be applied. Any packet that matches any filter will
+ * be passed to OOB by the main NIC.
+ *
+ * Each filter has two sets of bits, MDEF and MDEF_EXT. Each bit in the
+ * filter represents a filter with its logical operation. For example,
+ * NIC_FILTER_MDEF_MAC_AND_OFFSET(0) represent MAC filter 0 using AND
+ * operation. So, in order to receive packets matching a specific MAC, MAC0
+ * filter (NIC_FILTER_MAC_NUM:NIC_FILTER_MAC_PAIR0) must be programmed
+ * with the specific MAC. Then set NIC_FILTER_MDEF_MAC_AND_OFFSET (for
+ * AND) or NIC_FILTER_MDEF_MAC_OR_OFFSET (for OR) in one of the filters.
+ */
+
+ /*
* Command to set MAC filter
* Seven bytes are required to load the MAC address filters.
* Data 2—MAC address filters pair number (3:0).
@@ -351,9 +367,8 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
cmd = buf;
*cmd++ = NIC_FILTER_MAC_NUM;
*cmd++ = NIC_FILTER_MAC_PAIR0; /* pair 0 */
- for (i = 0; i < 6; i++) {
- *cmd++ = mac[i];
- }
+ memcpy(cmd, mac, 6);
+ cmd += 6;
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
@@ -380,17 +395,15 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
*cmd++ = NIC_FILTER_DECISION_EXT_NUM;
*cmd++ = NIC_FILTER_MDEF0;
/* enable filter for traffic from network and host */
- cmd32 = NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET)
- | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET);
- for (i = 0; i < sizeof(cmd32); i++) {
- *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF;
- }
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET)
+ | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
/* enable mac pair 0 */
- cmd32 = NIC_FILTER_MDEF_BIT_VAL(NIC_FILTER_MDEF_MAC_AND_OFFSET,
- NIC_FILTER_MAC_PAIR0);
- for (i = 0; i < sizeof(cmd32); i++) {
- *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF;
- }
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT_VAL(NIC_FILTER_MDEF_MAC_AND_OFFSET,
+ NIC_FILTER_MAC_PAIR0));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
@@ -398,23 +411,41 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
LOG_ERR(rc, "Failed to set MAC filter to MDEF 0");
return -rc;
}
- /* enable ARP and ND on filter 1*/
+
+ /* Program EtherType0 to match LLDP */
+ cmd = buf;
+ *cmd++ = NIC_FILTER_ETHERTYPE_NUM;
+ *cmd++ = NIC_FILTER_ETHERTYPE0;
+ cmd32 = htonl(ETHERTYPE_LLDP);
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
+ rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
+ cmd - buf, buf);
+ if (rc < 0) {
+ rc = errno;
+ LOG_ERR(rc, "Failed to program EtherType0 to match LLDP");
+ return -rc;
+ }
+
+ /* enable ARP, ND, and EtheryType0 (OR) on filter 1 */
cmd = buf;
*cmd++ = NIC_FILTER_DECISION_EXT_NUM;
*cmd++ = NIC_FILTER_MDEF1;
- /* enable filter for traffic from network and host */
- cmd32 = NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET)
- | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET);
- for (i = 0; i < sizeof(cmd32); i++) {
- *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF;
- }
+ /* enable filter for traffic from network and host, matching ethertype0 */
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_NET_EN_OFFSET)
+ | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_EXT_HOST_EN_OFFSET)
+ | NIC_FILTER_MDEF_BIT_VAL(
+ NIC_FILTER_MDEF_EXT_ETHTYPE_OR_OFFSET,
+ NIC_FILTER_ETHERTYPE0));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
+
/* enable ARP and ND */
- cmd32 = NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_ARP_REQ_OR_OFFSET)
- | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_ARP_RES_OR_OFFSET)
- | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_NBG_OR_OFFSET);
- for (i = 0; i < sizeof(cmd32); i++) {
- *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF;
- }
+ cmd32 = htonl(NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_ARP_REQ_OR_OFFSET)
+ | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_ARP_RES_OR_OFFSET)
+ | NIC_FILTER_MDEF_BIT(NIC_FILTER_MDEF_NBG_OR_OFFSET));
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
@@ -426,10 +457,9 @@ static int oob_nic_setup_filters(oob_nic *dev, const uint8_t mac[6]) {
/* make filter 0, matching MAC, to be mng only */
cmd = buf;
*cmd++ = NIC_FILTER_MNG_ONLY_NUM;
- cmd32 = NIC_FILTER_MNG_ONLY_FILTER0;
- for (i = 0; i < sizeof(cmd32); i++) {
- *cmd++ = (cmd32 >> (24 - 8 * i)) & 0xFF;
- }
+ cmd32 = htonl(NIC_FILTER_MNG_ONLY_FILTER0);
+ memcpy(cmd, &cmd32, sizeof(cmd32));
+ cmd += sizeof(cmd32);
rc = i2c_smbus_write_block_data(dev->on_file, NIC_WRITE_FILTER_CMD,
cmd - buf, buf);
if (rc < 0) {
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h
index 1ae8721..87574f0 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic/src/nic_defs.h
@@ -76,12 +76,6 @@ struct oob_nic_status_t {
/** Update MNG RCV Filter Parameters */
#define NIC_WRITE_FILTER_CMD 0xCC
-#define NIC_FILTER_MAC_NUM 0x66
-#define NIC_FILTER_MAC_PAIR0 0
-#define NIC_FILTER_MAC_PAIR1 1
-#define NIC_FILTER_MAC_PAIR2 2
-#define NIC_FILTER_MAC_PAIR3 3
-
#define NIC_FILTER_MNG_ONLY_NUM 0xF
#define NIC_FILTER_MNG_ONLY_FILTER0 (0x1)
#define NIC_FILTER_MNG_ONLY_FILTER1 (0x1 << 1)
@@ -89,6 +83,18 @@ struct oob_nic_status_t {
#define NIC_FILTER_MNG_ONLY_FILTER3 (0x1 << 3)
#define NIC_FILTER_MNG_ONLY_FILTER4 (0x1 << 4)
+#define NIC_FILTER_MAC_NUM 0x66
+#define NIC_FILTER_MAC_PAIR0 0
+#define NIC_FILTER_MAC_PAIR1 1
+#define NIC_FILTER_MAC_PAIR2 2
+#define NIC_FILTER_MAC_PAIR3 3
+
+#define NIC_FILTER_ETHERTYPE_NUM 0x67
+#define NIC_FILTER_ETHERTYPE0 0
+#define NIC_FILTER_ETHERTYPE1 1
+#define NIC_FILTER_ETHERTYPE2 2
+#define NIC_FILTER_ETHERTYPE3 3
+
#define NIC_FILTER_DECISION_EXT_NUM 0x68
#define NIC_FILTER_MDEF0 0 /* index 0 */
#define NIC_FILTER_MDEF1 1 /* index 1 */
diff --git a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb
index 1df83dc..82a5296 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/oob-nic/oob-nic_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "OOB Shared NIC driver"
DESCRIPTION = "The shared-nic driver"
@@ -12,7 +27,7 @@ SRC_URI = "file://src \
S = "${WORKDIR}/src"
-DEPENDS += "fbutils libwedge-eeprom"
+DEPENDS += "openbmc-utils liblog libwedge-eeprom"
RDEPENDS_${PN} += "libwedge-eeprom"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile
index 408de95..0b3fd71 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/files/Makefile
@@ -1,4 +1,20 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
all: po-eeprom
po-eeprom: po-eeprom.o
diff --git a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb
index e1d8b32..ad635dc 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/po-eeprom/po-eeprom_0.1.bb
@@ -1,4 +1,21 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
SUMMARY = "PowerOne EEPROM Utilities"
DESCRIPTION = "Util for PowerOne eeprom"
SECTION = "base"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile
index 4a3c25d..926bf52 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/Makefile
@@ -1,16 +1,40 @@
# Copyright 2014-present Facebook. All Rights Reserved.
-all: modbuscmd gpiowatch modbussim
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
+override CFLAGS+=-D_GNU_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=199309 -Wall -Werror -std=c99
+override LDFLAGS+=-pthread
+all: modbuscmd gpiowatch modbussim rackmond rackmondata
+
+rackmondata: rackmondata.c modbus.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+rackmond: rackmond.c modbus.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
modbuscmd: modbuscmd.c modbus.c
- $(CC) -D_BSD_SOURCE -Wall -Werror -std=c99 -o $@ $^ $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
modbussim: modbussim.c modbus.c
- $(CC) -D_BSD_SOURCE -Wall -Werror -std=c99 -o $@ $^ $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
gpiowatch: gpiowatch.c
- $(CC) -D_BSD_SOURCE -Wall -Werror -std=c99 -o $@ $^ $(LDFLAGS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean:
- rm -rf *.o modbuscmd gpiowatch modbussim
+ rm -rf *.o modbuscmd gpiowatch modbussim rackmond rackmondata
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py
new file mode 100644
index 0000000..c484fdf
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/hexfile.py
@@ -0,0 +1,174 @@
+# The MIT License (MIT)
+# =====================
+#
+# Copyright (c) 2014 Ryan Sturmer
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# https://github.com/ryansturmer/hexfile/blob/master/hexfile/core.py
+
+import itertools
+
+def short(msb,lsb):
+ return (msb<<8) | lsb
+
+class HexFile(object):
+ def __init__(self, segments):
+ self.segments = segments
+
+ def __getitem__(self, val):
+ if isinstance(val, slice):
+ address = val.start
+ else:
+ address = val
+
+ for segment in self.segments:
+ if address in segment:
+ return segment[val]
+
+ raise IndexError('No segment contains address 0x%x' % address)
+
+ def __len__(self):
+ return sum(map(len, self.segments))
+
+ @property
+ def size(self):
+ return len(self)
+
+ def __iter__(self):
+ return itertools.chain(*self.segments)
+
+ @staticmethod
+ def load(filename):
+ segments = [Segment(0)]
+
+ with open(filename) as fp:
+ lines = fp.readlines()
+
+ extended_linear_address = 0
+ current_address = 0
+ end_of_file = False
+
+ lineno = 0
+ for line in lines:
+ lineno += 1
+ line = line.strip();
+ if not line.startswith(':'):
+ continue
+
+ if end_of_file:
+ raise Exception("Record found after end of file on line %d" % lineno)
+
+ bytes = [int(line[i:i+2], 16) for i in range(1,len(line), 2)]
+ byte_count = bytes[0]
+ address = short(*bytes[1:3])
+ record_type = bytes[3]
+ checksum = bytes[-1]
+ data = bytes[4:-1]
+ computed_checksum = ((1 << 8)-(sum(bytes[:-1]) & 0xff)) & 0xff
+
+ if(computed_checksum != checksum):
+ raise Exception("Record checksum doesn't match on line %d" % lineno)
+
+ if record_type == 0:
+ if byte_count == len(data):
+ current_address = (address | extended_linear_address)
+ have_segment = False
+ for segment in segments:
+ if segment.end_address == current_address:
+ segment.data.extend(data)
+ have_segment = True
+ break
+ if not have_segment:
+ segments.append(Segment(current_address, data))
+ else:
+ raise Exception("Data record reported size does not match actual size on line %d" % lineno)
+ elif record_type == 1:
+ end_of_file = True
+ elif record_type == 4:
+ if byte_count != 2 or len(data) != 2:
+ raise Exception("Byte count misreported in extended linear address record on line %d" % lineno)
+ extended_linear_address = short(*data) << 16
+
+ else:
+ raise Exception("Unknown record type: %s" % record_type)
+ return HexFile(segments)
+
+ def pretty_string(self, stride=16):
+ retval = []
+ for segment in self.segments:
+ retval.append('Segment @ 0x%08x (%d bytes)' % (segment.start_address, segment.size))
+ retval.append(segment.pretty_string(stride=stride))
+ retval.append('')
+ return '\n'.join(retval)
+
+def load(filename):
+ return HexFile.load(filename)
+
+class Segment(object):
+ def __init__(self, start_address, data = None):
+ self.start_address = start_address
+ self.data = data or []
+
+ def pretty_string(self, stride=16):
+ retval = []
+ addresses = self.addresses
+ ranges = [addresses[i:i+stride] for i in range(0, self.size, stride)]
+ for r in ranges:
+ retval.append('%08x ' % r[0] + ' '.join(['%02x' % self[addr] for addr in r]))
+ return '\n'.join(retval)
+
+ def __str__(self):
+ return '<%d byte segment @ 0x%08x>' % (self.size, self.start_address)
+ def __repr__(self):
+ return str(self)
+
+ @property
+ def end_address(self):
+ return self.start_address + len(self.data)
+
+ @property
+ def size(self):
+ return len(self.data)
+
+ def __contains__(self, address):
+ return address >= self.start_address and address < self.end_address
+
+ def __getitem__(self, address):
+ if isinstance(address, slice):
+ if address.start not in self or address.stop-1 not in self:
+ raise IndexError('Address out of range for this segment')
+ else:
+ d = self.data[address.start-self.start_address:address.stop-self.start_address:address.step]
+ start_address = address.start + self.start_address
+ return Segment(start_address, d)
+ else:
+ if not address in self:
+ raise IndexError("Address 0x%x is not in this segment" % address)
+ return self.data[address-self.start_address]
+
+ @property
+ def addresses(self):
+ return range(self.start_address, self.end_address)
+
+ def __len__(self):
+ return len(self.data)
+
+ def __iter__(self):
+ return iter(self.data)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c
index 46618a9..8fb0835 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <time.h>
#include "modbus.h"
#include <termios.h>
#include <unistd.h>
@@ -26,9 +27,15 @@
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
+#include <sched.h>
+#include <pthread.h>
-static int loops = 0;
-void waitfd(int fd) {
+int verbose = 0;
+
+#define TIOCSERWAITTEMT 0x5499
+int waitfd(int fd) {
+ int loops = 0;
+ ioctl(fd, TIOCSERWAITTEMT, DEFAULT_GPIO);
while(1) {
int lsr;
int ret = ioctl(fd, TIOCSERGETLSR, &lsr);
@@ -37,8 +44,10 @@ void waitfd(int fd) {
break;
}
if(lsr & TIOCSER_TEMT) break;
+ // never should hit this with new ioctl
loops++;
}
+ return loops;
}
void gpio_on(int fd) {
@@ -60,8 +69,7 @@ void decode_hex_in_place(char* buf, size_t* len) {
void append_modbus_crc16(char* buf, size_t* len) {
uint16_t crc = modbus_crc16(buf, *len);
- if (verbose)
- fprintf(stderr, "[*] Append Modbus CRC16 %04x\n", crc);
+ dbg("[*] Append Modbus CRC16 %04x\n", crc);
buf[(*len)++] = crc >> 8;
buf[(*len)++] = crc & 0x00FF;
}
@@ -78,7 +86,7 @@ size_t read_wait(int fd, char* dst, size_t maxlen, int mdelay_us) {
size_t read_size = 0;
size_t pos = 0;
memset(dst, 0, maxlen);
- for(;;) {
+ while(pos < maxlen) {
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
timeout.tv_sec = 0;
@@ -95,10 +103,11 @@ size_t read_wait(int fd, char* dst, size_t maxlen, int mdelay_us) {
fprintf(stderr, "read error: %s\n", strerror(errno));
exit(1);
}
- if((pos + read_size) < maxlen) {
+ if((pos + read_size) <= maxlen) {
memcpy(dst + pos, read_buf, read_size);
pos += read_size;
} else {
+ return pos;
fprintf(stderr, "Response buffer overflowed!\n");
}
}
@@ -181,3 +190,163 @@ uint16_t modbus_crc16(char* buffer, size_t buffer_length) {
return (crc_hi << 8 | crc_lo);
}
+
+
+double ts_diff (struct timespec* begin, struct timespec* end) {
+ return 1000.0 * (end->tv_sec) + (1e-6 * end->tv_nsec)
+ - (1000.0 * (begin->tv_sec) + (1e-6 * begin->tv_nsec));
+}
+
+static long success = 0;
+static long crcfail = 0;
+static long timeout = 0;
+static long stat_wait = 0;
+
+int modbuscmd(modbus_req *req) {
+ int error = 0;
+ struct termios tio;
+ char modbus_cmd[req->cmd_len + 2];
+ size_t cmd_len = req->cmd_len;
+
+ if (verbose)
+ fprintf(stderr, "[*] Setting TTY flags!\n");
+ memset(&tio, 0, sizeof(tio));
+ // CREAD should be left *off* until we've confirmed THRE
+ // to avoid catching false character starts
+ cfsetspeed(&tio,B19200);
+ tio.c_cflag |= PARENB;
+ tio.c_cflag |= CLOCAL;
+ tio.c_cflag |= CS8;
+ tio.c_iflag |= INPCK;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ CHECK(tcsetattr(req->tty_fd,TCSANOW,&tio));
+
+ memcpy(modbus_cmd, req->modbus_cmd, cmd_len);
+ append_modbus_crc16(modbus_cmd, &cmd_len);
+
+ // print command as sent
+ if (verbose) {
+ fprintf(stderr, "Will send: ");
+ print_hex(stderr, modbus_cmd, cmd_len);
+ fprintf(stderr, "\n");
+ }
+
+ dbg("[*] Writing!\n");
+
+ // hoped adding the ioctl to do the switching would have alleviated the
+ // need to do SCHED_FIFO, but we still get preempted between the write and
+ // ioctl syscalls w/o it often enough to break f/w updates.
+ struct sched_param sp;
+ sp.sched_priority = 50;
+ int policy = SCHED_FIFO;
+ CHECKP(sched, pthread_setschedparam(pthread_self(), policy, &sp));
+ // gpio on, write, wait, gpio off
+ gpio_on(req->gpio_fd);
+ struct timespec write_begin;
+ struct timespec wait_begin;
+ struct timespec wait_end;
+ struct timespec read_end;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &write_begin);
+ write(req->tty_fd, modbus_cmd, cmd_len);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &wait_begin);
+ int waitloops = waitfd(req->tty_fd);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &wait_end);
+ gpio_off(req->gpio_fd);
+ sp.sched_priority = 0;
+ // Enable UART read
+ tio.c_cflag |= CREAD;
+ CHECK(tcsetattr(req->tty_fd,TCSANOW,&tio));
+ policy = SCHED_OTHER;
+ CHECKP(sched, pthread_setschedparam(pthread_self(), policy, &sp));
+
+ dbg("[*] waitfd loops: %d\n", waitloops);
+ dbg("[*] reading any response...\n");
+ // Read back response
+ size_t mb_pos = 0;
+ memset(req->dest_buf, 0, req->dest_limit);
+ if(req->expected_len == 0) {
+ req->expected_len = req->dest_limit;
+ }
+ if(req->expected_len > req->dest_limit) {
+ return -1;
+ }
+ mb_pos = read_wait(req->tty_fd, req->dest_buf, req->expected_len, req->timeout);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &read_end);
+ req->dest_len = mb_pos;
+ if(mb_pos >= 4) {
+ uint16_t crc = modbus_crc16(req->dest_buf, mb_pos - 2);
+ dbg("Modbus response CRC: %04X\n ", crc);
+ if((req->dest_buf[mb_pos - 2] == (crc >> 8)) &&
+ (req->dest_buf[mb_pos - 1] == (crc & 0x00FF))) {
+ dbg("CRC OK!\n");
+ } else {
+ dbg("BAD CRC :(\n");
+ fprintf(stderr, "bad crc timings:");
+ fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ fprintf(stderr, " read: %.2f ms\n", ts_diff(&wait_end, &read_end));
+ if(!req->scan) {
+ crcfail++;
+ }
+ if(verbose) {
+ print_hex(stderr, req->dest_buf, mb_pos);
+ }
+ return MODBUS_BAD_CRC;
+ }
+ } else {
+ fprintf(stderr, "timeout timings:");
+ fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ fprintf(stderr, " wait: %d iters", waitloops);
+ fprintf(stderr, " read: %.2f ms\n", ts_diff(&wait_end, &read_end));
+ dbg("No response :(\n");
+ if(!req->scan) {
+ timeout++;
+ }
+ return MODBUS_RESPONSE_TIMEOUT;
+ }
+
+cleanup:
+ if(error != 0) {
+ error = -1;
+ fprintf(stderr, "%s\n", strerror(errno));
+ } else {
+ //fprintf(stderr, "success, timings:");
+ //fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ //fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ //fprintf(stderr, " read: %.2f ms -- ", ts_diff(&wait_end, &read_end));
+ if(stat_wait == 0 && !req->scan) {
+ fprintf(stderr, "success: %.2f%% crcfail %.2f%%, timeout %.2f%%\n",
+ ((double) 100.0 * success / (success + crcfail + timeout)),
+ ((double) 100.0 * crcfail / (success + crcfail + timeout)),
+ ((double) 100.0 * timeout / (success + crcfail + timeout)));
+ stat_wait = 1000;
+ fprintf(stderr, "success timings:");
+ fprintf(stderr, " write: %.2f ms", ts_diff(&write_begin, &wait_begin));
+ fprintf(stderr, " wait: %.2f ms", ts_diff(&wait_begin, &wait_end));
+ fprintf(stderr, " wait: %d iters", waitloops);
+ fprintf(stderr, " read: %.2f ms\n", ts_diff(&wait_end, &read_end));
+ } else if (!req->scan) {
+ stat_wait--;
+ }
+ if(!req->scan) {
+ success++;
+ }
+ }
+ return 0;
+}
+
+const char* modbus_strerror(int mb_err) {
+ if (mb_err < 0) {
+ mb_err = -mb_err;
+ }
+ switch(mb_err) {
+ case 4:
+ return "timed out";
+ case 5:
+ return "crc check failed";
+ default:
+ return "unknown";
+ }
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h
index 435d518..1354feb 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbus.h
@@ -26,12 +26,27 @@ uint16_t modbus_crc16(char* buffer, size_t length);
#define DEFAULT_TTY "/dev/ttyS3"
#define DEFAULT_GPIO 45
-#define CHECK(x) { if((x) < 0) { \
- error = x; \
+extern int verbose;
+#define dbg(...) if(verbose) { fprintf(stderr, __VA_ARGS__); }
+#define log(...) { fprintf(stderr, __VA_ARGS__); }
+
+#define CHECK(expr) { int _check = expr; if((_check) < 0) { \
+ error = _check; \
+ goto cleanup; \
+} }
+#define CHECKP(name, expr) { int _check = expr; if((_check) < 0) { \
+ error = _check; \
+ perror(#name); \
goto cleanup; \
} }
+#define BAIL(...) { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ error = -1; \
+ goto cleanup; \
+}
-void waitfd(int fd);
+int waitfd(int fd);
void gpio_on(int fd);
void gpio_off(int fd);
void decode_hex_in_place(char* buf, size_t* len);
@@ -41,6 +56,30 @@ void print_hex(FILE* f, char* buf, size_t len);
// Read until maxlen bytes or no bytes in mdelay_us microseconds
size_t read_wait(int fd, char* dst, size_t maxlen, int mdelay_us);
-extern int verbose;
+
+typedef struct _modbus_req {
+ int tty_fd;
+ int gpio_fd;
+ const char *modbus_cmd;
+ size_t cmd_len;
+ int timeout;
+ size_t expected_len;
+ char *dest_buf;
+ size_t dest_limit;
+ size_t dest_len;
+ int scan;
+} modbus_req;
+
+int modbuscmd(modbus_req *req);
+// Modbus errors
+
+#define MODBUS_RESPONSE_TIMEOUT -4
+#define MODBUS_BAD_CRC -5
+
+const char* modbus_strerror(int mb_err);
+
+// Modbus constants
+#define MODBUS_READ_HOLDING_REGISTERS 3
+
#endif
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c
index 2d33039..78f62a1 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbuscmd.c
@@ -16,51 +16,54 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <termios.h>
-#include <unistd.h>
+#include <errno.h>
#include <fcntl.h>
-#include <stdlib.h>
+#include <getopt.h>
+#include <sched.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <errno.h>
+#include <unistd.h>
#include <sys/ioctl.h>
-#include <getopt.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include "modbus.h"
-
-int verbose;
+#include "rackmond.h"
void usage() {
fprintf(stderr,
- "modbuscmd [-v] [-t <tty>] [-g <gpio>] modbus_command\n"
- "\ttty defaults to %s\n"
- "\tgpio defaults to %d\n"
+ "modbuscmd [-v] [-t <timeout in ms>] [-x <expected response length>] modbus_command\n"
"\tmodbus command should be specified in hex\n"
- "\teg:\ta40300000008\n",
- DEFAULT_TTY, DEFAULT_GPIO);
+ "\teg:\ta40300000008\n"
+ "\tif an expected response length is provided, modbuscmd will stop receving and check crc immediately "
+ "after receiving that many bytes\n");
exit(1);
}
+
int main(int argc, char **argv) {
int error = 0;
- int fd;
- struct termios tio;
- char gpio_filename[255];
- int gpio_fd = 0;
- int gpio_n = DEFAULT_GPIO;
- char *tty = DEFAULT_TTY;
char *modbus_cmd = NULL;
size_t cmd_len = 0;
+ int expected = 0;
+ uint32_t timeout = 0;
verbose = 0;
+ rackmond_command *cmd = NULL;
+ char *response = NULL;
+ int clisock;
+ uint16_t response_len_actual;
+ struct sockaddr_un rackmond_addr;
int opt;
- while((opt = getopt(argc, argv, "t:g:v")) != -1) {
+ while((opt = getopt(argc, argv, "w:x:t:g:v")) != -1) {
switch (opt) {
- case 't':
- tty = optarg;
+ case 'x':
+ expected = atoi(optarg);
break;
- case 'g':
- gpio_n = atoi(optarg);
+ case 't':
+ timeout = atol(optarg);
break;
case 'v':
verbose = 1;
@@ -77,29 +80,6 @@ int main(int argc, char **argv) {
usage();
}
- if (verbose)
- fprintf(stderr, "[*] Opening TTY\n");
- fd = open(tty, O_RDWR | O_NOCTTY);
- CHECK(fd);
-
- if (verbose)
- fprintf(stderr, "[*] Opening GPIO %d\n", gpio_n);
- snprintf(gpio_filename, 255, "/sys/class/gpio/gpio%d/value", gpio_n);
- gpio_fd = open(gpio_filename, O_WRONLY | O_SYNC);
- CHECK(gpio_fd);
-
- if (verbose)
- fprintf(stderr, "[*] Setting TTY flags!\n");
- memset(&tio, 0, sizeof(tio));
- cfsetspeed(&tio,B19200);
- tio.c_cflag |= PARENB;
- tio.c_cflag |= CLOCAL;
- tio.c_cflag |= CS8;
- tio.c_iflag |= INPCK;
- tio.c_cc[VMIN] = 1;
- tio.c_cc[VTIME] = 0;
- CHECK(tcsetattr(fd,TCSANOW,&tio));
-
//convert hex to bytes
cmd_len = strlen(modbus_cmd);
if(cmd_len < 4) {
@@ -107,57 +87,45 @@ int main(int argc, char **argv) {
exit(1);
}
decode_hex_in_place(modbus_cmd, &cmd_len);
- append_modbus_crc16(modbus_cmd, &cmd_len);
- // print command as sent
- if (verbose) {
- fprintf(stderr, "Will send: ");
- print_hex(stderr, modbus_cmd, cmd_len);
- fprintf(stderr, "\n");
- }
-
- if (verbose)
- fprintf(stderr, "[*] Writing!\n");
-
- // gpio on, write, wait, gpio off
- gpio_on(gpio_fd);
- write(fd, modbus_cmd, cmd_len);
- waitfd(fd);
- gpio_off(gpio_fd);
+ cmd = malloc(sizeof(rackmond_command) + cmd_len);
+ cmd->type = COMMAND_TYPE_RAW_MODBUS;
+ cmd->raw_modbus.length = cmd_len;
+ cmd->raw_modbus.custom_timeout = timeout;
+ memcpy(cmd->raw_modbus.data, modbus_cmd, cmd_len);
+ cmd->raw_modbus.expected_response_length = expected;
+ response = malloc(expected ? expected : 1024);
+ uint16_t wire_cmd_len = sizeof(rackmond_command) + cmd_len;
- // Enable UART read
- tio.c_cflag |= CREAD;
- CHECK(tcsetattr(fd,TCSANOW,&tio));
-
- if(verbose)
- fprintf(stderr, "[*] reading any response...\n");
- // Read back response
- char modbus_buf[255];
- size_t mb_pos = 0;
- memset(modbus_buf, 0, sizeof(modbus_buf));
- mb_pos = read_wait(fd, modbus_buf, sizeof(modbus_buf), 90000);
- if(mb_pos >= 4) {
- uint16_t crc = modbus_crc16(modbus_buf, mb_pos - 2);
- if(verbose)
- fprintf(stderr, "Modbus response CRC: %04X\n ", crc);
- if((modbus_buf[mb_pos - 2] == (crc >> 8)) &&
- (modbus_buf[mb_pos - 1] == (crc & 0x00FF))) {
- if(verbose)
- fprintf(stderr, "CRC OK!\n");
- print_hex(stdout, modbus_buf, mb_pos);
- printf("\n");
- } else {
- fprintf(stderr, "BAD CRC :(\n");
- return 5;
- }
- } else {
- fprintf(stderr, "No response :(\n");
- return 4;
+ clisock = socket(AF_UNIX, SOCK_STREAM, 0);
+ CHECKP(socket, clisock);
+ rackmond_addr.sun_family = AF_UNIX;
+ strcpy(rackmond_addr.sun_path, "/var/run/rackmond.sock");
+ int addr_len = strlen(rackmond_addr.sun_path) + sizeof(rackmond_addr.sun_family);
+ CHECKP(connect, connect(clisock, (struct sockaddr*) &rackmond_addr, addr_len));
+ CHECKP(send, send(clisock, &wire_cmd_len, sizeof(wire_cmd_len), 0));
+ CHECKP(send, send(clisock, cmd, wire_cmd_len, 0));
+ CHECKP(recv, recv(clisock, &response_len_actual, sizeof(response_len_actual), 0));
+ if(response_len_actual == 0) {
+ uint16_t errcode = 0;
+ CHECKP(recv, recv(clisock, &errcode, sizeof(errcode), 0));
+ fprintf(stderr, "modbus error: %d (%s)\n", errcode, modbus_strerror(errcode));
+ error = 1;
+ goto cleanup;
+ }
+ CHECKP(recv, recv(clisock, response, response_len_actual, 0));
+ if(error == 0) {
+ printf("Response: ");
+ print_hex(stdout, response, response_len_actual);
+ printf("\n");
}
-
cleanup:
+ free(cmd);
+ free(response);
if(error != 0) {
+ if(errno != 0) {
+ fprintf(stderr, "errno err: %s\n", strerror(errno));
+ }
error = 1;
- fprintf(stderr, "%s\n", strerror(errno));
}
return error;
}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c
index bf8c6c8..e276501 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/modbussim.c
@@ -28,8 +28,6 @@
#include <getopt.h>
#include "modbus.h"
-int verbose = 0;
-
void usage() {
fprintf(stderr,
"modbussim [-v] [-t <tty>] [-g <gpio>] modbus_request modbus_reply\n"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py
new file mode 100755
index 0000000..a92cf8e
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/psu-update-delta.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import os.path
+import socket
+import struct
+import sys
+import argparse
+import traceback
+
+import hexfile
+
+
+def auto_int(x):
+ return int(x, 0)
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--addr', type=auto_int, required=True,
+ help="PSU Modbus Address")
+parser.add_argument('file', help="firmware file")
+
+
+class ModbusTimeout(Exception):
+ pass
+
+
+class ModbusCRCFail(Exception):
+ pass
+
+
+class ModbusUnknownError(Exception):
+ pass
+
+
+class BadMEIResponse(Exception):
+ pass
+
+
+def rackmon_command(cmd):
+ srvpath = "/var/run/rackmond.sock"
+ replydata = []
+ if os.path.exists(srvpath):
+ client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ client.connect(srvpath)
+ cmdlen = struct.pack("@H", len(cmd))
+ client.send(cmdlen)
+ client.send(cmd)
+ while True:
+ data = client.recv(1024)
+ if not data:
+ break
+ replydata.append(data)
+ client.close()
+ return ''.join(replydata)
+
+
+def pause_monitoring():
+ COMMAND_TYPE_PAUSE_MONITORING = 0x04
+ command = struct.pack("@Hxx", COMMAND_TYPE_PAUSE_MONITORING)
+ result = rackmon_command(command)
+ (res_n, ) = struct.unpack("@B", result)
+ if res_n == 1:
+ print("Monitoring was already paused when tried to pause")
+ elif res_n == 0:
+ print("Monitoring paused")
+ else:
+ print("Unknown response pausing monitoring: %d" % res_n)
+
+
+def resume_monitoring():
+ COMMAND_TYPE_START_MONITORING = 0x05
+ command = struct.pack("@Hxx", COMMAND_TYPE_START_MONITORING)
+ result = rackmon_command(command)
+ (res_n, ) = struct.unpack("@B", result)
+ if res_n == 1:
+ print("Monitoring was already running when tried to resume")
+ elif res_n == 0:
+ print("Monitoring resumed")
+ else:
+ print("Unknown response resuming monitoring: %d" % res_n)
+
+
+def modbuscmd(raw_cmd, expected=0, timeout=0):
+ COMMAND_TYPE_RAW_MODBUS = 1
+ send_command = struct.pack("@HxxHHL",
+ COMMAND_TYPE_RAW_MODBUS,
+ len(raw_cmd),
+ expected,
+ timeout) + raw_cmd
+ result = rackmon_command(send_command)
+ if len(result) == 0:
+ raise ModbusUnknownError()
+ (resp_len,) = struct.unpack("@H", result[:2])
+ if resp_len == 0:
+ (error, ) = struct.unpack("@H", result[2:4])
+ if error == 4:
+ raise ModbusTimeout()
+ if error == 5:
+ raise ModbusCRCFail()
+ print("Unknown modbus error: " + str(error))
+ raise ModbusUnknownError()
+ return result[2:resp_len]
+
+
+def mei_command(addr, func_code, mei_type=0x64, data=None, timeout=0):
+ i_data = data
+ if i_data is None:
+ i_data = ("\xFF" * 7)
+ if len(i_data) < 7:
+ i_data = i_data + ("\xFF" * (7 - len(i_data)))
+ assert len(i_data) == 7
+ command = struct.pack("BBBB", addr, 0x2b, mei_type, func_code) + i_data
+ return modbuscmd(command, expected=13, timeout=timeout)
+
+
+def enter_bootloader(addr):
+ try:
+ print("Entering bootloader...")
+ mei_command(addr, 0xFB, timeout=4000)
+ except ModbusTimeout:
+ print("Enter bootloader timed out (expected.)")
+ pass
+
+
+def mei_expect(response, addr, data_pfx, error, success_mei_type=0x71):
+ expected = struct.pack("BBB", addr, 0x2B, success_mei_type) + \
+ data_pfx + ("\xFF" * (8 - len(data_pfx)))
+ if response != expected:
+ print(error + ", response: " + response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def start_programming(addr):
+ print("Send start programming...")
+ response = mei_command(addr, 0x70, timeout=10000)
+ mei_expect(response, addr, "\xB0", "Start programming failed")
+ print("Start programming succeeded.")
+
+
+def get_challenge(addr):
+ print("Send get seed")
+ response = mei_command(addr, 0x27, timeout=3000)
+ expected = struct.pack("BBBB", addr, 0x2B, 0x71, 0x67)
+ if response[:len(expected)] != expected:
+ print("Bad response to get seed: " + response.encode('hex'))
+ raise BadMEIResponse()
+ challenge = response[len(expected):len(expected) + 4]
+ print("Got seed: " + challenge.encode('hex'))
+ return challenge
+
+
+def send_key(addr, key):
+ print("Send key")
+ response = mei_command(addr, 0x28, data=key, timeout=3000)
+ mei_expect(response, addr, "\x68", "Start programming failed")
+ print("Send key successful.")
+
+
+def delta_seccalckey(challenge):
+ (seed, ) = struct.unpack(">L", challenge)
+ for i in range(32):
+ if seed & 1 != 0:
+ seed = seed ^ 0xc758a5b6
+ seed = (seed >> 1) & 0x7fffffff
+ seed = seed ^ 0x06854137
+ return struct.pack(">L", seed)
+
+
+def verify_flash(addr):
+ print("Verifying program...")
+ response = mei_command(addr, 0x76, timeout=60000)
+ mei_expect(response, addr, "\xB6", "Program verification failed")
+
+
+def set_write_address(psu_addr, flash_addr):
+ # print("Set write address to " + hex(flash_addr))
+ data = struct.pack(">LB", flash_addr, 0xEA)
+ response = mei_command(psu_addr, 0x61, data=data, timeout=3000)
+ mei_expect(response, psu_addr, "\xA1\xEA", "Set address failed")
+
+
+def write_data(addr, data):
+ assert(len(data) == 8)
+ command = struct.pack(">BBB", addr, 0x2b, 0x65) + data
+ response = modbuscmd(command, expected=13, timeout=3000)
+ expected = struct.pack(">B", addr) +\
+ "\x2b\x73\xf0\xaa\xff\xff\xff\xff\xff\xff"
+ if response != expected:
+ print("Bad response to writing data: " +
+ response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def send_image(addr, fwimg):
+ total_chunks = sum([len(s) for s in fwimg.segments]) / 8
+ sent_chunks = 0
+ for s in fwimg.segments:
+ if len(s) == 0:
+ continue
+ print("Sending " + str(s))
+ set_write_address(addr, s.start_address)
+ for i in xrange(0, len(s), 8):
+ chunk = s.data[i:i+8]
+ if len(chunk) < 8:
+ chunk = chunk + ("\xFF" * (8 - len(chunk)))
+ sent_chunks += 1
+ print("\r[%.2f%%] Sending chunk %d of %d..." %
+ (sent_chunks * 100.0 / total_chunks,
+ sent_chunks, total_chunks), end="")
+ sys.stdout.flush()
+ write_data(addr, str(bytearray(chunk)))
+ print("")
+
+
+def reset_psu(addr):
+ print("Resetting PSU...")
+ try:
+ response = mei_command(addr, 0x72, timeout=10000)
+ except ModbusTimeout:
+ print("No reply from PSU reset (expected.)")
+ return
+ expected = struct.pack(">BBBB", addr, 0x2b, 0x71, 0xb2) +\
+ ("\xFF" * 7)
+ if response != expected:
+ print("Bad response to unit reset request: " +
+ response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def erase_flash(addr):
+ print("Erasing flash... ")
+ sys.stdout.flush()
+ response = mei_command(addr, 0x65, timeout=30000)
+ expected = struct.pack(">BBBB", addr, 0x2b, 0x71, 0xa5) +\
+ ("\xFF" * 7)
+ if response != expected:
+ print("Bad response to erasing flash: " +
+ response.encode('hex'))
+ raise BadMEIResponse()
+
+
+def update_psu(addr, filename):
+ pause_monitoring()
+ fwimg = hexfile.load(filename)
+ enter_bootloader(addr)
+ start_programming(addr)
+ challenge = get_challenge(addr)
+ send_key(addr, delta_seccalckey(challenge))
+ erase_flash(addr)
+ send_image(addr, fwimg)
+ verify_flash(addr)
+ reset_psu(addr)
+
+
+def main():
+ args = parser.parse_args()
+ try:
+ update_psu(args.addr, args.file)
+ except:
+ traceback.print_exc()
+ print("Firmware update failed")
+ resume_monitoring()
+ sys.exit(1)
+ resume_monitoring()
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py
new file mode 100644
index 0000000..e93dfae
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmon-config.py
@@ -0,0 +1,93 @@
+from __future__ import print_function
+import struct
+import socket
+import os, os.path
+
+reglist = [
+ {"begin": 0x0, #MFR_MODEL
+ "length": 8},
+ {"begin": 0x10, #MFR_DATE
+ "length": 8},
+ {"begin": 0x20, #FB Part #
+ "length": 8},
+ {"begin": 0x30, #HW Revision
+ "length": 4},
+ {"begin": 0x38, #FW Revision
+ "length": 4},
+ {"begin": 0x40, #MFR Serial #
+ "length": 16},
+ {"begin": 0x60, #Workorder #
+ "length": 4},
+ {"begin": 0x68, #PSU Status
+ "length": 1,
+ "keep": 10, # 10-sample ring buffer
+ "flags": 1},
+ {"begin": 0x69, #Battery Status
+ "length": 1,
+ "keep": 10, # 10-sample ring buffer
+ "flags": 1},
+ {"begin": 0x80, #Input VAC
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x82, #Input Current AC
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x84, #Battery Voltage
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x86, #Battery Current Output
+ "length": 1},
+ {"begin": 0x88, #Battery Current Input
+ "length": 1},
+ {"begin": 0x8A, #Output Voltage (main converter)
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x8C, #Output Current (main converter)
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x8E, #IT Load Voltage Output
+ "length": 1},
+ {"begin": 0x90, #IT Load Current Output
+ "length": 1},
+ {"begin": 0x92, #Bulk Cap Voltage
+ "length": 1},
+ {"begin": 0x94, #Input Power
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x96, #Output Power
+ "length": 1,
+ "keep": 10},
+ {"begin": 0x98, #RPM Fan 0
+ "length": 1},
+ {"begin": 0x9A, #RPM Fan 1
+ "length": 1},
+ {"begin": 0x9E, #Temp 0
+ "length": 1},
+ {"begin": 0xA0, #Temp 1
+ "length": 1},
+]
+
+def main():
+ COMMAND_TYPE_SET_CONFIG = 2
+ config_command = struct.pack("@HxxH",
+ COMMAND_TYPE_SET_CONFIG,
+ len(reglist))
+ for r in reglist:
+ keep = 1
+ if "keep" in r:
+ keep = r["keep"]
+ flags = 0
+ if "flags" in r:
+ flags = r["flags"]
+ monitor_interval = struct.pack("@HHHH", r["begin"], r["length"], keep, flags)
+ config_command += monitor_interval
+
+ config_packet = struct.pack("H", len(config_command)) + config_command
+ srvpath = "/var/run/rackmond.sock"
+ if os.path.exists(srvpath):
+ client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ client.connect(srvpath)
+ client.send(config_packet)
+
+if __name__ == "__main__":
+ main()
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c
new file mode 100644
index 0000000..cce3ba4
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.c
@@ -0,0 +1,637 @@
+#include "modbus.h"
+#include "rackmond.h"
+#include <string.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <poll.h>
+#include <time.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <signal.h>
+
+#define MAX_ACTIVE_ADDRS 12
+#define REGISTER_PSU_STATUS 0x68
+
+struct _lock_holder {
+ pthread_mutex_t *lock;
+ int held;
+};
+
+#define lock_holder(holder_name, lock_expr) \
+ struct _lock_holder holder_name; \
+ holder_name.lock = lock_expr; \
+ holder_name.held = 0;
+
+#define lock_take(holder_name) { \
+ pthread_mutex_lock(holder_name.lock); \
+ holder_name.held = 1; \
+}
+
+#define lock_release(holder_name) { \
+ if(holder_name.held) { \
+ pthread_mutex_unlock(holder_name.lock); \
+ holder_name.held = 0; \
+ } \
+}
+
+int scanning = 0;
+
+typedef struct _rs485_dev {
+ // hold this for the duration of a command
+ pthread_mutex_t lock;
+ int tty_fd;
+ int gpio_fd;
+} rs485_dev;
+
+typedef struct _register_req {
+ uint16_t begin;
+ int num;
+} register_req;
+
+typedef struct register_range_data {
+ monitor_interval* i;
+ void* mem_begin;
+ size_t mem_pos;
+} register_range_data;
+
+typedef struct monitoring_data {
+ uint8_t addr;
+ register_range_data range_data[1];
+} monitoring_data;
+
+typedef struct _rackmond_data {
+ // global rackmond lock
+ pthread_mutex_t lock;
+ // number of register read commands to send to each PSU
+ int num_reqs;
+ // register read commands (begin+length)
+ register_req *reqs;
+ monitoring_config *config;
+
+ uint8_t num_active_addrs;
+ uint8_t active_addrs[MAX_ACTIVE_ADDRS];
+ monitoring_data* stored_data[MAX_ACTIVE_ADDRS];
+ FILE *status_log;
+
+ // timeout in nanosecs
+ int modbus_timeout;
+
+ int paused;
+
+ rs485_dev rs485;
+} rackmond_data;
+
+rackmond_data world;
+
+char psu_address(int rack, int shelf, int psu) {
+ int rack_a = ((rack & 3) << 3);
+ int shelf_a = ((shelf & 1) << 2);
+ int psu_a = (psu & 3);
+ return 0xA0 | rack_a | shelf_a | psu_a;
+}
+
+int modbus_command(rs485_dev* dev, int timeout, char* command, size_t len, char* destbuf, size_t dest_limit, size_t expect) {
+ int error = 0;
+ lock_holder(devlock, &dev->lock);
+ modbus_req req;
+ req.tty_fd = dev->tty_fd;
+ req.gpio_fd = dev->gpio_fd;
+ req.modbus_cmd = command;
+ req.cmd_len = len;
+ req.dest_buf = destbuf;
+ req.dest_limit = dest_limit;
+ req.timeout = timeout;
+ req.expected_len = expect != 0 ? expect : dest_limit;
+ req.scan = scanning;
+ lock_take(devlock);
+ int cmd_error = modbuscmd(&req);
+ CHECK(cmd_error);
+cleanup:
+ lock_release(devlock);
+ if (error >= 0) {
+ return req.dest_len;
+ }
+
+ return error;
+}
+
+int read_registers(rs485_dev *dev, int timeout, uint8_t addr, uint16_t begin, uint16_t num, uint16_t* out) {
+ int error = 0;
+ // address, function, begin, length in # of regs
+ char command[sizeof(addr) + 1 + sizeof(begin) + sizeof(num)];
+ // address, function, length (1 byte), data (2 bytes per register), crc
+ // (VLA)
+ char response[sizeof(addr) + 1 + 1 + (2 * num) + 2];
+ command[0] = addr;
+ command[1] = MODBUS_READ_HOLDING_REGISTERS;
+ command[2] = begin << 8;
+ command[3] = begin & 0xFF;
+ command[4] = num << 8;
+ command[5] = num & 0xFF;
+
+ int dest_len =
+ modbus_command(
+ dev, timeout,
+ command, sizeof(addr) + 1 + sizeof(begin) + sizeof(num),
+ response, sizeof(addr) + 1 + 1 + (2 * num) + 2, 0);
+ CHECK(dest_len);
+
+ if (dest_len >= 5) {
+ memcpy(out, response + 3, num * 2);
+ } else {
+ log("Unexpected short but CRC correct response!\n");
+ error = -1;
+ goto cleanup;
+ }
+ if (response[0] != addr) {
+ log("Got response for addr %02x when expected %02x\n", response[0], addr);
+ error = -1;
+ goto cleanup;
+ }
+ if (response[2] != (num * 2)) {
+ log("Got %d register data bytes when expecting %d\n", response[2], (num * 2));
+ error = -1;
+ goto cleanup;
+ }
+cleanup:
+ return error;
+}
+
+int sub_uint8s(const void* a, const void* b) {
+ return (*(uint8_t*)a) - (*(uint8_t*)b);
+}
+
+int check_active_psus() {
+ int error = 0;
+ lock_holder(worldlock, &world.lock);
+ lock_take(worldlock);
+ if (world.paused == 1) {
+ usleep(1000);
+ goto cleanup;
+ }
+ if (world.config == NULL) {
+ lock_release(worldlock);
+ usleep(5000);
+ goto cleanup;
+ }
+ world.num_active_addrs = 0;
+
+ scanning = 1;
+ //fprintf(stderr, "Begin presence check: ");
+ for(int rack = 0; rack < 3; rack++) {
+ for(int shelf = 0; shelf < 2; shelf++) {
+ for(int psu = 0; psu < 3; psu++) {
+ char addr = psu_address(rack, shelf, psu);
+ uint16_t status = 0;
+ int err = read_registers(&world.rs485, world.modbus_timeout, addr, REGISTER_PSU_STATUS, 1, &status);
+ if (err == 0) {
+ world.active_addrs[world.num_active_addrs] = addr;
+ world.num_active_addrs++;
+ //fprintf(stderr, "%02x - active (%04x) ", addr, status);
+ } else {
+ dbg("%02x - %d; ", addr, err);
+ }
+ }
+ }
+ }
+ //its the only stdlib sort
+ qsort(world.active_addrs, world.num_active_addrs,
+ sizeof(uint8_t), sub_uint8s);
+cleanup:
+ scanning = 0;
+ lock_release(worldlock);
+ return error;
+}
+
+monitoring_data* alloc_monitoring_data(uint8_t addr) {
+ size_t size = sizeof(monitoring_data) +
+ sizeof(register_range_data) * world.config->num_intervals;
+ for(int i = 0; i < world.config->num_intervals; i++) {
+ monitor_interval *iv = &world.config->intervals[i];
+ int pitch = sizeof(uint32_t) + (sizeof(uint16_t) * iv->len);
+ int data_size = pitch * iv->keep;
+ size += data_size;
+ }
+ monitoring_data* d = calloc(1, size);
+ if (d == NULL) {
+ log("Failed to allocate memory for sensor data.\n");
+ return NULL;
+ }
+ d->addr = addr;
+ void* mem = d;
+ mem = mem + (sizeof(monitoring_data) +
+ sizeof(register_range_data) * world.config->num_intervals);
+ for(int i = 0; i < world.config->num_intervals; i++) {
+ monitor_interval *iv = &world.config->intervals[i];
+ int pitch = sizeof(uint32_t) + (sizeof(uint16_t) * iv->len);
+ int data_size = pitch * iv->keep;
+ d->range_data[i].i = iv;
+ d->range_data[i].mem_begin = mem;
+ d->range_data[i].mem_pos = 0;
+ mem = mem + data_size;
+ }
+ return d;
+}
+
+int sub_storeptrs(const void* va, const void *vb) {
+ //more *s than i like :/
+ monitoring_data* a = *(monitoring_data**)va;
+ monitoring_data* b = *(monitoring_data**)vb;
+ //nulls to the end
+ if (b == NULL && a == NULL) {
+ return 0;
+ }
+ if (b == NULL) {
+ return -1;
+ }
+ if (a == NULL) {
+ return 1;
+ }
+ return a->addr - b->addr;
+}
+
+int alloc_monitoring_datas() {
+ int error = 0;
+ if (world.config == NULL) {
+ goto cleanup;
+ }
+ qsort(world.stored_data, MAX_ACTIVE_ADDRS,
+ sizeof(monitoring_data*), sub_storeptrs);
+ int data_pos = 0;
+ for(int i = 0; i < world.num_active_addrs; i++) {
+ uint8_t addr = world.active_addrs[i];
+ while(world.stored_data[data_pos] != NULL &&
+ world.stored_data[data_pos]->addr != addr) {
+ data_pos++;
+ }
+ if (world.stored_data[data_pos] == NULL) {
+ log("Detected PSU at address 0x%02x\n", addr);
+ //syslog(LOG_INFO, "Detected PSU at address 0x%02x", addr);
+ world.stored_data[data_pos] = alloc_monitoring_data(addr);
+ if (world.stored_data[data_pos] == NULL) {
+ BAIL("allocation failed\n");
+ }
+ //reset search pos after alloc (post-sorted addrs may already be alloc'd, need to check again)
+ data_pos = 0;
+ continue;
+ }
+ if (world.stored_data[data_pos]->addr == addr) {
+ continue;
+ }
+ BAIL("shouldn't get here!\n");
+ }
+cleanup:
+ return error;
+}
+
+void record_data(register_range_data* rd, uint32_t time, uint16_t* regs) {
+ int n_regs = (rd->i->len);
+ int pitch = sizeof(time) + (sizeof(uint16_t) * n_regs);
+ int mem_size = pitch * rd->i->keep;
+
+ memcpy(rd->mem_begin + rd->mem_pos, &time, sizeof(time));
+ rd->mem_pos += sizeof(time);
+ memcpy(rd->mem_begin + rd->mem_pos, regs, n_regs * sizeof(uint16_t));
+ rd->mem_pos += n_regs * sizeof(uint16_t);
+ rd->mem_pos = rd->mem_pos % mem_size;
+}
+
+int fetch_monitored_data() {
+ int error = 0;
+ int data_pos = 0;
+ lock_holder(worldlock, &world.lock);
+ lock_take(worldlock);
+ if (world.paused == 1) {
+ usleep(1000);
+ goto cleanup;
+ }
+ if (world.config == NULL) {
+ goto cleanup;
+ }
+ lock_release(worldlock);
+
+ usleep(1000); // wait a sec btween PSUs to not overload RT scheduling
+ // threshold
+ while(world.stored_data[data_pos] != NULL && data_pos < MAX_ACTIVE_ADDRS) {
+ uint8_t addr = world.stored_data[data_pos]->addr;
+ //log("readpsu %02x\n", addr);
+ for(int r = 0; r < world.config->num_intervals; r++) {
+ register_range_data* rd = &world.stored_data[data_pos]->range_data[r];
+ monitor_interval* i = rd->i;
+ uint16_t regs[i->len];
+ int err = read_registers(&world.rs485,
+ world.modbus_timeout, addr, i->begin, i->len, regs);
+ if (err) {
+ log("Error %d reading %02x registers at %02x from %02x\n",
+ err, i->len, i->begin, addr);
+ continue;
+ }
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ uint32_t timestamp = ts.tv_sec;
+ if (rd->i->flags & MONITOR_FLAG_ONLY_CHANGES) {
+ int pitch = sizeof(timestamp) + (sizeof(uint16_t) * i->len);
+ int lastpos = rd->mem_pos - pitch;
+ if (lastpos < 0) {
+ lastpos = (pitch * rd->i->keep) - pitch;
+ }
+ if (!memcmp(rd->mem_begin + lastpos + sizeof(timestamp),
+ regs, sizeof(uint16_t) * i->len) &&
+ memcmp(rd->mem_begin, "\x00\x00\x00\x00", 4)) {
+ continue;
+ }
+
+ if (world.status_log) {
+ time_t rawt;
+ struct tm* ti;
+ time(&rawt);
+ ti = localtime(&rawt);
+ char timestr[80];
+ strftime(timestr, sizeof(timestr), "%b %e %T", ti);
+ fprintf(world.status_log,
+ "%s: Change to status register %02x on address %02x. New value: %02x\n",
+ timestr, i->begin, addr, regs[0]);
+ fflush(world.status_log);
+ }
+
+ }
+ lock_take(worldlock);
+ record_data(rd, timestamp, regs);
+ lock_release(worldlock);
+ }
+ data_pos++;
+ }
+cleanup:
+ lock_release(worldlock);
+ return error;
+}
+
+// check for new psus every N rounds of sensor reads
+#define SEARCH_PSUS_EVERY 200
+void* monitoring_loop(void* arg) {
+ (void) arg;
+ int until_search = 0;
+ world.status_log = fopen("/var/log/psu-status.log", "a+");
+ while(1) {
+ if (until_search == 0) {
+ check_active_psus();
+ alloc_monitoring_datas();
+ until_search = SEARCH_PSUS_EVERY;
+ } else {
+ until_search--;
+ }
+ fetch_monitored_data();
+ }
+ return NULL;
+}
+
+int open_rs485_dev(const char* tty_filename, int gpio_num, rs485_dev *dev) {
+ int error = 0;
+ int tty_fd, gpio_fd;
+ char gpio_filename[128];
+ dbg("[*] Opening TTY\n");
+ tty_fd = open(tty_filename, O_RDWR | O_NOCTTY);
+ CHECK(tty_fd);
+
+ dbg("[*] Opening GPIO %d\n", gpio_num);
+ snprintf(gpio_filename, sizeof(gpio_filename), "/sys/class/gpio/gpio%d/value", gpio_num);
+ gpio_fd = open(gpio_filename, O_WRONLY | O_SYNC);
+ CHECK(gpio_fd);
+
+ dev->tty_fd = tty_fd;
+ dev->gpio_fd = gpio_fd;
+ pthread_mutex_init(&dev->lock, NULL);
+cleanup:
+ return error;
+}
+
+int do_command(int sock, rackmond_command* cmd) {
+ int error = 0;
+ lock_holder(worldlock, &world.lock);
+ switch(cmd->type) {
+ case COMMAND_TYPE_RAW_MODBUS:
+ {
+ uint16_t expected = cmd->raw_modbus.expected_response_length;
+ int timeout = world.modbus_timeout;
+ if (cmd->raw_modbus.custom_timeout) {
+ //ms to us
+ timeout = cmd->raw_modbus.custom_timeout * 1000;
+ }
+ if (expected == 0) {
+ expected = 1024;
+ }
+ char response[expected];
+ int response_len = modbus_command(
+ &world.rs485, timeout,
+ cmd->raw_modbus.data, cmd->raw_modbus.length,
+ response, expected, expected);
+ uint16_t response_len_wire = response_len;
+ if(response_len < 0) {
+ uint16_t error = -response_len;
+ response_len_wire = 0;
+ send(sock, &response_len_wire, sizeof(uint16_t), 0);
+ send(sock, &error, sizeof(uint16_t), 0);
+ break;
+ }
+ send(sock, &response_len_wire, sizeof(uint16_t), 0);
+ send(sock, response, response_len, 0);
+ break;
+ }
+ case COMMAND_TYPE_SET_CONFIG:
+ {
+ lock_take(worldlock);
+ if (world.config != NULL) {
+ BAIL("rackmond already configured\n");
+ }
+ size_t config_size = sizeof(monitoring_config) +
+ (sizeof(monitor_interval) * cmd->set_config.config.num_intervals);
+ world.config = calloc(1, config_size);
+ memcpy(world.config, &cmd->set_config.config, config_size);
+ syslog(LOG_INFO, "got configuration");
+ lock_release(worldlock);
+ break;
+ }
+ case COMMAND_TYPE_DUMP_DATA_JSON:
+ {
+ lock_take(worldlock);
+ if (world.config == NULL) {
+ send(sock, "[]", 2, 0);
+ } else {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ uint32_t now = ts.tv_sec;
+ send(sock, "[", 1, 0);
+ int data_pos = 0;
+ while(world.stored_data[data_pos] != NULL && data_pos < MAX_ACTIVE_ADDRS) {
+ dprintf(sock, "{\"addr\":%d,\"now\":%d,\"ranges\":[",
+ world.stored_data[data_pos]->addr, now);
+ for(int i = 0; i < world.config->num_intervals; i++) {
+ uint32_t time;
+ register_range_data *rd = &world.stored_data[data_pos]->range_data[i];
+ char* mem_pos = rd->mem_begin;
+ dprintf(sock,"{\"begin\":%d,\"readings\":[", rd->i->begin);
+ // want to cut the list off early just before
+ // the first entry with time == 0
+ memcpy(&time, mem_pos, sizeof(time));
+ for(int j = 0; j < rd->i->keep && time != 0; j++) {
+ mem_pos += sizeof(time);
+ dprintf(sock, "{\"time\":%d,\"data\":\"", time);
+ for(int c = 0; c < rd->i->len * 2; c++) {
+ dprintf(sock, "%02x", *mem_pos);
+ mem_pos++;
+ }
+ send(sock, "\"}", 2, 0);
+ memcpy(&time, mem_pos, sizeof(time));
+ if (time == 0) {
+ break;
+ }
+ if ((j+1) < rd->i->keep) {
+ send(sock, ",", 1, 0);
+ }
+ }
+ send(sock, "]}", 2, 0);
+ if ((i+1) < world.config->num_intervals) {
+ send(sock, ",", 1, 0);
+ }
+ }
+ data_pos++;
+ if (data_pos < MAX_ACTIVE_ADDRS && world.stored_data[data_pos] != NULL) {
+ send(sock, "]},", 3, 0);
+ } else {
+ send(sock, "]}", 2, 0);
+ }
+ }
+ send(sock, "]", 1, 0);
+ }
+ lock_release(worldlock);
+ break;
+ }
+ case COMMAND_TYPE_PAUSE_MONITORING:
+ {
+ lock_take(worldlock);
+ uint8_t was_paused = world.paused;
+ world.paused = 1;
+ send(sock, &was_paused, sizeof(was_paused), 0);
+ lock_release(worldlock);
+ break;
+ }
+ case COMMAND_TYPE_START_MONITORING:
+ {
+ lock_take(worldlock);
+ uint8_t was_started = !world.paused;
+ world.paused = 0;
+ send(sock, &was_started, sizeof(was_started), 0);
+ lock_release(worldlock);
+ break;
+ }
+ default:
+ CHECK(-1);
+ }
+cleanup:
+ lock_release(worldlock);
+ return error;
+}
+
+typedef enum {
+ CONN_WAITING_LENGTH,
+ CONN_WAITING_BODY
+} rackmond_connection_state;
+
+// receive the command as a length prefixed block
+// (uint16_t, followed by data)
+// this is all over a local socket, won't be doing
+// endian flipping, clients should only be local procs
+// compiled for the same arch
+int handle_connection(int sock) {
+ int error = 0;
+ rackmond_connection_state state = CONN_WAITING_LENGTH;
+ char bodybuf[1024];
+ uint16_t expected_len = 0;
+ struct pollfd pfd;
+ int recvret = 0;
+ pfd.fd = sock;
+ pfd.events = POLLIN | POLLERR | POLLHUP;
+ // if you don't do anything for a whole second we bail
+next:
+ CHECKP(poll, poll(&pfd, 1, 1000));
+ if (pfd.revents & (POLLERR | POLLHUP)) {
+ goto cleanup;
+ }
+ switch(state) {
+ case CONN_WAITING_LENGTH:
+ recvret = recv(sock, &expected_len, 2, MSG_DONTWAIT);
+ if (recvret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ goto next;
+ }
+ if (expected_len == 0 || expected_len > sizeof(bodybuf)) {
+ // bad length; bail
+ goto cleanup;
+ }
+ state = CONN_WAITING_BODY;
+ goto next;
+ break;
+ case CONN_WAITING_BODY:
+ recvret = recv(sock, &bodybuf, expected_len, MSG_DONTWAIT);
+ if (recvret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ goto next;
+ }
+ CHECK(do_command(sock, (rackmond_command*) bodybuf));
+ }
+cleanup:
+ close(sock);
+ if (error != 0) {
+ fprintf(stderr, "Warning: possible error handling user connection (%d)\n", error);
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (getenv("RACKMOND_FOREGROUND") == NULL) {
+ daemon(0, 0);
+ }
+ signal(SIGPIPE, SIG_IGN);
+ int error = 0;
+ world.paused = 0;
+ world.modbus_timeout = 300000;
+ if (getenv("RACKMOND_TIMEOUT") != NULL) {
+ world.modbus_timeout = atoll(getenv("RACKMOND_TIMEOUT"));
+ fprintf(stderr, "Timeout from env: %dms\n",
+ (world.modbus_timeout / 1000));
+ }
+ world.config = NULL;
+ pthread_mutex_init(&world.lock, NULL);
+ verbose = getenv("RACKMOND_VERBOSE") != NULL ? 1 : 0;
+ openlog("rackmond", 0, LOG_USER);
+ syslog(LOG_INFO, "rackmon/modbus service starting");
+ CHECK(open_rs485_dev(DEFAULT_TTY, DEFAULT_GPIO, &world.rs485));
+ pthread_t monitoring_thread;
+ pthread_create(&monitoring_thread, NULL, monitoring_loop, NULL);
+ struct sockaddr_un local, client;
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ strcpy(local.sun_path, "/var/run/rackmond.sock");
+ local.sun_family = AF_UNIX;
+ int socknamelen = sizeof(local.sun_family) + strlen(local.sun_path);
+ unlink(local.sun_path);
+ CHECKP(bind, bind(sock, (struct sockaddr *)&local, socknamelen));
+ CHECKP(listen, listen(sock, 5));
+ syslog(LOG_INFO, "rackmon/modbus service listening");
+ while(1) {
+ socklen_t clisocklen = sizeof(struct sockaddr_un);
+ int clisock = accept(sock, (struct sockaddr*) &client, &clisocklen);
+ CHECKP(accept, clisock);
+ CHECK(handle_connection(clisock));
+ }
+
+cleanup:
+ if (error != 0) {
+ error = 1;
+ }
+ return error;
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h
new file mode 100644
index 0000000..2c0e8a0
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmond.h
@@ -0,0 +1,46 @@
+#include <stdint.h>
+
+//would've been nice to have thrift
+
+// Raw modbus command
+// Response is just the raw response data
+typedef struct raw_modbus_command {
+ uint16_t length;
+ uint16_t expected_response_length;
+ uint32_t custom_timeout; // 0 for default
+ char data[1];
+} raw_modbus_command;
+
+// only store new value if different from most recent
+// (for watching changes to status flags registers)
+#define MONITOR_FLAG_ONLY_CHANGES 0x1
+
+typedef struct monitor_interval {
+ uint16_t begin;
+ uint16_t len;
+ uint16_t keep; // How long of a history to keep?
+ uint16_t flags;
+} monitor_interval;
+
+typedef struct monitoring_config {
+ uint16_t num_intervals;
+ monitor_interval intervals[1];
+} monitoring_config;
+
+typedef struct set_config_command {
+ monitoring_config config;
+} set_config_command;
+
+#define COMMAND_TYPE_RAW_MODBUS 0x01
+#define COMMAND_TYPE_SET_CONFIG 0x02
+#define COMMAND_TYPE_DUMP_DATA_JSON 0x03
+#define COMMAND_TYPE_PAUSE_MONITORING 0x04
+#define COMMAND_TYPE_START_MONITORING 0x05
+
+typedef struct rackmond_command {
+ uint16_t type;
+ union {
+ raw_modbus_command raw_modbus;
+ set_config_command set_config;
+ };
+} rackmond_command;
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c
new file mode 100644
index 0000000..391b5be
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/rackmondata.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include "modbus.h"
+#include "rackmond.h"
+
+int main(int argc, char **argv) {
+ int error = 0;
+ rackmond_command cmd;
+ int clisock;
+ uint16_t wire_cmd_len = sizeof(cmd);
+ struct sockaddr_un rackmond_addr;
+ cmd.type = COMMAND_TYPE_DUMP_DATA_JSON;
+ clisock = socket(AF_UNIX, SOCK_STREAM, 0);
+ CHECKP(socket, clisock);
+ rackmond_addr.sun_family = AF_UNIX;
+ strcpy(rackmond_addr.sun_path, "/var/run/rackmond.sock");
+ int addr_len = strlen(rackmond_addr.sun_path) + sizeof(rackmond_addr.sun_family);
+ CHECKP(connect, connect(clisock, (struct sockaddr*) &rackmond_addr, addr_len));
+ CHECKP(send, send(clisock, &wire_cmd_len, sizeof(wire_cmd_len), 0));
+ CHECKP(send, send(clisock, &cmd, wire_cmd_len, 0));
+ char readbuf[256];
+ ssize_t n_read;
+ while((n_read = read(clisock, readbuf, sizeof(readbuf))) > 0) {
+ write(1, readbuf, n_read);
+ }
+cleanup:
+ if(error != 0) {
+ if(errno != 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ }
+ error = 1;
+ }
+ return error;
+}
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh
new file mode 100644
index 0000000..85a1e22
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon/setup-rackmond.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+### BEGIN INIT INFO
+# Provides: setup-rackmond
+# Required-Start:
+# Required-Stop:
+# Default-Start: S
+# Default-Stop:
+# Short-Description: Start Rackmon service
+### END INIT INFO
+
+echo -n "Starting rackmon background service..."
+/usr/local/bin/rackmond
+echo "done."
+
+echo -n "Configuring rackmon service..."
+python /etc/rackmon-config.py
+echo "done."
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb
index d3e79e4..399f7c0 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/rackmon/rackmon_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Rackmon Functionality"
DESCRIPTION = "Rackmon Functionality"
SECTION = "base"
@@ -6,7 +21,7 @@ PR = "r1"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://modbus.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
-#DEPENDS_append = " update-rc.d-native"
+DEPENDS_append = " update-rc.d-native"
SRC_URI = "file://Makefile \
file://modbuscmd.c \
@@ -14,6 +29,13 @@ SRC_URI = "file://Makefile \
file://modbus.c \
file://modbus.h \
file://gpiowatch.c \
+ file://rackmond.c \
+ file://rackmond.h \
+ file://rackmondata.c \
+ file://setup-rackmond.sh \
+ file://rackmon-config.py \
+ file://psu-update-delta.py \
+ file://hexfile.py \
"
S = "${WORKDIR}"
@@ -21,6 +43,10 @@ S = "${WORKDIR}"
binfiles = "modbuscmd \
modbussim \
gpiowatch \
+ rackmond \
+ rackmondata \
+ psu-update-delta.py \
+ hexfile.py \
"
#otherfiles = "README"
@@ -36,6 +62,11 @@ do_install() {
install -m 755 $f ${dst}/$f
ln -snf ../fbpackages/${pkgdir}/$f ${bin}/$f
done
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${sysconfdir}/rcS.d
+ install -m 755 setup-rackmond.sh ${D}${sysconfdir}/init.d/setup-rackmond.sh
+ install -m 755 rackmon-config.py ${D}${sysconfdir}/rackmon-config.py
+ update-rc.d -r ${D} setup-rackmond.sh start 95 2 3 4 5 .
}
FBPACKAGEDIR = "${prefix}/local/fbpackages"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py
index 6d59fd6..52c98d9 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest.py
@@ -20,14 +20,24 @@
from ctypes import *
-from bottle import route, run, template, request, response
+from bottle import route, run, template, request, response, ServerAdapter
from bottle import abort
+from wsgiref.simple_server import make_server, WSGIRequestHandler, WSGIServer
import json
-from rest_fruid import *
-from rest_server import *
-from rest_sensors import *
-from rest_bmc import *
-from rest_gpios import *
+import ssl
+import socket
+import os
+import rest_fruid
+import rest_server
+import rest_sensors
+import rest_bmc
+import rest_gpios
+import rest_modbus
+import rest_slotid
+
+CONSTANTS = {
+ 'certificate': '/usr/lib/ssl/certs/rest_server.pem',
+}
# Handler for root resource endpoint
@route('/api')
@@ -50,7 +60,8 @@ def rest_sys():
"Description": "Wedge System",
},
"Actions": [],
- "Resources": [ "mb", "bmc", "server", "sensors", "gpios"],
+ "Resources": [ "mb", "bmc", "server", "sensors", "gpios",
+ "modbus_registers", "slotid"],
}
return result
@@ -70,33 +81,72 @@ def rest_sys():
# Handler for sys/mb/fruid resource endpoint
@route('/api/sys/mb/fruid')
-def rest_fruid():
- return get_fruid()
+def rest_fruid_hdl():
+ return rest_fruid.get_fruid()
# Handler for sys/bmc resource endpoint
@route('/api/sys/bmc')
-def rest_bmc():
- return get_bmc()
+def rest_bmc_hdl():
+ return rest_bmc.get_bmc()
# Handler for sys/server resource endpoint
@route('/api/sys/server')
-def rest_bmc():
- return get_server()
+def rest_server_hdl():
+ return rest_server.get_server()
# Handler for uServer resource endpoint
@route('/api/sys/server', method='POST')
-def rest_server():
+def rest_server_act_hdl():
data = json.load(request.body)
- return server_action(data)
+ return rest_server.server_action(data)
# Handler for sensors resource endpoint
@route('/api/sys/sensors')
-def rest_sensors():
- return get_sensors()
+def rest_sensors_hdl():
+ return rest_sensors.get_sensors()
# Handler for sensors resource endpoint
@route('/api/sys/gpios')
-def rest_gpios():
- return get_gpios()
+def rest_gpios_hdl():
+ return rest_gpios.get_gpios()
+
+@route('/api/sys/modbus_registers')
+def modbus_registers_hdl():
+ return rest_modbus.get_modbus_registers()
+
+# Handler for sensors resource endpoint
+@route('/api/sys/slotid')
+def rest_slotid_hdl():
+ return rest_slotid.get_slotid()
run(host = "::", port = 8080)
+
+# SSL Wrapper for Rest API
+class SSLWSGIRefServer(ServerAdapter):
+ def run(self, handler):
+ if self.quiet:
+ class QuietHandler(WSGIRequestHandler):
+ def log_request(*args, **kw): pass
+ self.options['handler_class'] = QuietHandler
+
+ # IPv6 Support
+ server_cls = self.options.get('server_class', WSGIServer)
+
+ if ':' in self.host:
+ if getattr(server_cls, 'address_family') == socket.AF_INET:
+ class server_cls(server_cls):
+ address_family = socket.AF_INET6
+
+ srv = make_server(self.host, self.port, handler,
+ server_class=server_cls, **self.options)
+ srv.socket = ssl.wrap_socket (
+ srv.socket,
+ certfile=CONSTANTS['certificate'],
+ server_side=True)
+ srv.serve_forever()
+
+# Use SSL if the certificate exists. Otherwise, run without SSL.
+if os.access(CONSTANTS['certificate'], os.R_OK):
+ run(server=SSLWSGIRefServer(host="::", port=8443))
+else:
+ run(host = "::", port = 8080)
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py
index d9600ae..c4f661e 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_bmc.py
@@ -20,6 +20,7 @@
from subprocess import *
+import re
# Handler for FRUID resource endpoint
def get_bmc():
@@ -51,6 +52,14 @@ def get_bmc():
mem_usage = adata[0]
cpu_usage = adata[1]
+ # Get OpenBMC version
+ version = ""
+ data = Popen('cat /etc/issue', \
+ shell=True, stdout=PIPE).stdout.read()
+ ver = re.search(r'v([\w\d._-]*)\s', data)
+ if ver:
+ version = ver.group(1)
+
result = {
"Information": {
"Description": "Wedge BMC",
@@ -58,6 +67,7 @@ def get_bmc():
"Uptime": uptime,
"Memory Usage": mem_usage,
"CPU Usage": cpu_usage,
+ "OpenBMC Version": version,
},
"Actions": [],
"Resources": [],
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py
new file mode 100644
index 0000000..9d213fc
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_modbus.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+#
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+import subprocess
+from subprocess import Popen
+
+# Handler for sensors resource endpoint
+def get_modbus_registers():
+ p = Popen('/usr/local/bin/rackmondata', stdout=subprocess.PIPE)
+ out, err = p.communicate()
+ return out
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py
index f4f83d3..fa65372 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_sensors.py
@@ -39,12 +39,10 @@ def get_sensors():
if (len(tdata) < 2):
continue
sresult[tdata[0].strip()] = tdata[1].strip()
- result.append(sresult)
-
+ result.append(sresult)
fresult = {
"Information": result,
"Actions": [],
"Resources": [],
}
-
return fresult
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py
new file mode 100644
index 0000000..ee407ac
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/rest_slotid.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
+import subprocess
+
+# Handler for sensors resource endpoint
+def get_slotid():
+ p = subprocess.Popen('source /usr/local/bin/openbmc-utils.sh;'
+ 'wedge_slot_id $(wedge_board_type)',
+ shell=True, stdout=subprocess.PIPE)
+ out, err = p.communicate()
+ try:
+ slot = int(out.strip('\n'))
+ except:
+ slot = 0
+ return { 'slotid' : slot }
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh
index fe01c23..bdd79b6 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/files/setup-rest-api.sh
@@ -2,6 +2,22 @@
#
# Copyright 2014-present Facebook. All Rights Reserved.
#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
### BEGIN INIT INFO
# Provides: setup-rest-api
# Required-Start:
diff --git a/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb
index 2753f30..5dec4bf 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/rest-api/rest-api_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Rest API Daemon"
DESCRIPTION = "Daemon to handle RESTful interface."
SECTION = "base"
@@ -16,11 +31,13 @@ SRC_URI = "file://setup-rest-api.sh \
file://rest_gpios.py \
file://rest_server.py \
file://rest_sensors.py \
+ file://rest_modbus.py \
+ file://rest_slotid.py \
"
S = "${WORKDIR}"
-binfiles = "rest.py rest_bmc.py rest_fruid.py rest_gpios.py rest_server.py rest_sensors.py setup-rest-api.sh"
+binfiles = "rest.py rest_bmc.py rest_fruid.py rest_gpios.py rest_server.py rest_sensors.py rest_modbus.py rest_slotid.py setup-rest-api.sh"
pkgdir = "rest-api"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb
index ad6bb0c..1b0f937 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/sensor-setup/sensor-setup_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Configure the sensors"
DESCRIPTION = "The script configure sensors"
SECTION = "base"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile
index 6425261..dba9dbb 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/Makefile
@@ -1,4 +1,20 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
all: sms-kcsd
sms-kcsd: sms-kcsd.c
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh
index d369f5c..b4234a4 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh
+++ b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd/setup-sms-kcs.sh
@@ -2,6 +2,22 @@
#
# Copyright 2014-present Facebook. All Rights Reserved.
#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+
### BEGIN INIT INFO
# Provides: setup-sms-kcs
# Required-Start:
diff --git a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb
index 1f3ea08..812d815 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/sms-kcsd/sms-kcsd_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "SMS KCS Daemon"
DESCRIPTION = "Daemon to handle SMS KCS interface."
SECTION = "base"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb
index f92511c..c934f46 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/usb-console/usb-console_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Set up a USB serial console"
DESCRIPTION = "Sets up a USB serial console"
SECTION = "base"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile
index 0264efe..8c05686 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/Makefile
@@ -1,8 +1,24 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
lib: libwedge_eeprom.so
libwedge_eeprom.so: wedge_eeprom.c
- $(CC) $(CCFLAGS) -fPIC -c -o wedge_eeprom.o wedge_eeprom.c
+ $(CC) $(CFLAGS) -fPIC -c -o wedge_eeprom.o wedge_eeprom.c
$(CC) -shared -o libwedge_eeprom.so wedge_eeprom.o -lc
.PHONY: clean
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c
index 44f708d..e66941e 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/lib/wedge_eeprom.c
@@ -23,9 +23,11 @@
#include <stdio.h>
#include <string.h>
-#include <facebook/log.h>
+#include <openbmc/log.h>
+#ifndef FBW_EEPROM_FILE
#define FBW_EEPROM_FILE "/sys/class/i2c-adapter/i2c-6/6-0050/eeprom"
+#endif
#define FBW_EEPROM_VERSION 0
#define FBW_EEPROM_V0_SIZE 162
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile
index 30aac75..f2aeadc 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/Makefile
@@ -1,4 +1,20 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+
utils: weutil
weutil: weutil.o
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c
index 9e932aa..90aca10 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/files/utils/weutil.c
@@ -20,7 +20,7 @@
#include <stdio.h>
#include <facebook/wedge_eeprom.h>
-#include <facebook/log.h>
+#include <openbmc/log.h>
int main(int argc, const char *argv[])
{
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb
index 781cf76..6f62557 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/libwedge-eeprom_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Wedge EEPROM Library"
DESCRIPTION = "library for wedge eeprom"
SECTION = "base"
@@ -9,7 +24,7 @@ LIC_FILES_CHKSUM = "file://wedge_eeprom.c;beginline=4;endline=16;md5=da35978751a
SRC_URI = "file://lib \
"
-DEPENDS += "fbutils"
+DEPENDS += "liblog"
S = "${WORKDIR}/lib"
@@ -22,5 +37,4 @@ do_install() {
}
FILES_${PN} = "${libdir}/libwedge_eeprom.so"
-FILES_${PN}-dbg = "${libdir}/.debug"
FILES_${PN}-dev = "${includedir}/facebook/wedge_eeprom.h"
diff --git a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb
index 51bdbb9..3afbed1 100644
--- a/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb
+++ b/meta-facebook/meta-wedge/recipes-wedge/wedge-eeprom/wedge-eeprom_0.1.bb
@@ -1,4 +1,19 @@
# Copyright 2014-present Facebook. All Rights Reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
SUMMARY = "Wedge EEPROM Utilities"
DESCRIPTION = "Util for wedge eeprom"
SECTION = "base"
OpenPOWER on IntegriCloud