diff options
Diffstat (limited to 'meta-facebook/meta-wedge/recipes-wedge')
76 files changed, 4254 insertions, 296 deletions
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" |