summaryrefslogtreecommitdiffstats
path: root/common/recipes-core/ipmbd
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-core/ipmbd')
-rw-r--r--common/recipes-core/ipmbd/files/Makefile10
-rw-r--r--common/recipes-core/ipmbd/files/ipmbd.c843
-rw-r--r--common/recipes-core/ipmbd/ipmbd_0.1.bb19
3 files changed, 872 insertions, 0 deletions
diff --git a/common/recipes-core/ipmbd/files/Makefile b/common/recipes-core/ipmbd/files/Makefile
new file mode 100644
index 0000000..719ccc3
--- /dev/null
+++ b/common/recipes-core/ipmbd/files/Makefile
@@ -0,0 +1,10 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+all: ipmbd
+
+ipmbd: ipmbd.o
+ $(CC) $(CFLAGS) -pthread -lrt -lipmi -std=gnu99 -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o ipmbd
diff --git a/common/recipes-core/ipmbd/files/ipmbd.c b/common/recipes-core/ipmbd/files/ipmbd.c
new file mode 100644
index 0000000..5ea5af3
--- /dev/null
+++ b/common/recipes-core/ipmbd/files/ipmbd.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright 2015-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.
+ */
+
+/*
+ * This module handles all the IPMB communication protocol
+ * Refer http://www.intel.com/content/www/us/en/servers/ipmi/ipmp-spec-v1-0.html
+ * for more information.
+ *
+ * IPMB packet format is described here for quick reference
+ * Request:
+ * <Responder Slave Address(rsSA)>
+ * <NetFn/ResponderLUN(Netfn/rsLUN)>
+ * <Header Checksum(hdrCksum)>
+ * <Requester Slave Address(rqSA)>
+ * <Requester Sequence Number/RequesterLUN(rqSeq/rqLUN>
+ * <Command>
+ * <Data[0..n]>
+ * <Data Checksum(dataCksum)>
+ * Response:
+ * <Requester Slave Address(rqSA)>
+ * <NetFn/RequesterLUN(Netfn/rqLUN)>
+ * <Header Checksum(hdrCksum)>
+ * <Responder Slave Address(rsSA)>
+ * <Requester Sequence Number/ResponderLUN(rqSeq/rsLUN>
+ * <Command>
+ * <Completion Code(CC)>
+ * <Data[0..n]>
+ * <Data Checksum(dataCksum)>
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <syslog.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <mqueue.h>
+#include <semaphore.h>
+
+#include "facebook/i2c-dev.h"
+#include "openbmc/ipmi.h"
+#include "openbmc/ipmb.h"
+
+//#define DEBUG 0
+
+#define MAX_BYTES 255
+
+#define MQ_IPMB_REQ "/mq_ipmb_req"
+#define MQ_IPMB_RES "/mq_ipmb_res"
+#define MQ_MAX_MSG_SIZE MAX_BYTES
+#define MQ_MAX_NUM_MSGS 10
+
+#define SEQ_NUM_MAX 64
+
+#define I2C_RETRIES_MAX 3
+
+// Structure for i2c file descriptor and socket
+typedef struct _ipmb_sfd_t {
+ int fd;
+ int sock;
+} ipmb_sfd_t;
+
+// Structure for sequence number and buffer
+typedef struct _seq_buf_t {
+ bool in_use; // seq# is being used
+ uint8_t len; // buffer size
+ uint8_t *p_buf; // pointer to buffer
+ sem_t s_seq; // semaphore for thread sync.
+} seq_buf_t;
+
+// Structure for holding currently used sequence number and
+// array of all possible sequence number
+typedef struct _ipmb_sbuf_t {
+ uint8_t curr_seq; // currently used seq#
+ seq_buf_t seq[SEQ_NUM_MAX]; //array of all possible seq# struct.
+} ipmb_sbuf_t;
+
+// Global storage for holding IPMB sequence number and buffer
+ipmb_sbuf_t g_seq;
+
+// mutex to protect global data access
+pthread_mutex_t m_seq;
+
+pthread_mutex_t m_i2c;
+
+#ifdef CONFIG_YOSEMITE
+// Returns the payload ID from IPMB bus routing
+// Slot#1: bus#3, Slot#2: bus#1, Slot#3: bus#7, Slot#4: bus#5
+static uint8_t
+get_payload_id(uint8_t bus_id) {
+ uint8_t payload_id = 0xFF; // Invalid payload ID
+
+ switch(bus_id) {
+ case 1:
+ payload_id = 2;
+ break;
+ case 3:
+ payload_id = 1;
+ break;
+ case 5:
+ payload_id = 4;
+ break;
+ case 7:
+ payload_id = 3;
+ break;
+ default:
+ syslog(LOG_ALERT, "get_payload_id: Wrong bus ID\n");
+ break;
+ }
+
+ return payload_id;
+}
+#endif
+
+// Returns an unused seq# from all possible seq#
+static uint8_t
+seq_get_new(void) {
+ uint8_t ret = -1;
+ uint8_t index;
+
+ pthread_mutex_lock(&m_seq);
+
+ // Search for unused sequence number
+ index = g_seq.curr_seq;
+ do {
+ if (g_seq.seq[index].in_use == false) {
+ // Found it!
+ ret = index;
+ g_seq.seq[index].in_use = true;
+ g_seq.seq[index].len = 0;
+ break;
+ }
+
+ if (++index == SEQ_NUM_MAX) {
+ index = 0;
+ }
+ } while (index != g_seq.curr_seq);
+
+ // Update the current seq num
+ if (ret >= 0) {
+ if (++index == SEQ_NUM_MAX) {
+ index = 0;
+ }
+ g_seq.curr_seq = index;
+ }
+
+ pthread_mutex_unlock(&m_seq);
+
+ return ret;
+}
+
+static int
+i2c_open(uint8_t bus_num) {
+ int fd;
+ char fn[32];
+ int rc;
+
+ snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus_num);
+ fd = open(fn, O_RDWR);
+ if (fd == -1) {
+ syslog(LOG_ALERT, "Failed to open i2c device %s", fn);
+ return -1;
+ }
+
+ rc = ioctl(fd, I2C_SLAVE, BRIDGE_SLAVE_ADDR);
+ if (rc < 0) {
+ syslog(LOG_ALERT, "Failed to open slave @ address 0x%x", BRIDGE_SLAVE_ADDR);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static int
+i2c_write(int fd, uint8_t *buf, uint8_t len) {
+ struct i2c_rdwr_ioctl_data data;
+ struct i2c_msg msg;
+ int rc;
+ int i;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.addr = BRIDGE_SLAVE_ADDR;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = buf;
+
+ data.msgs = &msg;
+ data.nmsgs = 1;
+
+ pthread_mutex_lock(&m_i2c);
+
+ for (i = 0; i < I2C_RETRIES_MAX; i++) {
+ rc = ioctl(fd, I2C_RDWR, &data);
+ if (rc < 0) {
+ sleep(1);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (rc < 0) {
+ syslog(LOG_ALERT, "Failed to do raw io");
+ pthread_mutex_unlock(&m_i2c);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&m_i2c);
+
+ return 0;
+}
+
+static int
+i2c_slave_open(uint8_t bus_num) {
+ int fd;
+ char fn[32];
+ int rc;
+ struct i2c_rdwr_ioctl_data data;
+ struct i2c_msg msg;
+ uint8_t read_bytes[MAX_BYTES] = { 0 };
+
+ snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus_num);
+ fd = open(fn, O_RDWR);
+ if (fd == -1) {
+ syslog(LOG_ALERT, "Failed to open i2c device %s", fn);
+ return -1;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.addr = BMC_SLAVE_ADDR;
+ msg.flags = I2C_S_EN;
+ msg.len = 1;
+ msg.buf = read_bytes;
+ msg.buf[0] = 1;
+
+ data.msgs = &msg;
+ data.nmsgs = 1;
+
+ rc = ioctl(fd, I2C_SLAVE_RDWR, &data);
+ if (rc < 0) {
+ syslog(LOG_ALERT, "Failed to open slave @ address 0x%x", BMC_SLAVE_ADDR);
+ close(fd);
+ }
+
+ return fd;
+}
+
+static int
+i2c_slave_read(int fd, uint8_t *buf, uint8_t *len) {
+ struct i2c_rdwr_ioctl_data data;
+ struct i2c_msg msg;
+ int rc;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.addr = BMC_SLAVE_ADDR;
+ msg.flags = 0;
+ msg.len = MAX_BYTES;
+ msg.buf = buf;
+
+ data.msgs = &msg;
+ data.nmsgs = 1;
+
+ rc = ioctl(fd, I2C_SLAVE_RDWR, &data);
+ if (rc < 0) {
+ return -1;
+ }
+
+ *len = msg.len;
+
+ return 0;
+}
+
+// Thread to handle new requests
+static void*
+ipmb_req_handler(void *bus_num) {
+ uint8_t *bnum = (uint8_t*) bus_num;
+ mqd_t mq;
+ int fd;
+ int i;
+
+ //Buffers for IPMB transport
+ uint8_t rxbuf[MQ_MAX_MSG_SIZE] = {0};
+ uint8_t txbuf[MQ_MAX_MSG_SIZE] = {0};
+ ipmb_req_t *p_ipmb_req;
+ ipmb_res_t *p_ipmb_res;
+
+ p_ipmb_req = (ipmb_req_t*) rxbuf;
+ p_ipmb_res = (ipmb_res_t*) txbuf;
+
+ //Buffers for IPMI Stack
+ uint8_t rbuf[MQ_MAX_MSG_SIZE] = {0};
+ uint8_t tbuf[MQ_MAX_MSG_SIZE] = {0};
+ ipmi_mn_req_t *p_ipmi_mn_req;
+ ipmi_res_t *p_ipmi_res;
+
+ p_ipmi_mn_req = (ipmi_mn_req_t*) rbuf;
+ p_ipmi_res = (ipmi_res_t*) tbuf;
+
+ uint8_t rlen = 0;
+ uint8_t tlen = 0;
+
+ char mq_ipmb_req[64] = {0};
+
+ sprintf(mq_ipmb_req, "%s_%d", MQ_IPMB_REQ, *bnum);
+
+ // Open Queue to receive requests
+ mq = mq_open(mq_ipmb_req, O_RDONLY);
+ if (mq == (mqd_t) -1) {
+ return NULL;
+ }
+
+ // Open the i2c bus for sending response
+ fd = i2c_open(*bnum);
+ if (fd < 0) {
+ syslog(LOG_ALERT, "i2c_open failure\n");
+ close(mq);
+ return NULL;
+ }
+
+ // Loop to process incoming requests
+ while (1) {
+ if ((rlen = mq_receive(mq, rxbuf, MQ_MAX_MSG_SIZE, NULL)) < 0) {
+ sleep(1);
+ continue;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_ALERT, "Received Request of %d bytes\n", rlen);
+ for (i = 0; i < rlen; i++) {
+ syslog(LOG_ALERT, "0x%X", rxbuf[i]);
+ }
+#endif
+
+ // Create IPMI request from IPMB data
+#ifdef CONFIG_YOSEMITE
+ p_ipmi_mn_req->payload_id = get_payload_id(*bnum);
+#else
+ // For single node systems use payload ID as 1
+ p_ipmi_mn_req->payload_id = 0x1;
+#endif
+ p_ipmi_mn_req->netfn_lun = p_ipmb_req->netfn_lun;
+ p_ipmi_mn_req->cmd = p_ipmb_req->cmd;
+
+ memcpy(p_ipmi_mn_req->data, p_ipmb_req->data, rlen - IPMB_HDR_SIZE - IPMI_REQ_HDR_SIZE);
+
+ // Send to IPMI stack and get response
+ // Additional byte as we are adding and passing payload ID for MN support
+ lib_ipmi_handle(rbuf, rlen - IPMB_HDR_SIZE + 1, tbuf, &tlen);
+
+ // Populate IPMB response data from IPMB request
+ p_ipmb_res->req_slave_addr = p_ipmb_req->req_slave_addr;
+ p_ipmb_res->res_slave_addr = p_ipmb_req->res_slave_addr;
+ p_ipmb_res->cmd = p_ipmb_req->cmd;
+ p_ipmb_res->seq_lun = p_ipmb_req->seq_lun;
+
+ // Add IPMI response data
+ p_ipmb_res->netfn_lun = p_ipmi_res->netfn_lun;
+ p_ipmb_res->cc = p_ipmi_res->cc;
+
+ memcpy(p_ipmb_res->data, p_ipmi_res->data, tlen - IPMI_RESP_HDR_SIZE);
+
+ // Calculate Header Checksum
+ p_ipmb_res->hdr_cksum = p_ipmb_res->req_slave_addr +
+ p_ipmb_res->netfn_lun;
+ p_ipmb_res->hdr_cksum = ZERO_CKSUM_CONST - p_ipmb_res->hdr_cksum;
+
+ // Calculate Data Checksum
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE] = p_ipmb_res->res_slave_addr +
+ p_ipmb_res->seq_lun +
+ p_ipmb_res->cmd +
+ p_ipmb_res->cc;
+
+ for (i = 0; i < tlen-IPMI_RESP_HDR_SIZE; i++) {
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE] += p_ipmb_res->data[i];
+ }
+
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE] = ZERO_CKSUM_CONST -
+ p_ipmb_res->data[tlen-IPMI_RESP_HDR_SIZE];
+
+#ifdef DEBUG
+ syslog(LOG_ALERT, "Sending Response of %d bytes\n", tlen+IPMB_HDR_SIZE-1);
+ for (i = 1; i < tlen+IPMB_HDR_SIZE; i++) {
+ syslog(LOG_ALERT, "0x%X:", txbuf[i]);
+ }
+#endif
+
+ // Send response back
+ i2c_write(fd, &txbuf[1], tlen+IPMB_HDR_SIZE-1);
+ }
+}
+
+// Thread to handle the incoming responses
+static void*
+ipmb_res_handler(void *bus_num) {
+ uint8_t *bnum = (uint8_t*) bus_num;
+ uint8_t buf[MQ_MAX_MSG_SIZE] = { 0 };
+ uint8_t len = 0;
+ mqd_t mq;
+ ipmb_res_t *p_res;
+ uint8_t index;
+ char mq_ipmb_res[64] = {0};
+
+ sprintf(mq_ipmb_res, "%s_%d", MQ_IPMB_RES, *bnum);
+
+ // Open the message queue
+ mq = mq_open(mq_ipmb_res, O_RDONLY);
+ if (mq == (mqd_t) -1) {
+ syslog(LOG_ALERT, "mq_open fails\n");
+ return NULL;
+ }
+
+ // Loop to wait for incomng response messages
+ while (1) {
+ if ((len = mq_receive(mq, buf, MQ_MAX_MSG_SIZE, NULL)) < 0) {
+ sleep(1);
+ continue;
+ }
+
+ p_res = (ipmb_res_t *) buf;
+
+ // Check the seq# of response
+ index = p_res->seq_lun >> LUN_OFFSET;
+
+ // Check if the response is being waited for
+ pthread_mutex_lock(&m_seq);
+ if (g_seq.seq[index].in_use) {
+ // Copy the response to the requester's buffer
+ memcpy(g_seq.seq[index].p_buf, buf, len);
+ g_seq.seq[index].len = len;
+
+ // Wake up the worker thread to receive the response
+ sem_post(&g_seq.seq[index].s_seq);
+ }
+ pthread_mutex_unlock(&m_seq);
+
+#ifdef DEBUG
+ syslog(LOG_ALERT, "Received Response of %d bytes\n", len);
+ int i;
+ for (i = 0; i < len; i++) {
+ syslog(LOG_ALERT, "0x%X:", buf[i]);
+ }
+#endif
+ }
+}
+
+// Thread to receive the IPMB messages over i2c bus as a slave
+static void*
+ipmb_rx_handler(void *bus_num) {
+ uint8_t *bnum = (uint8_t*) bus_num;
+ int fd;
+ uint8_t len;
+ uint8_t tlun;
+ uint8_t buf[MAX_BYTES] = { 0 };
+ mqd_t mq_req, mq_res, tmq;
+ ipmb_req_t *p_req;
+ struct timespec req;
+ struct timespec rem;
+ char mq_ipmb_req[64] = {0};
+ char mq_ipmb_res[64] = {0};
+
+ // Setup wait time
+ req.tv_sec = 0;
+ req.tv_nsec = 10000000;//10mSec
+
+ // Open the i2c bus as a slave
+ fd = i2c_slave_open(*bnum);
+ if (fd < 0) {
+ syslog(LOG_ALERT, "i2c_slave_open fails\n");
+ goto cleanup;
+ }
+
+ sprintf(mq_ipmb_req, "%s_%d", MQ_IPMB_REQ, *bnum);
+ sprintf(mq_ipmb_res, "%s_%d", MQ_IPMB_RES, *bnum);
+
+ // Open the message queues for post processing
+ mq_req = mq_open(mq_ipmb_req, O_WRONLY);
+ if (mq_req == (mqd_t) -1) {
+ syslog(LOG_ALERT, "mq_open req fails\n");
+ goto cleanup;
+ }
+
+ mq_res = mq_open(mq_ipmb_res, O_WRONLY);
+ if (mq_res == (mqd_t) -1) {
+ syslog(LOG_ALERT, "mq_open res fails\n");
+ goto cleanup;
+ }
+
+ // Loop that retrieves messages
+ while (1) {
+ // Read messages from i2c driver
+ if (i2c_slave_read(fd, buf, &len) < 0) {
+ nanosleep(&req, &rem);
+ continue;
+ }
+
+ // Check if the messages is request or response
+ // Even NetFn: Request, Odd NetFn: Response
+ p_req = (ipmb_req_t*) buf;
+ tlun = p_req->netfn_lun >> LUN_OFFSET;
+ if (tlun%2) {
+ tmq = mq_res;
+ } else {
+ tmq = mq_req;
+ }
+ // Post message to approriate Queue for further processing
+ if (mq_send(tmq, buf, len, 0)) {
+ syslog(LOG_ALERT, "mq_send failed\n");
+ sleep(1);
+ continue;
+ }
+ }
+
+cleanup:
+ if (fd > 0) {
+ close (fd);
+ }
+
+ if (mq_req > 0) {
+ close(mq_req);
+ }
+
+ if (mq_res > 0) {
+ close(mq_req);
+ }
+}
+
+/*
+ * Function to handle all IPMB requests
+ */
+static void
+ipmb_handle (int fd, unsigned char *request, unsigned char req_len,
+ unsigned char *response, unsigned char *res_len)
+{
+ ipmb_req_t *req = (ipmb_req_t *) request;
+ ipmb_res_t *res = (ipmb_res_t *) response;
+
+ uint8_t index;
+ struct timespec ts;
+
+ // Allocate right sequence Number
+ index = seq_get_new();
+ if (index < 0) {
+ *res_len = 0;
+ return ;
+ }
+
+ req->seq_lun = index << LUN_OFFSET;
+
+ // Calculate/update dataCksum
+ // Note: dataCkSum byte is last byte
+ int i;
+ for (i = IPMB_DATA_OFFSET; i < req_len-1; i++) {
+ request[req_len-1] += request[i];
+ }
+
+ request[req_len-1] = ZERO_CKSUM_CONST - request[req_len-1];
+
+ // Setup response buffer
+ pthread_mutex_lock(&m_seq);
+ g_seq.seq[index].p_buf = response;
+ pthread_mutex_unlock(&m_seq);
+
+ // Send request over i2c bus
+ // Note: Need not send first byte SlaveAddress automatically added by driver
+ if (i2c_write(fd, &request[1], req_len-1)) {
+ goto ipmb_handle_out;
+ }
+
+ // Wait on semaphore for that sequence Number
+ clock_gettime(CLOCK_REALTIME, &ts);
+
+ ts.tv_sec += TIMEOUT_IPMI;
+
+ int ret;
+ ret = sem_timedwait(&g_seq.seq[index].s_seq, &ts);
+ if (ret == -1) {
+ syslog(LOG_ALERT, "No response for sequence number: %d\n", index);
+ *res_len = 0;
+ }
+
+ipmb_handle_out:
+ // Reply to user with data
+ pthread_mutex_lock(&m_seq);
+ *res_len = g_seq.seq[index].len;
+
+ g_seq.seq[index].in_use = false;
+ pthread_mutex_unlock(&m_seq);
+
+ return;
+}
+
+void
+*conn_handler(void *sfd) {
+ ipmb_sfd_t *p_sfd = (ipmb_sfd_t *) sfd;
+
+ int sock = p_sfd->sock;
+ int fd = p_sfd->fd;
+ int n;
+ unsigned char req_buf[MAX_IPMI_MSG_SIZE];
+ unsigned char res_buf[MAX_IPMI_MSG_SIZE];
+ unsigned char res_len = 0;
+
+ n = recv(sock, req_buf, sizeof(req_buf), 0);
+ if (n <= 0) {
+ syslog(LOG_ALERT, "ipmbd: recv() failed with %d\n", n);
+ goto conn_cleanup;
+ }
+
+ ipmb_handle(fd, req_buf, n, res_buf, &res_len);
+
+ if (send(sock, res_buf, res_len, MSG_NOSIGNAL) < 0) {
+ syslog(LOG_ALERT, "ipmbd: send() failed\n");
+ }
+
+conn_cleanup:
+ close(sock);
+ free(p_sfd);
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+// Thread to receive the IPMB lib messages from various apps
+static void*
+ipmb_lib_handler(void *bus_num) {
+ int s, s2, t, len;
+ struct sockaddr_un local, remote;
+ pthread_t tid;
+ ipmb_sfd_t *sfd;
+ int fd;
+ uint8_t *bnum = (uint8_t*) bus_num;
+ char sock_path[20] = {0};
+
+ // Open the i2c bus for sending request
+ fd = i2c_open(*bnum);
+ if (fd < 0) {
+ syslog(LOG_ALERT, "i2c_open failure\n");
+ return NULL;
+ }
+
+ // Initialize g_seq structure
+ int i;
+ for (i = 0; i < SEQ_NUM_MAX; i++) {
+ g_seq.seq[i].in_use = false;
+ sem_init(&g_seq.seq[i].s_seq, 0, 0);
+ g_seq.seq[i].len = 0;
+ }
+
+ // Initialize mutex to access global structure
+ pthread_mutex_init(&m_seq, NULL);
+
+ if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ syslog(LOG_ALERT, "ipmbd: socket() failed\n");
+ exit (1);
+ }
+
+ sprintf(sock_path, "%s_%d", SOCK_PATH_IPMB, *bnum);
+
+ local.sun_family = AF_UNIX;
+ strcpy (local.sun_path, sock_path);
+ unlink (local.sun_path);
+ len = strlen (local.sun_path) + sizeof (local.sun_family);
+ if (bind (s, (struct sockaddr *) &local, len) == -1)
+ {
+ syslog(LOG_ALERT, "ipmbd: bind() failed\n");
+ exit (1);
+ }
+
+ if (listen (s, 5) == -1)
+ {
+ syslog(LOG_ALERT, "ipmbd: listen() failed\n");
+ exit (1);
+ }
+
+ while(1) {
+ int n;
+ t = sizeof (remote);
+ if ((s2 = accept (s, (struct sockaddr *) &remote, &t)) < 0) {
+ syslog(LOG_ALERT, "ipmbd: accept() failed\n");
+ break;
+ }
+
+ // Creating a worker thread to handle the request
+ // TODO: Need to monitor the server performance with higher load and
+ // see if we need to create pre-defined number of workers and schedule
+ // the requests among them.
+ sfd = (ipmb_sfd_t *) malloc(sizeof(ipmb_sfd_t));
+ sfd->fd = fd;
+ sfd->sock = s2;
+ if (pthread_create(&tid, NULL, conn_handler, (void*) sfd) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ close(s2);
+ continue;
+ }
+
+ pthread_detach(tid);
+ }
+
+ close(s);
+ pthread_mutex_destroy(&m_seq);
+
+ return 0;
+}
+
+int
+main(int argc, char * const argv[]) {
+ pthread_t tid_ipmb_rx;
+ pthread_t tid_req_handler;
+ pthread_t tid_res_handler;
+ pthread_t tid_lib_handler;
+ uint8_t ipmb_bus_num;
+ mqd_t mqd_req, mqd_res;
+ struct mq_attr attr;
+ char mq_ipmb_req[64] = {0};
+ char mq_ipmb_res[64] = {0};
+
+ daemon(1, 0);
+ openlog("ipmbd", LOG_CONS, LOG_DAEMON);
+
+ if (argc != 2) {
+ syslog(LOG_ALERT, "ipmbd: Usage: ipmbd <bus#>");
+ exit(1);
+ }
+
+ ipmb_bus_num = atoi(argv[1]);
+syslog(LOG_ALERT, "ipmbd: bus#:%d\n", ipmb_bus_num);
+
+ pthread_mutex_init(&m_i2c, NULL);
+
+ // Create Message Queues for Request Messages and Response Messages
+ attr.mq_flags = 0;
+ attr.mq_maxmsg = MQ_MAX_NUM_MSGS;
+ attr.mq_msgsize = MQ_MAX_MSG_SIZE;
+ attr.mq_curmsgs = 0;
+
+ sprintf(mq_ipmb_req, "%s_%d", MQ_IPMB_REQ, ipmb_bus_num);
+ sprintf(mq_ipmb_res, "%s_%d", MQ_IPMB_RES, ipmb_bus_num);
+
+ // Remove the MQ if exists
+ mq_unlink(mq_ipmb_req);
+
+ errno = 0;
+ mqd_req = mq_open(mq_ipmb_req, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &attr);
+ if (mqd_req == (mqd_t) -1) {
+ syslog(LOG_ALERT, "ipmbd: mq_open request failed errno:%d\n", errno);
+ goto cleanup;
+ }
+
+ // Remove the MQ if exists
+ mq_unlink(mq_ipmb_res);
+
+ errno = 0;
+ mqd_res = mq_open(mq_ipmb_res, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &attr);
+ if (mqd_res == (mqd_t) -1) {
+ syslog(LOG_ALERT, "ipmbd: mq_open response failed errno: %d\n", errno);
+ goto cleanup;
+ }
+
+ // Create thread to handle IPMB Requests
+ if (pthread_create(&tid_req_handler, NULL, ipmb_req_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+ // Create thread to handle IPMB Responses
+ if (pthread_create(&tid_res_handler, NULL, ipmb_res_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+ // Create thread to retrieve ipmb traffic from i2c bus as slave
+ if (pthread_create(&tid_ipmb_rx, NULL, ipmb_rx_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+ // Create thread to receive ipmb library requests from apps
+ if (pthread_create(&tid_lib_handler, NULL, ipmb_lib_handler, (void*) &ipmb_bus_num) < 0) {
+ syslog(LOG_ALERT, "ipmbd: pthread_create failed\n");
+ goto cleanup;
+ }
+
+cleanup:
+ if (tid_ipmb_rx > 0) {
+ pthread_join(tid_ipmb_rx, NULL);
+ }
+
+ if (tid_req_handler > 0) {
+ pthread_join(tid_req_handler, NULL);
+ }
+
+ if (tid_res_handler > 0) {
+ pthread_join(tid_res_handler, NULL);
+ }
+
+ if (tid_lib_handler > 0) {
+ pthread_join(tid_lib_handler, NULL);
+ }
+
+ if (mqd_res > 0) {
+ mq_close(mqd_res);
+ mq_unlink(mq_ipmb_res);
+ }
+
+ if (mqd_req > 0) {
+ mq_close(mqd_req);
+ mq_unlink(mq_ipmb_req);
+ }
+
+ pthread_mutex_destroy(&m_i2c);
+
+ return 0;
+}
diff --git a/common/recipes-core/ipmbd/ipmbd_0.1.bb b/common/recipes-core/ipmbd/ipmbd_0.1.bb
new file mode 100644
index 0000000..f5724b0
--- /dev/null
+++ b/common/recipes-core/ipmbd/ipmbd_0.1.bb
@@ -0,0 +1,19 @@
+# Copyright 2015-present Facebook. All Rights Reserved.
+
+SUMMARY = "ipmbd tx/rx daemon"
+DESCRIPTION = "The ipmb daemon to receive/transmit messages"
+SECTION = "base"
+PR = "r2"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://ipmbd.c;beginline=4;endline=16;md5=da35978751a9d71b73679307c4d296ec"
+
+SRC_URI = "file://Makefile \
+ file://ipmbd.c \
+ "
+
+S = "${WORKDIR}"
+DEPENDS += "libipmi libipmb"
+
+binfiles = "ipmbd"
+
+pkgdir = "ipmbd"
OpenPOWER on IntegriCloud