xref: /openbmc/ipmitool/lib/hpm2.c (revision d531785a)
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/hpm2.h>
34 #include <ipmitool/ipmi_intf.h>
35 #include <ipmitool/log.h>
36 #include <ipmitool/bswap.h>
37 
38 #if HAVE_PRAGMA_PACK
39 # pragma pack(push, 1)
40 #endif
41 
42 /* HPM.x Get Capabilities request */
43 struct hpmx_cmd_get_capabilities_rq {
44 	uint8_t picmg_id;
45 	uint8_t hpmx_id;
46 } ATTRIBUTE_PACKING;
47 
48 /* HPM.2 Get Capabilities response */
49 struct hpm2_cmd_get_capabilities_rp {
50 	uint8_t picmg_id;
51 	struct hpm2_lan_attach_capabilities caps;
52 } ATTRIBUTE_PACKING;
53 
54 #if HAVE_PRAGMA_PACK
55 # pragma pack(pop)
56 #endif
57 
58 /* IPMI Get LAN Configuration Parameters command */
59 #define IPMI_LAN_GET_CONFIG	0x02
60 
61 int hpm2_get_capabilities(struct ipmi_intf * intf,
62 		struct hpm2_lan_attach_capabilities * caps)
63 {
64 	struct ipmi_rq req;
65 	struct ipmi_rs * rsp;
66 	struct hpmx_cmd_get_capabilities_rq rq;
67 
68 	/* reset result */
69 	memset(caps, 0, sizeof(struct hpm2_lan_attach_capabilities));
70 
71 	/* prepare request */
72 	rq.picmg_id = 0;
73 	rq.hpmx_id = 2;
74 
75 	/* prepare request */
76 	memset(&req, 0, sizeof(req));
77 	req.msg.netfn = IPMI_NETFN_PICMG;
78 	req.msg.cmd = HPM2_GET_LAN_ATTACH_CAPABILITIES;
79 	req.msg.data = (uint8_t *)&rq;
80 	req.msg.data_len = sizeof(rq);
81 
82 
83 	/* send */
84 	rsp = intf->sendrecv(intf, &req);
85 
86 	if (!rsp) {
87 		lprintf(LOG_NOTICE, "Error sending request.");
88 		return -1;
89 	}
90 
91 	if (rsp->ccode == 0xC1) {
92 		lprintf(LOG_DEBUG, "IPM Controller is not HPM.2 compatible");
93 		return rsp->ccode;
94 	} else if (rsp->ccode) {
95 		lprintf(LOG_NOTICE, "Get HPM.x Capabilities request failed,"
96 				" compcode = %x", rsp->ccode);
97 		return rsp->ccode;
98 	}
99 
100 	/* check response length */
101 	if (rsp->data_len < 2 || rsp->data_len > 10) {
102 		lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
103 		return -1;
104 	}
105 
106 	/* check HPM.x identifier */
107 	if (rsp->data[1] != 2) {
108 		lprintf(LOG_NOTICE, "Bad HPM.x ID, id=%d", rsp->data[1]);
109 		return rsp->ccode;
110 	}
111 
112 	/*
113 	 * this hardly can happen, since completion code is already checked.
114 	 * but check for safety
115 	 */
116 	if (rsp->data_len < 4) {
117 		lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
118 		return -1;
119 	}
120 
121 	/* copy HPM.2 capabilities */
122 	memcpy(caps, rsp->data + 2, rsp->data_len - 2);
123 
124 #if WORDS_BIGENDIAN
125 	/* swap bytes to convert from little-endian format */
126 	caps->lan_channel_mask = BSWAP_16(caps->lan_channel_mask);
127 #endif
128 
129 	/* check HPM.2 revision */
130 	if (caps->hpm2_revision_id != HPM2_REVISION) {
131 		lprintf(LOG_NOTICE, "Bad HPM.2 revision, rev=%d",
132 				caps->hpm2_revision_id);
133 		return -1;
134 	}
135 
136 	if (!caps->lan_channel_mask) {
137 		return -1;
138 	}
139 
140 	/* check response length */
141 	if (rsp->data_len < 8) {
142 		lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
143 		return -1;
144 	}
145 
146 	/* check HPM.2 LAN parameters start */
147 	if (caps->hpm2_lan_params_start < 0xC0) {
148 		lprintf(LOG_NOTICE, "Bad HPM.2 LAN params start, start=%x",
149 				caps->hpm2_lan_params_start);
150 		return -1;
151 	}
152 
153 	/* check HPM.2 LAN parameters revision */
154 	if (caps->hpm2_lan_params_rev != HPM2_LAN_PARAMS_REV) {
155 		lprintf(LOG_NOTICE, "Bad HPM.2 LAN params revision, rev=%d",
156 				caps->hpm2_lan_params_rev);
157 		return -1;
158 	}
159 
160 	/* check for HPM.2 SOL extension */
161 	if (!(caps->hpm2_caps & HPM2_CAPS_SOL_EXTENSION)) {
162 		/* no further checks */
163 		return 0;
164 	}
165 
166 	/* check response length */
167 	if (rsp->data_len < 10) {
168 		lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
169 		return -1;
170 	}
171 
172 	/* check HPM.2 SOL parameters start */
173 	if (caps->hpm2_sol_params_start < 0xC0) {
174 		lprintf(LOG_NOTICE, "Bad HPM.2 SOL params start, start=%x",
175 				caps->hpm2_sol_params_start);
176 		return -1;
177 	}
178 
179 	/* check HPM.2 SOL parameters revision */
180 	if (caps->hpm2_sol_params_rev != HPM2_SOL_PARAMS_REV) {
181 		lprintf(LOG_NOTICE, "Bad HPM.2 SOL params revision, rev=%d",
182 				caps->hpm2_sol_params_rev);
183 		return -1;
184 	}
185 
186 	return 0;
187 }
188 
189 int hpm2_get_lan_channel_capabilities(struct ipmi_intf * intf,
190 		uint8_t hpm2_lan_params_start,
191 		struct hpm2_lan_channel_capabilities * caps)
192 {
193 	struct ipmi_rq req;
194 	struct ipmi_rs * rsp;
195 	uint8_t rq[4];
196 
197 	/* reset result */
198 	memset(caps, 0, sizeof(struct hpm2_lan_channel_capabilities));
199 
200 	/* prepare request */
201 	memset(&req, 0, sizeof(req));
202 	req.msg.netfn = IPMI_NETFN_TRANSPORT;
203 	req.msg.cmd = IPMI_LAN_GET_CONFIG;
204 	req.msg.data = (uint8_t *)&rq;
205 	req.msg.data_len = sizeof(rq);
206 
207 	/* prepare request data */
208 	rq[0] = 0xE;					/* sending channel */
209 	rq[1] = hpm2_lan_params_start;	/* HPM.2 Channel Caps */
210 	rq[2] = rq[3] = 0;
211 
212 	/* send */
213 	rsp = intf->sendrecv(intf, &req);
214 
215 	if (rsp) {
216 		lprintf(LOG_NOTICE, "Error sending request");
217 		return -1;
218 	}
219 
220 	if (rsp->ccode == 0x80) {
221 		lprintf(LOG_DEBUG, "HPM.2 Channel Caps parameter is not supported");
222 		return rsp->ccode;
223 	} else if (rsp->ccode) {
224 		lprintf(LOG_NOTICE, "Get LAN Configuration Parameters request failed,"
225 				" compcode = %x", rsp->ccode);
226 		return rsp->ccode;
227 	}
228 
229 	/* check response length */
230 	if (rsp->data_len != sizeof (struct hpm2_lan_channel_capabilities) + 1) {
231 		lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
232 		return -1;
233 	}
234 
235 	/* check parameter revision */
236 	if (rsp->data[0] != HPM2_LAN_PARAMS_REV) {
237 		lprintf(LOG_NOTICE, "Bad HPM.2 LAN parameter revision, rev=%d",
238 				rsp->data[0]);
239 		return -1;
240 	}
241 
242 	/* copy parameter data */
243 	memcpy(caps, &rsp->data[1], sizeof (struct hpm2_lan_channel_capabilities));
244 
245 #if WORDS_BIGENDIAN
246 	/* swap bytes to convert from little-endian format */
247 	caps->max_inbound_pld_size = BSWAP_16(caps->max_inbound_pld_size);
248 	caps->max_outbound_pld_size = BSWAP_16(caps->max_outbound_pld_size);
249 #endif
250 
251 	return 0;
252 }
253 
254 int hpm2_detect_max_payload_size(struct ipmi_intf * intf)
255 {
256 	struct hpm2_lan_attach_capabilities attach_caps;
257 	struct hpm2_lan_channel_capabilities channel_caps;
258 	int err;
259 
260 	/* query HPM.2 support */
261 	err = hpm2_get_capabilities(intf, &attach_caps);
262 
263 	/* check if HPM.2 is supported */
264 	if (err != 0 || !attach_caps.lan_channel_mask) {
265 		return err;
266 	}
267 
268 	/* query channel capabilities */
269 	err = hpm2_get_lan_channel_capabilities(intf,
270 			attach_caps.hpm2_lan_params_start, &channel_caps);
271 
272 	/* check if succeeded */
273 	if (err != 0) {
274 		return err;
275 	}
276 
277 	/* update request and response sizes */
278 	ipmi_intf_set_max_request_data_size(intf,
279 			channel_caps.max_inbound_pld_size - 7);
280 	ipmi_intf_set_max_response_data_size(intf,
281 			channel_caps.max_outbound_pld_size - 8);
282 
283 	/* print debug info */
284 	lprintf(LOG_DEBUG, "Set maximum request size to %d\n"
285 			"Set maximum response size to %d",
286 			intf->max_request_data_size, intf->max_response_data_size);
287 
288 	return 0;
289 }
290