]>
Commit | Line | Data |
---|---|---|
78f69a38 | 1 | #include <avr/pgmspace.h> |
da7751cb | 2 | #include <string.h> |
d5193055 MG |
3 | #include <stdio.h> |
4 | ||
da7751cb MG |
5 | #include "i2c.h" |
6 | #include "chassis.h" | |
d5193055 MG |
7 | #include "ipmb.h" |
8 | ||
9 | uint8_t ipmb_csum(unsigned char *buf, int len) | |
10 | { | |
11 | uint8_t csum = 0x00; | |
12 | int i; | |
13 | ||
14 | for(i = 0; i < len; i++) { | |
15 | csum += buf[i]; | |
16 | } | |
17 | ||
18 | return -csum; | |
19 | } | |
20 | ||
78f69a38 | 21 | void ipmb_send(struct ipmb_resp *resp, const unsigned char *data, uint8_t datalen) |
d5193055 | 22 | { |
da7751cb MG |
23 | unsigned char buf[24]; |
24 | int len; | |
25 | #ifdef DEBUG | |
d5193055 | 26 | int i; |
da7751cb | 27 | #endif |
d5193055 | 28 | |
da7751cb MG |
29 | buf[0] = resp->rqSA; |
30 | buf[1] = ((resp->netFn)<<2) | (resp->rqLUN & 0x3); | |
31 | buf[2] = ipmb_csum(buf, 2); | |
32 | buf[3] = resp->rsSA; | |
33 | buf[4] = ((resp->rqSEQ)<<2) | (resp->rsLUN & 0x3); | |
34 | buf[5] = resp->cmd; | |
8a583fd2 | 35 | memcpy_P(buf+6, data, datalen); |
67a9a9e8 | 36 | len = datalen + 7; |
da7751cb MG |
37 | buf[len-1] = ipmb_csum(buf+3, len - 4); |
38 | ||
39 | #ifdef DEBUG | |
40 | printf("Sending: "); | |
41 | for(i = 0; i < len; i++) { | |
42 | printf("0x%02x ", buf[i]); | |
43 | } | |
44 | printf("\n"); | |
45 | #endif | |
46 | ||
47 | i2c_send(buf, len); | |
48 | ||
49 | } | |
50 | ||
51 | #ifdef DEBUG | |
52 | void ipmb_dump_req(struct ipmb_req *req) | |
53 | { | |
54 | int i; | |
d5193055 MG |
55 | |
56 | printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); | |
57 | printf("Connection Header:\n"); | |
da7751cb MG |
58 | printf("\trs Slave Addr.: 0x%02x\n", req->rsSA); |
59 | printf("\tnetFn: 0x%02x, LUN: 0x%02x\n", req->netFn, req->rsLUN); | |
d5193055 | 60 | printf("Data:\n"); |
da7751cb MG |
61 | printf("\trq Slave Addr.: 0x%02x\n", req->rqSA); |
62 | printf("\trqSeq: 0x%02x, rqLUN: 0x%02x\n", req->rqSEQ, req->rqLUN); | |
63 | printf("\tcmd: 0x%02x\n", req->cmd); | |
d5193055 | 64 | printf("\tData: "); |
da7751cb MG |
65 | for(i = 0; i < req->datalen; i++) { |
66 | printf("0x%02x ", req->data[i]); | |
d5193055 MG |
67 | } |
68 | printf("\n"); | |
d5193055 | 69 | printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); |
da7751cb MG |
70 | } |
71 | #endif | |
72 | ||
73 | void ipmb_invalid(struct ipmb_resp *resp) | |
74 | { | |
67a9a9e8 | 75 | #if 1 |
8a583fd2 | 76 | static const unsigned char cmd_invalid[] PROGMEM = {IPMB_CC_INVALID}; |
da7751cb | 77 | |
67a9a9e8 | 78 | ipmb_send(resp, cmd_invalid, sizeof(cmd_invalid)); |
da7751cb MG |
79 | #endif |
80 | } | |
81 | ||
82 | void ipmb_cmd(struct ipmb_req *req) | |
83 | { | |
84 | struct ipmb_resp resp; | |
8a583fd2 | 85 | static const unsigned char get_devid[] PROGMEM = |
da7751cb | 86 | {IPMB_CC_NORMALLY, 0x42, 0x42, 0x01, 0x01, 0x51, 0xff /* Add. Dev. Supp */, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
8a583fd2 | 87 | static const unsigned char get_wd_timer[] PROGMEM = |
da7751cb | 88 | {IPMB_CC_NORMALLY, 0x42, 0x00, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xfe}; |
8a583fd2 | 89 | static const unsigned char cc_normal[] PROGMEM = |
da7751cb | 90 | {IPMB_CC_NORMALLY}; |
8a583fd2 | 91 | static const unsigned char sel_info[] PROGMEM = |
67a9a9e8 | 92 | {IPMB_CC_NORMALLY, 0x51, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; |
8a583fd2 | 93 | static const unsigned char sel_alloc_info[] PROGMEM = |
67a9a9e8 | 94 | {IPMB_CC_NORMALLY, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
8a583fd2 | 95 | static const unsigned char sel_entry[] PROGMEM = |
67a9a9e8 | 96 | {IPMB_CC_ERROR}; |
8a583fd2 | 97 | static const unsigned char sel_timestamp[] PROGMEM = |
67a9a9e8 | 98 | {IPMB_CC_NORMALLY, 0x00, 0x00, 0x00, 0x00}; |
8a583fd2 | 99 | static const unsigned char chassis_status[] PROGMEM = |
67a9a9e8 | 100 | {IPMB_CC_NORMALLY, 0x60, 0x10, 0x00, 0x00}; |
8a583fd2 | 101 | static const unsigned char reserve_sdr[] PROGMEM = |
67a9a9e8 | 102 | {IPMB_CC_NORMALLY, 0x00, 0x00}; |
8a583fd2 | 103 | static const unsigned char get_sdr[] PROGMEM = |
67a9a9e8 | 104 | {IPMB_CC_NORMALLY, 0xff, 0xff}; |
da7751cb MG |
105 | |
106 | resp.rqSA = req->rqSA; | |
107 | resp.netFn = req->netFn+1; | |
108 | resp.rqLUN = req->rqLUN; | |
109 | resp.rsSA = req->rsSA; | |
110 | resp.rqSEQ = req->rqSEQ; | |
111 | resp.rsLUN = req->rsLUN; | |
112 | resp.cmd = req->cmd; | |
113 | ||
114 | switch (req->netFn) { | |
115 | case IPMB_NETFN_CHASSIS: | |
116 | switch (req->cmd) { | |
67a9a9e8 MG |
117 | case IPMB_CHASSIS_GET_STATUS: |
118 | ipmb_send(&resp, chassis_status, sizeof(chassis_status)); | |
119 | break; | |
da7751cb MG |
120 | case IPMB_CHASSIS_CONTROL: |
121 | chassis_control(*(req->data)); | |
67a9a9e8 | 122 | ipmb_send(&resp, cc_normal, sizeof(cc_normal)); |
da7751cb MG |
123 | break; |
124 | default: | |
125 | #ifdef DEBUG | |
126 | printf("Unknown chassis cmd 0x%02x\n", req->cmd); | |
127 | ipmb_dump_req(req); | |
128 | #endif | |
129 | ipmb_invalid(&resp); | |
130 | break; | |
131 | } | |
132 | break; | |
133 | ||
134 | case IPMB_NETFN_SENSOR_EVENT: | |
135 | switch (req->cmd) { | |
4f3bb118 MG |
136 | case IPMB_SE_PLATFORM_EVENT: |
137 | /* | |
138 | * >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
139 | * Connection Header: | |
140 | * rs Slave Addr.: 0x24 | |
141 | * netFn: 0x04, LUN: 0x00 | |
142 | * Data: | |
143 | * rq Slave Addr.: 0x28 | |
144 | * rqSeq: 0x03, rqLUN: 0x00 | |
145 | * cmd: 0x02 | |
146 | * Data: 0x03 0xc8 0x00 0x6f 0x61 0x8f 0x03 | |
147 | * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
148 | * data[0] - EvMRev: 0x03 | |
149 | * data[1] - Sensor Type: 0xc8 | |
150 | * data[2] - Sensor #: 0x00 | |
151 | * data[3] - Event Dir(1)|Event Type(7): 0x6f: 0x0|0x6f (assert, discrete) | |
152 | * data[4] - Event Data: 0x61 | |
153 | * data[5] - Event Data: 0x8f | |
154 | * data[6] - Event Data: 0x03 | |
155 | */ | |
67a9a9e8 | 156 | ipmb_send(&resp, cc_normal, sizeof(cc_normal)); |
4f3bb118 MG |
157 | break; |
158 | ||
159 | ||
da7751cb MG |
160 | default: |
161 | #ifdef DEBUG | |
162 | printf("Unknown sensor cmd 0x%02x\n", req->cmd); | |
163 | ipmb_dump_req(req); | |
164 | #endif | |
165 | ipmb_invalid(&resp); | |
166 | break; | |
167 | } | |
168 | break; | |
169 | ||
170 | case IPMB_NETFN_APP: | |
171 | switch (req->cmd) { | |
172 | case IPMB_APP_GET_DEVICE_ID: | |
67a9a9e8 | 173 | ipmb_send(&resp, get_devid, sizeof(get_devid)); |
da7751cb MG |
174 | break; |
175 | ||
176 | case IPMB_APP_GET_WATCHDOG_TIMER: | |
67a9a9e8 | 177 | ipmb_send(&resp, get_wd_timer, sizeof(get_wd_timer)); |
da7751cb MG |
178 | break; |
179 | ||
180 | default: | |
181 | #ifdef DEBUG | |
182 | printf("Unknown app cmd 0x%02x\n", req->cmd); | |
183 | ipmb_dump_req(req); | |
184 | #endif | |
185 | ipmb_invalid(&resp); | |
186 | break; | |
187 | } | |
188 | break; | |
189 | ||
190 | case IPMB_NETFN_STORAGE: | |
191 | switch (req->cmd) { | |
67a9a9e8 MG |
192 | case IPMB_STORAGE_RESERVE_SDR: |
193 | ipmb_send(&resp, reserve_sdr, sizeof(reserve_sdr)); | |
194 | break; | |
195 | case IPMB_STORAGE_GET_SDR: | |
196 | ipmb_send(&resp, get_sdr, sizeof(get_sdr)); | |
197 | break; | |
198 | case IPMB_STORAGE_GET_SEL_INFO: | |
199 | ipmb_send(&resp, sel_info, sizeof(sel_info)); | |
200 | break; | |
201 | case IPMB_STORAGE_GET_SEL_ALLOCATION: | |
202 | ipmb_send(&resp, sel_alloc_info, sizeof(sel_alloc_info)); | |
203 | break; | |
204 | case IPMB_STORAGE_GET_SEL_ENTRY: | |
205 | ipmb_send(&resp, sel_entry, sizeof(sel_entry)); | |
206 | break; | |
207 | case IPMB_STORAGE_GET_SEL_TIME: | |
208 | ipmb_send(&resp, sel_timestamp, sizeof(sel_timestamp)); | |
209 | break; | |
da7751cb MG |
210 | default: |
211 | #ifdef DEBUG | |
212 | printf("Unknown storage cmd 0x%02x\n", req->cmd); | |
213 | ipmb_dump_req(req); | |
214 | #endif | |
215 | ipmb_invalid(&resp); | |
216 | break; | |
217 | } | |
218 | break; | |
219 | ||
220 | default: | |
221 | #ifdef DEBUG | |
222 | printf("Unknown netFn 0x%02x\n", req->netFn); | |
223 | ipmb_dump_req(req); | |
224 | #endif | |
225 | ipmb_invalid(&resp); | |
226 | break; | |
227 | } | |
228 | } | |
229 | ||
230 | void decode_ipmb_pkt(unsigned char *buf, int len) | |
231 | { | |
232 | struct ipmb_req req; | |
d5193055 MG |
233 | |
234 | if ((buf[2] != ipmb_csum(buf, 2)) || | |
da7751cb | 235 | (buf[len-1] != ipmb_csum(buf+3, len-4))) |
d5193055 MG |
236 | return; /* Checksum wrong */ |
237 | ||
da7751cb MG |
238 | req.rsSA = buf[0]; |
239 | req.netFn = (buf[1]>>2)&0x3f; | |
240 | req.rsLUN = (buf[1] & 0x03); | |
241 | req.rqSA = buf[3]; | |
242 | req.rqSEQ = (buf[4]>>2)&0x3f; | |
243 | req.rqLUN = (buf[4] & 0x03); | |
244 | req.cmd = buf[5]; | |
245 | req.data = buf+6; | |
246 | req.datalen = len - 6 - 1; | |
247 | ||
248 | ipmb_cmd(&req); | |
d5193055 | 249 | } |