]> git.zerfleddert.de Git - rsbs2/commitdiff
Completely working IPMB communication (power up/down, reset)
authorMichael Gernoth <michael@gernoth.net>
Sun, 22 Aug 2010 22:23:56 +0000 (00:23 +0200)
committerMichael Gernoth <michael@gernoth.net>
Sun, 22 Aug 2010 22:23:56 +0000 (00:23 +0200)
bmc/Makefile
bmc/bmc.c
bmc/bmc.h
bmc/chassis.c [new file with mode: 0644]
bmc/chassis.h [new file with mode: 0644]
bmc/i2c.c
bmc/i2c.h
bmc/ipmb.c
bmc/ipmb.h

index d9ad589182cf17e150276c61f7640b3c3cd89cc8..5c1c4a49312b2a2ee6d7912ed504c540507d9835 100644 (file)
@@ -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 $^ $@
index 525785ec48cf81e3a6dc8d5f836fd902648d0624..99427f6580713ccbda8093a75b24e6b49897c206 100644 (file)
--- a/bmc/bmc.c
+++ b/bmc/bmc.c
@@ -1,16 +1,20 @@
 #include <avr/io.h>
-#include <avr/sleep.h>
 #include <avr/interrupt.h>
+#include <string.h>
 #include <stdio.h>
 #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;
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..82e7911fa3028745c9ea1d36dfc67289847d05d8 100644 (file)
--- 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 (file)
index 0000000..5bdad1f
--- /dev/null
@@ -0,0 +1,37 @@
+#include <avr/io.h>
+#include <stdio.h>
+
+#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 (file)
index 0000000..291e1b6
--- /dev/null
@@ -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);
index 6550c92fc62b084bc6d572cc8ae90b046e3d9045..e479fd32e50092ca5ceef796913a881a603d2c3a 100644 (file)
--- a/bmc/i2c.c
+++ b/bmc/i2c.c
@@ -2,22 +2,25 @@
 #include <avr/interrupt.h>
 #include <stdio.h>
 #include "i2c.h"
+#include "bmc.h"
 #include "ipmb.h"
 
 #define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);  
 #define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC);
 #define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(0<<TWWC);  
 
-static volatile unsigned char databuf[12];
-static volatile uint8_t pos = 0x00;
+volatile unsigned char i2c_databuf[12];
+volatile uint8_t i2c_len = 0x00;
+static volatile uint8_t i2c_pos = 0x00;
+volatile uint8_t i2c_done = 0x00;
 
 void i2c_init()
 {
+       TWBR = 0xff;
        TWAR = BMC_ADDR & 0xfe;
        TWDR = 0x00;
        TWCR &= ~((1<<TWSTA) | (1<<TWSTO));
        TWCR |= ((1<<TWEA) | (1<<TWEN) | (1<<TWIE)); 
-       printf("Status: 0x%02x\n", TW_STATUS);
        PORTC = 0x03;
 }
 
@@ -52,9 +55,12 @@ void i2c_send(unsigned char *buf, int len)
        }
 
        TWCR = ((1<<TWINT) | (1<<TWEN) | (1<<TWSTO));
+       while(!(TWCR & (1<<TWSTO))) {}
 
-       printf("I2C Data sent 0x%02x\n", TW_STATUS);
-
+#if 1
+       /* Timing problem... */
+       printf("I2C Data sent\n");
+#endif
 
 out:   
        TWDR = 0x00;
@@ -64,14 +70,17 @@ out:
 
 ISR (TWI_vect, ISR_BLOCK)
 {
+       if (i2c_done)
+               TWCR_RESET;
+
        switch (TW_STATUS) {
                case TW_SR_SLA_ACK:
 #ifdef DEBUG
                        printf("I2C: Slave 0x%02x adressed\n", TWDR);
 #endif
-                       pos = 0x00;
-                       databuf[pos] = TWDR;
-                       pos++;
+                       i2c_pos = 0x00;
+                       i2c_databuf[i2c_pos] = TWDR;
+                       i2c_pos++;
                        TWCR_ACK;
                        break;
 
@@ -79,8 +88,8 @@ ISR (TWI_vect, ISR_BLOCK)
 #ifdef DEBUG
                        printf("I2C: Data received: 0x%02x\n", TWDR);
 #endif
-                       databuf[pos] = TWDR;
-                       pos++;
+                       i2c_databuf[i2c_pos] = TWDR;
+                       i2c_pos++;
                        TWCR_ACK;
                        break;
 
@@ -88,8 +97,9 @@ ISR (TWI_vect, ISR_BLOCK)
 #ifdef DEBUG
                        printf("I2C: STOP received\n");
 #endif
-                       decode_ipmb_pkt((unsigned char*)databuf, pos);
-                       pos = 0x00;
+                       i2c_len = i2c_pos;
+                       i2c_pos = 0x00;
+                       i2c_done = 0x01;
                        TWCR_RESET;
                        break;
 
index c53ff035ca2418df240512781bc242883d6319ef..af27f94bb90db0d853dde7ae19ea19732fe4f337 100644 (file)
--- a/bmc/i2c.h
+++ b/bmc/i2c.h
@@ -1,4 +1,8 @@
 #define BMC_ADDR 0x24
 
+extern volatile unsigned char i2c_databuf[12];
+extern volatile uint8_t i2c_len;
+extern volatile uint8_t i2c_done;
+
 void i2c_init();
 void i2c_send(unsigned char *buf, int len);
index 7d272fbc994bb29f89d0196f8d2701e6c3154ae5..65ddea0b36a7bf4b810e82f82fa0df0e7d9f5f16 100644 (file)
@@ -1,5 +1,8 @@
+#include <string.h>
 #include <stdio.h>
 
+#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);
 }
index c48ad31c05fdf5ad10432eb3d69fe9c2948c08da..1be0a486f7f58e0194cc078a752f106cace9aea8 100644 (file)
@@ -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);
Impressum, Datenschutz