From da7751cb0539c2ecb03ff66d05904626052e06e3 Mon Sep 17 00:00:00 2001 From: Michael Gernoth Date: Mon, 23 Aug 2010 00:23:56 +0200 Subject: [PATCH 1/1] Completely working IPMB communication (power up/down, reset) --- bmc/Makefile | 2 +- bmc/bmc.c | 24 +++++-- bmc/bmc.h | 2 + bmc/chassis.c | 37 ++++++++++ bmc/chassis.h | 8 +++ bmc/i2c.c | 34 +++++---- bmc/i2c.h | 4 ++ bmc/ipmb.c | 189 +++++++++++++++++++++++++++++++++++++++++++------- bmc/ipmb.h | 36 ++++++++++ 9 files changed, 295 insertions(+), 41 deletions(-) create mode 100644 bmc/chassis.c create mode 100644 bmc/chassis.h diff --git a/bmc/Makefile b/bmc/Makefile index d9ad589..5c1c4a4 100644 --- a/bmc/Makefile +++ b/bmc/Makefile @@ -11,7 +11,7 @@ OBJCOPY=avr-objcopy all: bmc.bin -bmc: bmc.o usart.o i2c.o ipmb.o +bmc: bmc.o usart.o i2c.o ipmb.o chassis.o bmc.bin: bmc $(OBJCOPY) -j .text -j .data -O binary $^ $@ diff --git a/bmc/bmc.c b/bmc/bmc.c index 525785e..99427f6 100644 --- a/bmc/bmc.c +++ b/bmc/bmc.c @@ -1,16 +1,20 @@ #include -#include #include +#include #include #include "usart.h" #include "i2c.h" +#include "ipmb.h" +#include "chassis.h" #include "bmc.h" int main(void) { - DDRB = 0xff; - PORTB = 0xff; + uint8_t old_SREG; + unsigned char buf[12]; + unsigned int len; + chassis_init(); usart_init(); printf("\n"); @@ -21,9 +25,21 @@ int main(void) sei(); while(1) { -#if 1 +#if 0 sleep_mode(); #endif + old_SREG = SREG; + cli(); + if (i2c_done) { + len = i2c_len; + memcpy(buf, (unsigned char*)i2c_databuf, len); + i2c_done = 0x00; + SREG = old_SREG; + + decode_ipmb_pkt(buf, len); + } else { + SREG = old_SREG; + } } return 0; diff --git a/bmc/bmc.h b/bmc/bmc.h index e69de29..82e7911 100644 --- a/bmc/bmc.h +++ b/bmc/bmc.h @@ -0,0 +1,2 @@ +extern volatile unsigned char i2cbuf[12]; +extern volatile uint8_t i2cbuflen; diff --git a/bmc/chassis.c b/bmc/chassis.c new file mode 100644 index 0000000..5bdad1f --- /dev/null +++ b/bmc/chassis.c @@ -0,0 +1,37 @@ +#include +#include + +#include "chassis.h" + +#define DEBUG + +void chassis_init() +{ + DDRB = 0xff; + PORTB = 0xff; +} + +void chassis_control(unsigned char action) +{ +#ifdef DEBUG + printf("Chassis control 0x%02x\n", action); +#endif + + switch(action) { + case CHASSIS_ACTION_POWER_DOWN: + PORTB=0xff; + break; + + case CHASSIS_ACTION_POWER_UP: + PORTB=0x00; + break; + + case CHASSIS_ACTION_HARD_RESET: + PORTB=0x55; + break; + + default: + printf("Unimplemented chassis action 0x%02x\n", action); + break; + } +} diff --git a/bmc/chassis.h b/bmc/chassis.h new file mode 100644 index 0000000..291e1b6 --- /dev/null +++ b/bmc/chassis.h @@ -0,0 +1,8 @@ +#define CHASSIS_ACTION_POWER_DOWN 0x00 +#define CHASSIS_ACTION_POWER_UP 0x01 +#define CHASSIS_ACTION_POWER_CYCLE 0x02 +#define CHASSIS_ACTION_HARD_RESET 0x03 +#define CHASSIS_ACTION_SOFT_SHUTDOWN 0x05 + +void chassis_init(); +void chassis_control(unsigned char action); diff --git a/bmc/i2c.c b/bmc/i2c.c index 6550c92..e479fd3 100644 --- a/bmc/i2c.c +++ b/bmc/i2c.c @@ -2,22 +2,25 @@ #include #include #include "i2c.h" +#include "bmc.h" #include "ipmb.h" #define TWCR_ACK TWCR = (1< #include +#include "i2c.h" +#include "chassis.h" #include "ipmb.h" uint8_t ipmb_csum(unsigned char *buf, int len) @@ -14,43 +17,181 @@ uint8_t ipmb_csum(unsigned char *buf, int len) return -csum; } -void decode_ipmb_pkt(unsigned char *buf, int len) +void ipmb_send(struct ipmb_resp *resp) { + unsigned char buf[24]; + int len; +#ifdef DEBUG int i; - struct ipmb_req req; +#endif - req.rsSA = buf[0]; - req.netFn = (buf[1]>>2)&0x3f; - req.rsLUN = (buf[1] & 0x03); - req.rqSA = buf[3]; - req.rqSEQ = (buf[4]>>2)&0x3f; - req.rqLUN = (buf[4] & 0x03); - req.cmd = buf[5]; - req.data = buf+6; - req.datalen = len - 6 - 1; + buf[0] = resp->rqSA; + buf[1] = ((resp->netFn)<<2) | (resp->rqLUN & 0x3); + buf[2] = ipmb_csum(buf, 2); + buf[3] = resp->rsSA; + buf[4] = ((resp->rqSEQ)<<2) | (resp->rsLUN & 0x3); + buf[5] = resp->cmd; + memcpy(buf+6, resp->data, resp->datalen); + len = resp->datalen + 7; + buf[len-1] = ipmb_csum(buf+3, len - 4); + +#ifdef DEBUG + printf("Sending: "); + for(i = 0; i < len; i++) { + printf("0x%02x ", buf[i]); + } + printf("\n"); +#endif + + i2c_send(buf, len); + +} + +#ifdef DEBUG +void ipmb_dump_req(struct ipmb_req *req) +{ + int i; printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); printf("Connection Header:\n"); - printf("\trs Slave Addr.: 0x%02x\n", req.rsSA); - printf("\tnetFn: 0x%02x, LUN: 0x%02x\n", req.netFn, req.rsLUN); - printf("\tChecksum: 0x%02x (%s)\n", buf[2], - (buf[2] == ipmb_csum(buf, 2)) ? "OK" : "Wrong"); + printf("\trs Slave Addr.: 0x%02x\n", req->rsSA); + printf("\tnetFn: 0x%02x, LUN: 0x%02x\n", req->netFn, req->rsLUN); printf("Data:\n"); - printf("\trq Slave Addr.: 0x%02x\n", req.rqSA); - printf("\trqSeq: 0x%02x, rqLUN: 0x%02x\n", req.rqSEQ, req.rqLUN); - printf("\tcmd: 0x%02x\n", req.cmd); + printf("\trq Slave Addr.: 0x%02x\n", req->rqSA); + printf("\trqSeq: 0x%02x, rqLUN: 0x%02x\n", req->rqSEQ, req->rqLUN); + printf("\tcmd: 0x%02x\n", req->cmd); printf("\tData: "); - for(i = 0; i < req.datalen; i++) { - printf("0x%02x ", req.data[i]); + for(i = 0; i < req->datalen; i++) { + printf("0x%02x ", req->data[i]); } printf("\n"); - printf("\tChecksum: 0x%02x (%s)\n", buf[len-1], - (buf[len-1] == ipmb_csum(buf+3, len-4)) ? "OK" : "Wrong"); printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); +} +#endif + +void ipmb_invalid(struct ipmb_resp *resp) +{ +#if 0 + static unsigned char cmd_invalid[] = {0xc2}; + + resp->data = cmd_invalid; + resp->datalen = sizeof(cmd_invalid); + ipmb_send(resp); +#endif +} + +void ipmb_cmd(struct ipmb_req *req) +{ + struct ipmb_resp resp; + static unsigned char get_devid[] = + {IPMB_CC_NORMALLY, 0x42, 0x42, 0x01, 0x01, 0x51, 0xff /* Add. Dev. Supp */, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static unsigned char get_wd_timer[] = + {IPMB_CC_NORMALLY, 0x42, 0x00, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xfe}; + static unsigned char cc_normal[] = + {IPMB_CC_NORMALLY}; + + resp.rqSA = req->rqSA; + resp.netFn = req->netFn+1; + resp.rqLUN = req->rqLUN; + resp.rsSA = req->rsSA; + resp.rqSEQ = req->rqSEQ; + resp.rsLUN = req->rsLUN; + resp.cmd = req->cmd; + + switch (req->netFn) { + case IPMB_NETFN_CHASSIS: + switch (req->cmd) { + case IPMB_CHASSIS_CONTROL: + chassis_control(*(req->data)); + resp.data = cc_normal; + resp.datalen = sizeof(cc_normal); + ipmb_send(&resp); + break; + default: +#ifdef DEBUG + printf("Unknown chassis cmd 0x%02x\n", req->cmd); + ipmb_dump_req(req); +#endif + ipmb_invalid(&resp); + break; + } + break; + + case IPMB_NETFN_SENSOR_EVENT: + switch (req->cmd) { + default: +#ifdef DEBUG + printf("Unknown sensor cmd 0x%02x\n", req->cmd); + ipmb_dump_req(req); +#endif + ipmb_invalid(&resp); + break; + } + break; + + case IPMB_NETFN_APP: + switch (req->cmd) { + case IPMB_APP_GET_DEVICE_ID: + resp.data = get_devid; + resp.datalen = sizeof(get_devid); + ipmb_send(&resp); + break; + + case IPMB_APP_GET_WATCHDOG_TIMER: + resp.data = get_wd_timer; + resp.datalen = sizeof(get_wd_timer); + ipmb_send(&resp); + break; + + default: +#ifdef DEBUG + printf("Unknown app cmd 0x%02x\n", req->cmd); + ipmb_dump_req(req); +#endif + ipmb_invalid(&resp); + break; + } + break; + + case IPMB_NETFN_STORAGE: + switch (req->cmd) { + default: +#ifdef DEBUG + printf("Unknown storage cmd 0x%02x\n", req->cmd); + ipmb_dump_req(req); +#endif + ipmb_invalid(&resp); + break; + } + break; + + default: +#ifdef DEBUG + printf("Unknown netFn 0x%02x\n", req->netFn); + ipmb_dump_req(req); +#endif + ipmb_invalid(&resp); + break; + } +} + +void decode_ipmb_pkt(unsigned char *buf, int len) +{ + struct ipmb_req req; if ((buf[2] != ipmb_csum(buf, 2)) || - (buf[len-1] == ipmb_csum(buf+3, len-4))) + (buf[len-1] != ipmb_csum(buf+3, len-4))) return; /* Checksum wrong */ - //i2c_send((unsigned char*)"\x28\x00",1); + req.rsSA = buf[0]; + req.netFn = (buf[1]>>2)&0x3f; + req.rsLUN = (buf[1] & 0x03); + req.rqSA = buf[3]; + req.rqSEQ = (buf[4]>>2)&0x3f; + req.rqLUN = (buf[4] & 0x03); + req.cmd = buf[5]; + req.data = buf+6; + req.datalen = len - 6 - 1; + + ipmb_cmd(&req); } diff --git a/bmc/ipmb.h b/bmc/ipmb.h index c48ad31..1be0a48 100644 --- a/bmc/ipmb.h +++ b/bmc/ipmb.h @@ -1,3 +1,27 @@ +#define IPMB_APP_GET_DEVICE_ID 0x01 +#define IPMB_APP_GET_WATCHDOG_TIMER 0x25 + +#define IPMB_CHASSIS_GET_STATUS 0x01 +#define IPMB_CHASSIS_CONTROL 0x02 + +#define IPMB_SE_PLATFORM_EVENT 0x02 + +#define IPMB_STORAGE_GET_SEL_INFO 0x40 +#define IPMB_STORAGE_GET_SEL_TIME 0x48 + +#define IPMB_NETFN_CHASSIS 0x00 +#define IPMB_NETFN_BRIDGE 0x02 +#define IPMB_NETFN_SENSOR_EVENT 0x04 +#define IPMB_NETFN_APP 0x06 +#define IPMB_NETFN_FIRMWARE 0x08 +#define IPMB_NETFN_STORAGE 0x0a + +#define IPMB_CC_NORMALLY 0x00 +#define IPMB_CC_BUSY 0xc0 +#define IPMB_CC_INVALID 0xc1 +#define IPMB_CC_ERROR 0xff + +/* ipmb1010ltd.pdf page 27 (33) */ struct ipmb_req { uint8_t rsSA; uint8_t netFn; @@ -10,4 +34,16 @@ struct ipmb_req { uint8_t datalen; }; +struct ipmb_resp { + uint8_t rqSA; + uint8_t netFn; + uint8_t rqLUN; + uint8_t rsSA; + uint8_t rqSEQ; + uint8_t rsLUN; + uint8_t cmd; + unsigned char *data; + uint8_t datalen; +}; + void decode_ipmb_pkt(unsigned char *buf, int len); -- 2.39.5