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 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 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 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