1 /*
2 * Copyright (c) 2012 Pigeon Point Systems. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Pigeon Point Systems nor the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <ipmitool/bswap.h>
34 #include <ipmitool/hpm2.h>
35 #include <ipmitool/ipmi_intf.h>
36 #include <ipmitool/log.h>
37 #include <ipmitool/bswap.h>
38
39 /* From src/plugins/ipmi_intf.c: */
40 void
41 ipmi_intf_set_max_request_data_size(struct ipmi_intf * intf, uint16_t size);
42 void
43 ipmi_intf_set_max_response_data_size(struct ipmi_intf * intf, uint16_t size);
44
45 #if HAVE_PRAGMA_PACK
46 # pragma pack(push, 1)
47 #endif
48
49 /* HPM.x Get Capabilities request */
50 struct hpmx_cmd_get_capabilities_rq {
51 uint8_t picmg_id;
52 uint8_t hpmx_id;
53 } ATTRIBUTE_PACKING;
54
55 /* HPM.2 Get Capabilities response */
56 struct hpm2_cmd_get_capabilities_rp {
57 uint8_t picmg_id;
58 struct hpm2_lan_attach_capabilities caps;
59 } ATTRIBUTE_PACKING;
60
61 #if HAVE_PRAGMA_PACK
62 # pragma pack(pop)
63 #endif
64
65 /* IPMI Get LAN Configuration Parameters command */
66 #define IPMI_LAN_GET_CONFIG 0x02
67
hpm2_get_capabilities(struct ipmi_intf * intf,struct hpm2_lan_attach_capabilities * caps)68 int hpm2_get_capabilities(struct ipmi_intf * intf,
69 struct hpm2_lan_attach_capabilities * caps)
70 {
71 struct ipmi_rq req;
72 struct ipmi_rs * rsp;
73 struct hpmx_cmd_get_capabilities_rq rq;
74
75 /* reset result */
76 memset(caps, 0, sizeof(struct hpm2_lan_attach_capabilities));
77
78 /* prepare request */
79 rq.picmg_id = 0;
80 rq.hpmx_id = 2;
81
82 /* prepare request */
83 memset(&req, 0, sizeof(req));
84 req.msg.netfn = IPMI_NETFN_PICMG;
85 req.msg.cmd = HPM2_GET_LAN_ATTACH_CAPABILITIES;
86 req.msg.data = (uint8_t *)&rq;
87 req.msg.data_len = sizeof(rq);
88
89
90 /* send */
91 rsp = intf->sendrecv(intf, &req);
92
93 if (!rsp) {
94 lprintf(LOG_NOTICE, "Error sending request.");
95 return -1;
96 }
97
98 if (rsp->ccode == 0xC1) {
99 lprintf(LOG_DEBUG, "IPM Controller is not HPM.2 compatible");
100 return rsp->ccode;
101 } else if (rsp->ccode) {
102 lprintf(LOG_NOTICE, "Get HPM.x Capabilities request failed,"
103 " compcode = %x", rsp->ccode);
104 return rsp->ccode;
105 }
106
107 /* check response length */
108 if (rsp->data_len < 2 || rsp->data_len > 10) {
109 lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
110 return -1;
111 }
112
113 /* check HPM.x identifier */
114 if (rsp->data[1] != 2) {
115 lprintf(LOG_NOTICE, "Bad HPM.x ID, id=%d", rsp->data[1]);
116 return rsp->ccode;
117 }
118
119 /*
120 * this hardly can happen, since completion code is already checked.
121 * but check for safety
122 */
123 if (rsp->data_len < 4) {
124 lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
125 return -1;
126 }
127
128 /* copy HPM.2 capabilities */
129 memcpy(caps, rsp->data + 2, rsp->data_len - 2);
130
131 #if WORDS_BIGENDIAN
132 /* swap bytes to convert from little-endian format */
133 caps->lan_channel_mask = BSWAP_16(caps->lan_channel_mask);
134 #endif
135
136 /* check HPM.2 revision */
137 if (caps->hpm2_revision_id == 0) {
138 lprintf(LOG_NOTICE, "Bad HPM.2 revision, rev=%d",
139 caps->hpm2_revision_id);
140 return -1;
141 }
142
143 if (!caps->lan_channel_mask) {
144 return -1;
145 }
146
147 /* check response length */
148 if (rsp->data_len < 8) {
149 lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
150 return -1;
151 }
152
153 /* check HPM.2 LAN parameters start */
154 if (caps->hpm2_lan_params_start < 0xC0) {
155 lprintf(LOG_NOTICE, "Bad HPM.2 LAN params start, start=%x",
156 caps->hpm2_lan_params_start);
157 return -1;
158 }
159
160 /* check HPM.2 LAN parameters revision */
161 if (caps->hpm2_lan_params_rev != HPM2_LAN_PARAMS_REV) {
162 lprintf(LOG_NOTICE, "Bad HPM.2 LAN params revision, rev=%d",
163 caps->hpm2_lan_params_rev);
164 return -1;
165 }
166
167 /* check for HPM.2 SOL extension */
168 if (!(caps->hpm2_caps & HPM2_CAPS_SOL_EXTENSION)) {
169 /* no further checks */
170 return 0;
171 }
172
173 /* check response length */
174 if (rsp->data_len < 10) {
175 lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
176 return -1;
177 }
178
179 /* check HPM.2 SOL parameters start */
180 if (caps->hpm2_sol_params_start < 0xC0) {
181 lprintf(LOG_NOTICE, "Bad HPM.2 SOL params start, start=%x",
182 caps->hpm2_sol_params_start);
183 return -1;
184 }
185
186 /* check HPM.2 SOL parameters revision */
187 if (caps->hpm2_sol_params_rev != HPM2_SOL_PARAMS_REV) {
188 lprintf(LOG_NOTICE, "Bad HPM.2 SOL params revision, rev=%d",
189 caps->hpm2_sol_params_rev);
190 return -1;
191 }
192
193 return 0;
194 }
195
hpm2_get_lan_channel_capabilities(struct ipmi_intf * intf,uint8_t hpm2_lan_params_start,struct hpm2_lan_channel_capabilities * caps)196 int hpm2_get_lan_channel_capabilities(struct ipmi_intf * intf,
197 uint8_t hpm2_lan_params_start,
198 struct hpm2_lan_channel_capabilities * caps)
199 {
200 struct ipmi_rq req;
201 struct ipmi_rs * rsp;
202 uint8_t rq[4];
203
204 /* reset result */
205 memset(caps, 0, sizeof(struct hpm2_lan_channel_capabilities));
206
207 /* prepare request */
208 memset(&req, 0, sizeof(req));
209 req.msg.netfn = IPMI_NETFN_TRANSPORT;
210 req.msg.cmd = IPMI_LAN_GET_CONFIG;
211 req.msg.data = (uint8_t *)&rq;
212 req.msg.data_len = sizeof(rq);
213
214 /* prepare request data */
215 rq[0] = 0xE; /* sending channel */
216 rq[1] = hpm2_lan_params_start; /* HPM.2 Channel Caps */
217 rq[2] = rq[3] = 0;
218
219 /* send */
220 rsp = intf->sendrecv(intf, &req);
221
222 if (!rsp) {
223 lprintf(LOG_NOTICE, "Error sending request.");
224 return -1;
225 }
226
227 if (rsp->ccode == 0x80) {
228 lprintf(LOG_DEBUG, "HPM.2 Channel Caps parameter is not supported");
229 return rsp->ccode;
230 } else if (rsp->ccode) {
231 lprintf(LOG_NOTICE, "Get LAN Configuration Parameters request failed,"
232 " compcode = %x", rsp->ccode);
233 return rsp->ccode;
234 }
235
236 /* check response length */
237 if (rsp->data_len != sizeof (struct hpm2_lan_channel_capabilities) + 1) {
238 lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
239 return -1;
240 }
241
242 /* check parameter revision */
243 if (rsp->data[0] !=
244 LAN_PARAM_REV(HPM2_LAN_PARAMS_REV, HPM2_LAN_PARAMS_REV)) {
245 lprintf(LOG_NOTICE, "Bad HPM.2 LAN parameter revision, rev=%d",
246 rsp->data[0]);
247 return -1;
248 }
249
250 /* copy parameter data */
251 memcpy(caps, &rsp->data[1], sizeof (struct hpm2_lan_channel_capabilities));
252
253 #if WORDS_BIGENDIAN
254 /* swap bytes to convert from little-endian format */
255 caps->max_inbound_pld_size = BSWAP_16(caps->max_inbound_pld_size);
256 caps->max_outbound_pld_size = BSWAP_16(caps->max_outbound_pld_size);
257 #endif
258
259 return 0;
260 }
261
hpm2_detect_max_payload_size(struct ipmi_intf * intf)262 int hpm2_detect_max_payload_size(struct ipmi_intf * intf)
263 {
264 struct hpm2_lan_attach_capabilities attach_caps;
265 struct hpm2_lan_channel_capabilities channel_caps;
266 int err;
267
268 /* query HPM.2 support */
269 err = hpm2_get_capabilities(intf, &attach_caps);
270
271 /* check if HPM.2 is supported */
272 if (err != 0 || !attach_caps.lan_channel_mask) {
273 return err;
274 }
275
276 /* query channel capabilities */
277 err = hpm2_get_lan_channel_capabilities(intf,
278 attach_caps.hpm2_lan_params_start, &channel_caps);
279
280 /* check if succeeded */
281 if (err != 0) {
282 return err;
283 }
284
285 /* update request and response sizes */
286 ipmi_intf_set_max_request_data_size(intf,
287 channel_caps.max_inbound_pld_size - 7);
288 ipmi_intf_set_max_response_data_size(intf,
289 channel_caps.max_outbound_pld_size - 8);
290
291 /* print debug info */
292 lprintf(LOG_DEBUG, "Set maximum request size to %d\n"
293 "Set maximum response size to %d",
294 intf->max_request_data_size, intf->max_response_data_size);
295
296 return 0;
297 }
298