xref: /openbmc/qemu/tests/qtest/ipmi-bt-test.c (revision 1aa84a4b)
11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth  * IPMI BT test cases, using the external interface for checking
31e8a1faeSThomas Huth  *
41e8a1faeSThomas Huth  * Copyright (c) 2012 Corey Minyard <cminyard@mvista.com>
51e8a1faeSThomas Huth  *
61e8a1faeSThomas Huth  * Permission is hereby granted, free of charge, to any person obtaining a copy
71e8a1faeSThomas Huth  * of this software and associated documentation files (the "Software"), to deal
81e8a1faeSThomas Huth  * in the Software without restriction, including without limitation the rights
91e8a1faeSThomas Huth  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
101e8a1faeSThomas Huth  * copies of the Software, and to permit persons to whom the Software is
111e8a1faeSThomas Huth  * furnished to do so, subject to the following conditions:
121e8a1faeSThomas Huth  *
131e8a1faeSThomas Huth  * The above copyright notice and this permission notice shall be included in
141e8a1faeSThomas Huth  * all copies or substantial portions of the Software.
151e8a1faeSThomas Huth  *
161e8a1faeSThomas Huth  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171e8a1faeSThomas Huth  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181e8a1faeSThomas Huth  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
191e8a1faeSThomas Huth  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201e8a1faeSThomas Huth  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211e8a1faeSThomas Huth  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
221e8a1faeSThomas Huth  * THE SOFTWARE.
231e8a1faeSThomas Huth  */
241e8a1faeSThomas Huth 
251e8a1faeSThomas Huth #include "qemu/osdep.h"
261e8a1faeSThomas Huth 
271e8a1faeSThomas Huth #include <sys/socket.h>
281e8a1faeSThomas Huth #include <netinet/in.h>
291e8a1faeSThomas Huth #include <netinet/ip.h>
301e8a1faeSThomas Huth #include <netinet/tcp.h>
311e8a1faeSThomas Huth 
321e8a1faeSThomas Huth 
331e8a1faeSThomas Huth #include "libqtest-single.h"
341e8a1faeSThomas Huth 
351e8a1faeSThomas Huth #define IPMI_IRQ        5
361e8a1faeSThomas Huth 
371e8a1faeSThomas Huth #define IPMI_BT_BASE    0xe4
381e8a1faeSThomas Huth 
391e8a1faeSThomas Huth #define IPMI_BT_CTLREG_CLR_WR_PTR  0
401e8a1faeSThomas Huth #define IPMI_BT_CTLREG_CLR_RD_PTR  1
411e8a1faeSThomas Huth #define IPMI_BT_CTLREG_H2B_ATN     2
421e8a1faeSThomas Huth #define IPMI_BT_CTLREG_B2H_ATN     3
431e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SMS_ATN     4
441e8a1faeSThomas Huth #define IPMI_BT_CTLREG_H_BUSY      6
451e8a1faeSThomas Huth #define IPMI_BT_CTLREG_B_BUSY      7
461e8a1faeSThomas Huth 
471e8a1faeSThomas Huth #define IPMI_BT_CTLREG_GET(b) ((bt_get_ctrlreg() >> (b)) & 1)
481e8a1faeSThomas Huth #define IPMI_BT_CTLREG_GET_H2B_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H2B_ATN)
491e8a1faeSThomas Huth #define IPMI_BT_CTLREG_GET_B2H_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B2H_ATN)
501e8a1faeSThomas Huth #define IPMI_BT_CTLREG_GET_SMS_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_SMS_ATN)
511e8a1faeSThomas Huth #define IPMI_BT_CTLREG_GET_H_BUSY()  IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H_BUSY)
521e8a1faeSThomas Huth #define IPMI_BT_CTLREG_GET_B_BUSY()  IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B_BUSY)
531e8a1faeSThomas Huth 
541e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET(b) bt_write_ctrlreg(1 << (b))
551e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET_CLR_WR_PTR() IPMI_BT_CTLREG_SET( \
561e8a1faeSThomas Huth                                                 IPMI_BT_CTLREG_CLR_WR_PTR)
571e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET_CLR_RD_PTR() IPMI_BT_CTLREG_SET( \
581e8a1faeSThomas Huth                                                 IPMI_BT_CTLREG_CLR_RD_PTR)
591e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET_H2B_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H2B_ATN)
601e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET_B2H_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_B2H_ATN)
611e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET_SMS_ATN()  IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_SMS_ATN)
621e8a1faeSThomas Huth #define IPMI_BT_CTLREG_SET_H_BUSY()   IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H_BUSY)
631e8a1faeSThomas Huth 
641e8a1faeSThomas Huth static int bt_ints_enabled;
651e8a1faeSThomas Huth 
bt_get_ctrlreg(void)661e8a1faeSThomas Huth static uint8_t bt_get_ctrlreg(void)
671e8a1faeSThomas Huth {
681e8a1faeSThomas Huth     return inb(IPMI_BT_BASE);
691e8a1faeSThomas Huth }
701e8a1faeSThomas Huth 
bt_write_ctrlreg(uint8_t val)711e8a1faeSThomas Huth static void bt_write_ctrlreg(uint8_t val)
721e8a1faeSThomas Huth {
731e8a1faeSThomas Huth     outb(IPMI_BT_BASE, val);
741e8a1faeSThomas Huth }
751e8a1faeSThomas Huth 
bt_get_buf(void)761e8a1faeSThomas Huth static uint8_t bt_get_buf(void)
771e8a1faeSThomas Huth {
781e8a1faeSThomas Huth     return inb(IPMI_BT_BASE + 1);
791e8a1faeSThomas Huth }
801e8a1faeSThomas Huth 
bt_write_buf(uint8_t val)811e8a1faeSThomas Huth static void bt_write_buf(uint8_t val)
821e8a1faeSThomas Huth {
831e8a1faeSThomas Huth     outb(IPMI_BT_BASE + 1, val);
841e8a1faeSThomas Huth }
851e8a1faeSThomas Huth 
bt_get_irqreg(void)861e8a1faeSThomas Huth static uint8_t bt_get_irqreg(void)
871e8a1faeSThomas Huth {
881e8a1faeSThomas Huth     return inb(IPMI_BT_BASE + 2);
891e8a1faeSThomas Huth }
901e8a1faeSThomas Huth 
bt_write_irqreg(uint8_t val)911e8a1faeSThomas Huth static void bt_write_irqreg(uint8_t val)
921e8a1faeSThomas Huth {
931e8a1faeSThomas Huth     outb(IPMI_BT_BASE + 2, val);
941e8a1faeSThomas Huth }
951e8a1faeSThomas Huth 
bt_wait_b_busy(void)961e8a1faeSThomas Huth static void bt_wait_b_busy(void)
971e8a1faeSThomas Huth {
981e8a1faeSThomas Huth     unsigned int count = 1000;
991e8a1faeSThomas Huth     while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) {
100bfaa3b05SPeter Maydell         --count;
101bfaa3b05SPeter Maydell         g_assert(count != 0);
1021e8a1faeSThomas Huth         usleep(100);
1031e8a1faeSThomas Huth     }
1041e8a1faeSThomas Huth }
1051e8a1faeSThomas Huth 
bt_wait_b2h_atn(void)1061e8a1faeSThomas Huth static void bt_wait_b2h_atn(void)
1071e8a1faeSThomas Huth {
1081e8a1faeSThomas Huth     unsigned int count = 1000;
1091e8a1faeSThomas Huth     while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) {
110bfaa3b05SPeter Maydell         --count;
111bfaa3b05SPeter Maydell         g_assert(count != 0);
1121e8a1faeSThomas Huth         usleep(100);
1131e8a1faeSThomas Huth     }
1141e8a1faeSThomas Huth }
1151e8a1faeSThomas Huth 
1161e8a1faeSThomas Huth 
1171e8a1faeSThomas Huth static int emu_lfd;
1181e8a1faeSThomas Huth static int emu_fd;
1191e8a1faeSThomas Huth static in_port_t emu_port;
1201e8a1faeSThomas Huth static uint8_t inbuf[100];
1211e8a1faeSThomas Huth static unsigned int inbuf_len;
1221e8a1faeSThomas Huth static unsigned int inbuf_pos;
1231e8a1faeSThomas Huth static int last_was_aa;
1241e8a1faeSThomas Huth 
read_emu_data(void)1251e8a1faeSThomas Huth static void read_emu_data(void)
1261e8a1faeSThomas Huth {
1271e8a1faeSThomas Huth     fd_set readfds;
1281e8a1faeSThomas Huth     int rv;
1291e8a1faeSThomas Huth     struct timeval tv;
1301e8a1faeSThomas Huth 
1311e8a1faeSThomas Huth     FD_ZERO(&readfds);
1321e8a1faeSThomas Huth     FD_SET(emu_fd, &readfds);
1331e8a1faeSThomas Huth     tv.tv_sec = 10;
1341e8a1faeSThomas Huth     tv.tv_usec = 0;
1351e8a1faeSThomas Huth     rv = select(emu_fd + 1, &readfds, NULL, NULL, &tv);
1361e8a1faeSThomas Huth     if (rv == -1) {
1371e8a1faeSThomas Huth         perror("select");
1381e8a1faeSThomas Huth     }
1391e8a1faeSThomas Huth     g_assert(rv == 1);
1401e8a1faeSThomas Huth     rv = read(emu_fd, inbuf, sizeof(inbuf));
1411e8a1faeSThomas Huth     if (rv == -1) {
1421e8a1faeSThomas Huth         perror("read");
1431e8a1faeSThomas Huth     }
1441e8a1faeSThomas Huth     g_assert(rv > 0);
1451e8a1faeSThomas Huth     inbuf_len = rv;
1461e8a1faeSThomas Huth     inbuf_pos = 0;
1471e8a1faeSThomas Huth }
1481e8a1faeSThomas Huth 
write_emu_msg(uint8_t * msg,unsigned int len)1491e8a1faeSThomas Huth static void write_emu_msg(uint8_t *msg, unsigned int len)
1501e8a1faeSThomas Huth {
1511e8a1faeSThomas Huth     int rv;
1521e8a1faeSThomas Huth 
1531e8a1faeSThomas Huth #ifdef DEBUG_TEST
1541e8a1faeSThomas Huth     {
1551e8a1faeSThomas Huth         unsigned int i;
1561e8a1faeSThomas Huth         printf("sending:");
1571e8a1faeSThomas Huth         for (i = 0; i < len; i++) {
1581e8a1faeSThomas Huth             printf(" %2.2x", msg[i]);
1591e8a1faeSThomas Huth         }
1601e8a1faeSThomas Huth         printf("\n");
1611e8a1faeSThomas Huth     }
1621e8a1faeSThomas Huth #endif
1631e8a1faeSThomas Huth     rv = write(emu_fd, msg, len);
1641e8a1faeSThomas Huth     g_assert(rv == len);
1651e8a1faeSThomas Huth }
1661e8a1faeSThomas Huth 
get_emu_msg(uint8_t * msg,unsigned int * len)1671e8a1faeSThomas Huth static void get_emu_msg(uint8_t *msg, unsigned int *len)
1681e8a1faeSThomas Huth {
1691e8a1faeSThomas Huth     unsigned int outpos = 0;
1701e8a1faeSThomas Huth 
1711e8a1faeSThomas Huth     for (;;) {
1721e8a1faeSThomas Huth         while (inbuf_pos < inbuf_len) {
1731e8a1faeSThomas Huth             uint8_t ch = inbuf[inbuf_pos++];
1741e8a1faeSThomas Huth 
1751e8a1faeSThomas Huth             g_assert(outpos < *len);
1761e8a1faeSThomas Huth             if (last_was_aa) {
1771e8a1faeSThomas Huth                 assert(ch & 0x10);
1781e8a1faeSThomas Huth                 msg[outpos++] = ch & ~0x10;
1791e8a1faeSThomas Huth                 last_was_aa = 0;
1801e8a1faeSThomas Huth             } else if (ch == 0xaa) {
1811e8a1faeSThomas Huth                 last_was_aa = 1;
1821e8a1faeSThomas Huth             } else {
1831e8a1faeSThomas Huth                 msg[outpos++] = ch;
1841e8a1faeSThomas Huth                 if ((ch == 0xa0) || (ch == 0xa1)) {
1851e8a1faeSThomas Huth                     /* Message complete */
1861e8a1faeSThomas Huth                     *len = outpos;
1871e8a1faeSThomas Huth                     goto done;
1881e8a1faeSThomas Huth                 }
1891e8a1faeSThomas Huth             }
1901e8a1faeSThomas Huth         }
1911e8a1faeSThomas Huth         read_emu_data();
1921e8a1faeSThomas Huth     }
1931e8a1faeSThomas Huth  done:
1941e8a1faeSThomas Huth #ifdef DEBUG_TEST
1951e8a1faeSThomas Huth     {
1961e8a1faeSThomas Huth         unsigned int i;
1971e8a1faeSThomas Huth         printf("Msg:");
1981e8a1faeSThomas Huth         for (i = 0; i < outpos; i++) {
1991e8a1faeSThomas Huth             printf(" %2.2x", msg[i]);
2001e8a1faeSThomas Huth         }
2011e8a1faeSThomas Huth         printf("\n");
2021e8a1faeSThomas Huth     }
2031e8a1faeSThomas Huth #endif
2041e8a1faeSThomas Huth     return;
2051e8a1faeSThomas Huth }
2061e8a1faeSThomas Huth 
2071e8a1faeSThomas Huth static uint8_t
ipmb_checksum(const unsigned char * data,int size,unsigned char start)2081e8a1faeSThomas Huth ipmb_checksum(const unsigned char *data, int size, unsigned char start)
2091e8a1faeSThomas Huth {
2101e8a1faeSThomas Huth         unsigned char csum = start;
2111e8a1faeSThomas Huth 
2121e8a1faeSThomas Huth         for (; size > 0; size--, data++) {
2131e8a1faeSThomas Huth                 csum += *data;
2141e8a1faeSThomas Huth         }
2151e8a1faeSThomas Huth         return csum;
2161e8a1faeSThomas Huth }
2171e8a1faeSThomas Huth 
2181e8a1faeSThomas Huth static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 };
2191e8a1faeSThomas Huth static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
2201e8a1faeSThomas Huth                                     0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 };
2211e8a1faeSThomas Huth 
2221e8a1faeSThomas Huth static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f };
2231e8a1faeSThomas Huth static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 };
2241e8a1faeSThomas Huth static uint8_t enable_irq_cmd[] = { 0x05, 0xa1 };
2251e8a1faeSThomas Huth 
emu_msg_handler(void)2261e8a1faeSThomas Huth static void emu_msg_handler(void)
2271e8a1faeSThomas Huth {
2281e8a1faeSThomas Huth     uint8_t msg[100];
2291e8a1faeSThomas Huth     unsigned int msg_len = sizeof(msg);
2301e8a1faeSThomas Huth 
2311e8a1faeSThomas Huth     get_emu_msg(msg, &msg_len);
2321e8a1faeSThomas Huth     g_assert(msg_len >= 5);
2331e8a1faeSThomas Huth     g_assert(msg[msg_len - 1] == 0xa0);
2341e8a1faeSThomas Huth     msg_len--;
2351e8a1faeSThomas Huth     g_assert(ipmb_checksum(msg, msg_len, 0) == 0);
2361e8a1faeSThomas Huth     msg_len--;
2371e8a1faeSThomas Huth     if ((msg[1] == get_dev_id_cmd[0]) && (msg[2] == get_dev_id_cmd[1])) {
2381e8a1faeSThomas Huth         memcpy(msg + 1, get_dev_id_rsp, sizeof(get_dev_id_rsp));
2391e8a1faeSThomas Huth         msg_len = sizeof(get_dev_id_rsp) + 1;
2401e8a1faeSThomas Huth         msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
2411e8a1faeSThomas Huth         msg_len++;
2421e8a1faeSThomas Huth         msg[msg_len++] = 0xa0;
2431e8a1faeSThomas Huth         write_emu_msg(msg, msg_len);
2441e8a1faeSThomas Huth     } else if ((msg[1] == set_bmc_globals_cmd[0]) &&
2451e8a1faeSThomas Huth                (msg[2] == set_bmc_globals_cmd[1])) {
2461e8a1faeSThomas Huth         write_emu_msg(enable_irq_cmd, sizeof(enable_irq_cmd));
2471e8a1faeSThomas Huth         memcpy(msg + 1, set_bmc_globals_rsp, sizeof(set_bmc_globals_rsp));
2481e8a1faeSThomas Huth         msg_len = sizeof(set_bmc_globals_rsp) + 1;
2491e8a1faeSThomas Huth         msg[msg_len] = -ipmb_checksum(msg, msg_len, 0);
2501e8a1faeSThomas Huth         msg_len++;
2511e8a1faeSThomas Huth         msg[msg_len++] = 0xa0;
2521e8a1faeSThomas Huth         write_emu_msg(msg, msg_len);
2531e8a1faeSThomas Huth     } else {
2541e8a1faeSThomas Huth         g_assert(0);
2551e8a1faeSThomas Huth     }
2561e8a1faeSThomas Huth }
2571e8a1faeSThomas Huth 
bt_cmd(uint8_t * cmd,unsigned int cmd_len,uint8_t * rsp,unsigned int * rsp_len)2581e8a1faeSThomas Huth static void bt_cmd(uint8_t *cmd, unsigned int cmd_len,
2591e8a1faeSThomas Huth                     uint8_t *rsp, unsigned int *rsp_len)
2601e8a1faeSThomas Huth {
2611e8a1faeSThomas Huth     unsigned int i, len, j = 0;
2621e8a1faeSThomas Huth     uint8_t seq = 5;
2631e8a1faeSThomas Huth 
2641e8a1faeSThomas Huth     /* Should be idle */
2651e8a1faeSThomas Huth     g_assert(bt_get_ctrlreg() == 0);
2661e8a1faeSThomas Huth 
2671e8a1faeSThomas Huth     bt_wait_b_busy();
2681e8a1faeSThomas Huth     IPMI_BT_CTLREG_SET_CLR_WR_PTR();
2691e8a1faeSThomas Huth     bt_write_buf(cmd_len + 1);
2701e8a1faeSThomas Huth     bt_write_buf(cmd[0]);
2711e8a1faeSThomas Huth     bt_write_buf(seq);
2721e8a1faeSThomas Huth     for (i = 1; i < cmd_len; i++) {
2731e8a1faeSThomas Huth         bt_write_buf(cmd[i]);
2741e8a1faeSThomas Huth     }
2751e8a1faeSThomas Huth     IPMI_BT_CTLREG_SET_H2B_ATN();
2761e8a1faeSThomas Huth 
2771e8a1faeSThomas Huth     emu_msg_handler(); /* We should get a message on the socket here. */
2781e8a1faeSThomas Huth 
2791e8a1faeSThomas Huth     bt_wait_b2h_atn();
2801e8a1faeSThomas Huth     if (bt_ints_enabled) {
2811e8a1faeSThomas Huth         g_assert((bt_get_irqreg() & 0x02) == 0x02);
2821e8a1faeSThomas Huth         g_assert(get_irq(IPMI_IRQ));
2831e8a1faeSThomas Huth         bt_write_irqreg(0x03);
2841e8a1faeSThomas Huth     } else {
2851e8a1faeSThomas Huth         g_assert(!get_irq(IPMI_IRQ));
2861e8a1faeSThomas Huth     }
2871e8a1faeSThomas Huth     IPMI_BT_CTLREG_SET_H_BUSY();
2881e8a1faeSThomas Huth     IPMI_BT_CTLREG_SET_B2H_ATN();
2891e8a1faeSThomas Huth     IPMI_BT_CTLREG_SET_CLR_RD_PTR();
2901e8a1faeSThomas Huth     len = bt_get_buf();
2911e8a1faeSThomas Huth     g_assert(len >= 4);
2921e8a1faeSThomas Huth     rsp[0] = bt_get_buf();
2931e8a1faeSThomas Huth     assert(bt_get_buf() == seq);
2941e8a1faeSThomas Huth     len--;
2951e8a1faeSThomas Huth     for (j = 1; j < len; j++) {
2961e8a1faeSThomas Huth         rsp[j] = bt_get_buf();
2971e8a1faeSThomas Huth     }
2981e8a1faeSThomas Huth     IPMI_BT_CTLREG_SET_H_BUSY();
2991e8a1faeSThomas Huth     *rsp_len = j;
3001e8a1faeSThomas Huth }
3011e8a1faeSThomas Huth 
3021e8a1faeSThomas Huth 
3031e8a1faeSThomas Huth /*
3041e8a1faeSThomas Huth  * We should get a connect request and a short message with capabilities.
3051e8a1faeSThomas Huth  */
test_connect(void)3061e8a1faeSThomas Huth static void test_connect(void)
3071e8a1faeSThomas Huth {
3081e8a1faeSThomas Huth     fd_set readfds;
3091e8a1faeSThomas Huth     int rv;
3101e8a1faeSThomas Huth     int val;
3111e8a1faeSThomas Huth     struct timeval tv;
3121e8a1faeSThomas Huth     uint8_t msg[100];
3131e8a1faeSThomas Huth     unsigned int msglen;
3141e8a1faeSThomas Huth     static uint8_t exp1[] = { 0xff, 0x01, 0xa1 }; /* A protocol version */
3151e8a1faeSThomas Huth     static uint8_t exp2[] = { 0x08, 0x3f, 0xa1 }; /* A capabilities cmd */
3161e8a1faeSThomas Huth 
3171e8a1faeSThomas Huth     FD_ZERO(&readfds);
3181e8a1faeSThomas Huth     FD_SET(emu_lfd, &readfds);
3191e8a1faeSThomas Huth     tv.tv_sec = 10;
3201e8a1faeSThomas Huth     tv.tv_usec = 0;
3211e8a1faeSThomas Huth     rv = select(emu_lfd + 1, &readfds, NULL, NULL, &tv);
3221e8a1faeSThomas Huth     g_assert(rv == 1);
3231e8a1faeSThomas Huth     emu_fd = accept(emu_lfd, NULL, 0);
3241e8a1faeSThomas Huth     if (emu_fd < 0) {
3251e8a1faeSThomas Huth         perror("accept");
3261e8a1faeSThomas Huth     }
3271e8a1faeSThomas Huth     g_assert(emu_fd >= 0);
3281e8a1faeSThomas Huth 
3291e8a1faeSThomas Huth     val = 1;
3301e8a1faeSThomas Huth     rv = setsockopt(emu_fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
3311e8a1faeSThomas Huth     g_assert(rv != -1);
3321e8a1faeSThomas Huth 
3331e8a1faeSThomas Huth     /* Report our version */
3341e8a1faeSThomas Huth     write_emu_msg(exp1, sizeof(exp1));
3351e8a1faeSThomas Huth 
3361e8a1faeSThomas Huth     /* Validate that we get the info we expect. */
3371e8a1faeSThomas Huth     msglen = sizeof(msg);
3381e8a1faeSThomas Huth     get_emu_msg(msg, &msglen);
3391e8a1faeSThomas Huth     g_assert(msglen == sizeof(exp1));
3401e8a1faeSThomas Huth     g_assert(memcmp(msg, exp1, msglen) == 0);
3411e8a1faeSThomas Huth     msglen = sizeof(msg);
3421e8a1faeSThomas Huth     get_emu_msg(msg, &msglen);
3431e8a1faeSThomas Huth     g_assert(msglen == sizeof(exp2));
3441e8a1faeSThomas Huth     g_assert(memcmp(msg, exp2, msglen) == 0);
3451e8a1faeSThomas Huth }
3461e8a1faeSThomas Huth 
3471e8a1faeSThomas Huth /*
3481e8a1faeSThomas Huth  * Send a get_device_id to do a basic test.
3491e8a1faeSThomas Huth  */
test_bt_base(void)3501e8a1faeSThomas Huth static void test_bt_base(void)
3511e8a1faeSThomas Huth {
3521e8a1faeSThomas Huth     uint8_t rsp[20];
3531e8a1faeSThomas Huth     unsigned int rsplen = sizeof(rsp);
3541e8a1faeSThomas Huth 
3551e8a1faeSThomas Huth     bt_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen);
3561e8a1faeSThomas Huth     g_assert(rsplen == sizeof(get_dev_id_rsp));
3571e8a1faeSThomas Huth     g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0);
3581e8a1faeSThomas Huth }
3591e8a1faeSThomas Huth 
3601e8a1faeSThomas Huth /*
3611e8a1faeSThomas Huth  * Enable IRQs for the interface.
3621e8a1faeSThomas Huth  */
test_enable_irq(void)3631e8a1faeSThomas Huth static void test_enable_irq(void)
3641e8a1faeSThomas Huth {
3651e8a1faeSThomas Huth     uint8_t rsp[20];
3661e8a1faeSThomas Huth     unsigned int rsplen = sizeof(rsp);
3671e8a1faeSThomas Huth 
3681e8a1faeSThomas Huth     bt_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen);
3691e8a1faeSThomas Huth     g_assert(rsplen == sizeof(set_bmc_globals_rsp));
3701e8a1faeSThomas Huth     g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0);
3711e8a1faeSThomas Huth     bt_write_irqreg(0x01);
3721e8a1faeSThomas Huth     bt_ints_enabled = 1;
3731e8a1faeSThomas Huth }
3741e8a1faeSThomas Huth 
3751e8a1faeSThomas Huth /*
3761e8a1faeSThomas Huth  * Create a local TCP socket with any port, then save off the port we got.
3771e8a1faeSThomas Huth  */
open_socket(void)3781e8a1faeSThomas Huth static void open_socket(void)
3791e8a1faeSThomas Huth {
380a8ca0033SPeter Maydell     struct sockaddr_in myaddr = {};
3811e8a1faeSThomas Huth     socklen_t addrlen;
3821e8a1faeSThomas Huth 
3831e8a1faeSThomas Huth     myaddr.sin_family = AF_INET;
3841e8a1faeSThomas Huth     myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3851e8a1faeSThomas Huth     myaddr.sin_port = 0;
3861e8a1faeSThomas Huth     emu_lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
3871e8a1faeSThomas Huth     if (emu_lfd == -1) {
3881e8a1faeSThomas Huth         perror("socket");
3891e8a1faeSThomas Huth         exit(1);
3901e8a1faeSThomas Huth     }
3911e8a1faeSThomas Huth     if (bind(emu_lfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
3921e8a1faeSThomas Huth         perror("bind");
3931e8a1faeSThomas Huth         exit(1);
3941e8a1faeSThomas Huth     }
3951e8a1faeSThomas Huth     addrlen = sizeof(myaddr);
3961e8a1faeSThomas Huth     if (getsockname(emu_lfd, (struct sockaddr *) &myaddr , &addrlen) == -1) {
3971e8a1faeSThomas Huth         perror("getsockname");
3981e8a1faeSThomas Huth         exit(1);
3991e8a1faeSThomas Huth     }
4001e8a1faeSThomas Huth     emu_port = ntohs(myaddr.sin_port);
4011e8a1faeSThomas Huth     assert(listen(emu_lfd, 1) != -1);
4021e8a1faeSThomas Huth }
4031e8a1faeSThomas Huth 
main(int argc,char ** argv)4041e8a1faeSThomas Huth int main(int argc, char **argv)
4051e8a1faeSThomas Huth {
4061e8a1faeSThomas Huth     int ret;
4071e8a1faeSThomas Huth 
4081e8a1faeSThomas Huth     open_socket();
4091e8a1faeSThomas Huth 
4101e8a1faeSThomas Huth     /* Run the tests */
4111e8a1faeSThomas Huth     g_test_init(&argc, &argv, NULL);
4121e8a1faeSThomas Huth 
4131e8a1faeSThomas Huth     global_qtest = qtest_initf(
414*1aa84a4bSVladimir Sementsov-Ogievskiy         " -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect=10"
4151e8a1faeSThomas Huth         " -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
4161e8a1faeSThomas Huth         " -device isa-ipmi-bt,bmc=bmc0", emu_port);
4171e8a1faeSThomas Huth     qtest_irq_intercept_in(global_qtest, "ioapic");
4181e8a1faeSThomas Huth     qtest_add_func("/ipmi/extern/connect", test_connect);
4191e8a1faeSThomas Huth     qtest_add_func("/ipmi/extern/bt_base", test_bt_base);
4201e8a1faeSThomas Huth     qtest_add_func("/ipmi/extern/bt_enable_irq", test_enable_irq);
4211e8a1faeSThomas Huth     qtest_add_func("/ipmi/extern/bt_base_irq", test_bt_base);
4221e8a1faeSThomas Huth     ret = g_test_run();
4231e8a1faeSThomas Huth     qtest_quit(global_qtest);
4241e8a1faeSThomas Huth 
4251e8a1faeSThomas Huth     return ret;
4261e8a1faeSThomas Huth }
427