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