]>
Commit | Line | Data |
---|---|---|
1 | #include <avr/pgmspace.h> | |
2 | #include <string.h> | |
3 | #include <stdio.h> | |
4 | ||
5 | #include "i2c.h" | |
6 | #include "chassis.h" | |
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 | ||
21 | void ipmb_send(struct ipmb_resp *resp, const unsigned char *data, uint8_t datalen) | |
22 | { | |
23 | unsigned char buf[24]; | |
24 | int len; | |
25 | #ifdef DEBUG | |
26 | int i; | |
27 | #endif | |
28 | ||
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; | |
35 | memcpy(buf+6, data, datalen); | |
36 | len = datalen + 7; | |
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; | |
55 | ||
56 | printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); | |
57 | printf("Connection Header:\n"); | |
58 | printf("\trs Slave Addr.: 0x%02x\n", req->rsSA); | |
59 | printf("\tnetFn: 0x%02x, LUN: 0x%02x\n", req->netFn, req->rsLUN); | |
60 | printf("Data:\n"); | |
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); | |
64 | printf("\tData: "); | |
65 | for(i = 0; i < req->datalen; i++) { | |
66 | printf("0x%02x ", req->data[i]); | |
67 | } | |
68 | printf("\n"); | |
69 | printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); | |
70 | } | |
71 | #endif | |
72 | ||
73 | void ipmb_invalid(struct ipmb_resp *resp) | |
74 | { | |
75 | #if 1 | |
76 | const unsigned char cmd_invalid[] = {IPMB_CC_INVALID}; | |
77 | ||
78 | ipmb_send(resp, cmd_invalid, sizeof(cmd_invalid)); | |
79 | #endif | |
80 | } | |
81 | ||
82 | void ipmb_cmd(struct ipmb_req *req) | |
83 | { | |
84 | struct ipmb_resp resp; | |
85 | const unsigned char get_devid[] = | |
86 | {IPMB_CC_NORMALLY, 0x42, 0x42, 0x01, 0x01, 0x51, 0xff /* Add. Dev. Supp */, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
87 | const unsigned char get_wd_timer[] = | |
88 | {IPMB_CC_NORMALLY, 0x42, 0x00, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xfe}; | |
89 | const unsigned char cc_normal[] = | |
90 | {IPMB_CC_NORMALLY}; | |
91 | const unsigned char sel_info[] = | |
92 | {IPMB_CC_NORMALLY, 0x51, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
93 | const unsigned char sel_alloc_info[] = | |
94 | {IPMB_CC_NORMALLY, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
95 | const unsigned char sel_entry[] = | |
96 | {IPMB_CC_ERROR}; | |
97 | const unsigned char sel_timestamp[] = | |
98 | {IPMB_CC_NORMALLY, 0x00, 0x00, 0x00, 0x00}; | |
99 | const unsigned char chassis_status[] = | |
100 | {IPMB_CC_NORMALLY, 0x60, 0x10, 0x00, 0x00}; | |
101 | const unsigned char reserve_sdr[] = | |
102 | {IPMB_CC_NORMALLY, 0x00, 0x00}; | |
103 | const unsigned char get_sdr[] = | |
104 | {IPMB_CC_NORMALLY, 0xff, 0xff}; | |
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) { | |
117 | case IPMB_CHASSIS_GET_STATUS: | |
118 | ipmb_send(&resp, chassis_status, sizeof(chassis_status)); | |
119 | break; | |
120 | case IPMB_CHASSIS_CONTROL: | |
121 | chassis_control(*(req->data)); | |
122 | ipmb_send(&resp, cc_normal, sizeof(cc_normal)); | |
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) { | |
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 | */ | |
156 | ipmb_send(&resp, cc_normal, sizeof(cc_normal)); | |
157 | break; | |
158 | ||
159 | ||
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: | |
173 | ipmb_send(&resp, get_devid, sizeof(get_devid)); | |
174 | break; | |
175 | ||
176 | case IPMB_APP_GET_WATCHDOG_TIMER: | |
177 | ipmb_send(&resp, get_wd_timer, sizeof(get_wd_timer)); | |
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) { | |
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; | |
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; | |
233 | ||
234 | if ((buf[2] != ipmb_csum(buf, 2)) || | |
235 | (buf[len-1] != ipmb_csum(buf+3, len-4))) | |
236 | return; /* Checksum wrong */ | |
237 | ||
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); | |
249 | } |