1 /* 2 * Copyright (c) 2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc. or 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 * SUN MICROSYSTEMS, INC. ("SUN") 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 * SUN 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 SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31 */ 32 33 34 /* 35 * interface routines between ipmitool and the bmc kernel driver 36 */ 37 38 #include <stdio.h> 39 #include <fcntl.h> 40 #include <unistd.h> 41 #include <sys/ioctl.h> 42 #include <errno.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <sys/types.h> 46 #include <sys/stropts.h> 47 #include <stddef.h> 48 #include <stropts.h> 49 50 #include <ipmitool/ipmi.h> 51 #include <ipmitool/ipmi_intf.h> 52 #include "bmc_intf.h" 53 54 #include "bmc.h" 55 56 static int curr_seq; 57 static int bmc_method(int fd, int *if_type); 58 struct ipmi_rs *(*sendrecv_fn)(struct ipmi_intf *, struct ipmi_rq *) = NULL; 59 extern int verbose; 60 61 static void dump_request(bmc_req_t *request); 62 static void dump_response(bmc_rsp_t *response); 63 static struct ipmi_rs *ipmi_bmc_send_cmd_ioctl(struct ipmi_intf *intf, 64 struct ipmi_rq *req); 65 static struct ipmi_rs *ipmi_bmc_send_cmd_putmsg(struct ipmi_intf *intf, 66 struct ipmi_rq *req); 67 68 #define MESSAGE_BUFSIZE 1024 69 70 struct ipmi_intf ipmi_bmc_intf = { 71 name: "bmc", 72 desc: "IPMI v2.0 BMC interface", 73 open: ipmi_bmc_open, 74 close: ipmi_bmc_close, 75 sendrecv: ipmi_bmc_send_cmd}; 76 77 void 78 ipmi_bmc_close(struct ipmi_intf *intf) 79 { 80 if (intf && intf->fd >= 0) 81 close(intf->fd); 82 83 intf->opened = 0; 84 intf->manufacturer_id = IPMI_OEM_UNKNOWN; 85 intf->fd = -1; 86 } 87 88 int 89 ipmi_bmc_open(struct ipmi_intf *intf) 90 { 91 int method; 92 93 if (!intf) 94 return -1; 95 96 /* Open local device */ 97 intf->fd = open(BMC_DEV, O_RDWR); 98 99 if (intf->fd <= 0) { 100 perror("Could not open bmc device"); 101 return (-1); 102 } 103 curr_seq = 0; 104 105 intf->opened = 1; 106 107 if (bmc_method(intf->fd, &method) < 0) { 108 perror("Could not determine bmc messaging interface"); 109 return (-1); 110 } 111 112 sendrecv_fn = (method == BMC_PUTMSG_METHOD) ? 113 ipmi_bmc_send_cmd_putmsg : ipmi_bmc_send_cmd_ioctl; 114 115 intf->manufacturer_id = ipmi_get_oem(intf); 116 return (intf->fd); 117 } 118 119 struct ipmi_rs * 120 ipmi_bmc_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req) 121 { 122 /* If not already opened open the device or network connection */ 123 if (!intf->opened && intf->open && intf->open(intf) < 0) 124 return NULL; 125 126 /* sendrecv_fn cannot be NULL at this point */ 127 return ((*sendrecv_fn)(intf, req)); 128 } 129 130 static struct ipmi_rs * 131 ipmi_bmc_send_cmd_ioctl(struct ipmi_intf *intf, struct ipmi_rq *req) 132 { 133 struct strioctl istr; 134 static struct bmc_reqrsp reqrsp; 135 static struct ipmi_rs rsp; 136 137 memset(&reqrsp, 0, sizeof (reqrsp)); 138 reqrsp.req.fn = req->msg.netfn; 139 reqrsp.req.lun = 0; 140 reqrsp.req.cmd = req->msg.cmd; 141 reqrsp.req.datalength = req->msg.data_len; 142 memcpy(reqrsp.req.data, req->msg.data, req->msg.data_len); 143 reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE; 144 145 istr.ic_cmd = IOCTL_IPMI_KCS_ACTION; 146 istr.ic_timout = 0; 147 istr.ic_dp = (char *)&reqrsp; 148 istr.ic_len = sizeof (struct bmc_reqrsp); 149 150 if (verbose) { 151 printf("--\n"); 152 dump_request(&reqrsp.req); 153 printf("--\n"); 154 } 155 156 if (ioctl(intf->fd, I_STR, &istr) < 0) { 157 perror("BMC IOCTL: I_STR"); 158 return (NULL); 159 } 160 161 if (verbose > 2) { 162 dump_response(&reqrsp.rsp); 163 printf("--\n"); 164 } 165 166 memset(&rsp, 0, sizeof (struct ipmi_rs)); 167 rsp.ccode = reqrsp.rsp.ccode; 168 rsp.data_len = reqrsp.rsp.datalength; 169 170 /* Decrement for sizeof lun, cmd and ccode */ 171 rsp.data_len -= 3; 172 173 if (!rsp.ccode && (rsp.data_len > 0)) 174 memcpy(rsp.data, reqrsp.rsp.data, rsp.data_len); 175 176 return (&rsp); 177 } 178 179 static struct ipmi_rs * 180 ipmi_bmc_send_cmd_putmsg(struct ipmi_intf *intf, struct ipmi_rq *req) 181 { 182 struct strbuf sb; 183 int flags = 0; 184 static uint32_t msg_seq = 0; 185 186 /* 187 * The length of the message structure is equal to the size of the 188 * bmc_req_t structure, PLUS any additional data space in excess of 189 * the data space already reserved in the data member + <n> for 190 * the rest of the members in the bmc_msg_t structure. 191 */ 192 int msgsz = offsetof(bmc_msg_t, msg) + sizeof(bmc_req_t) + 193 ((req->msg.data_len > SEND_MAX_PAYLOAD_SIZE) ? 194 (req->msg.data_len - SEND_MAX_PAYLOAD_SIZE) : 0); 195 bmc_msg_t *msg = malloc(msgsz); 196 bmc_req_t *request = (bmc_req_t *)&msg->msg[0]; 197 bmc_rsp_t *response; 198 static struct ipmi_rs rsp; 199 struct ipmi_rs *ret = NULL; 200 201 msg->m_type = BMC_MSG_REQUEST; 202 msg->m_id = msg_seq++; 203 request->fn = req->msg.netfn; 204 request->lun = 0; 205 request->cmd = req->msg.cmd; 206 request->datalength = req->msg.data_len; 207 memcpy(request->data, req->msg.data, req->msg.data_len); 208 209 sb.len = msgsz; 210 sb.buf = (unsigned char *)msg; 211 212 if (verbose) { 213 printf("--\n"); 214 dump_request(request); 215 printf("--\n"); 216 } 217 218 if (putmsg(intf->fd, NULL, &sb, 0) < 0) { 219 perror("BMC putmsg: "); 220 free(msg); 221 msg = NULL; 222 return (NULL); 223 } 224 225 free(msg); 226 msg = NULL; 227 228 sb.buf = malloc(MESSAGE_BUFSIZE); 229 sb.maxlen = MESSAGE_BUFSIZE; 230 231 if (getmsg(intf->fd, NULL, &sb, &flags) < 0) { 232 perror("BMC getmsg: "); 233 free(sb.buf); 234 sb.buf = NULL; 235 return (NULL); 236 } 237 238 msg = (bmc_msg_t *)sb.buf; 239 240 if (verbose > 3) { 241 printf("Got msg (id 0x%x) type 0x%x\n", msg->m_id, msg->m_type); 242 } 243 244 245 /* Did we get an error back from the stream? */ 246 switch (msg->m_type) { 247 248 case BMC_MSG_RESPONSE: 249 response = (bmc_rsp_t *)&msg->msg[0]; 250 251 if (verbose > 2) { 252 dump_response(response); 253 printf("--\n"); 254 } 255 256 memset(&rsp, 0, sizeof (struct ipmi_rs)); 257 rsp.ccode = response->ccode; 258 rsp.data_len = response->datalength; 259 260 if (!rsp.ccode && (rsp.data_len > 0)) 261 memcpy(rsp.data, response->data, rsp.data_len); 262 263 ret = &rsp; 264 break; 265 266 case BMC_MSG_ERROR: 267 /* In case of an error, msg->msg[0] has the error code */ 268 printf("bmc_send_cmd: %s\n", strerror(msg->msg[0])); 269 break; 270 271 } 272 273 free(sb.buf); 274 sb.buf = NULL; 275 return (ret); 276 } 277 278 /* 279 * Determine which interface to use. Returns the interface method 280 * to use. 281 */ 282 static int 283 bmc_method(int fd, int *if_type) 284 { 285 struct strioctl istr; 286 int retval = 0; 287 uint8_t method = BMC_PUTMSG_METHOD; 288 289 istr.ic_cmd = IOCTL_IPMI_INTERFACE_METHOD; 290 istr.ic_timout = 0; 291 istr.ic_dp = (uint8_t *)&method; 292 istr.ic_len = 1; 293 294 /* 295 * If the ioctl doesn't exist, we should get an EINVAL back. 296 * Bail out on any other error. 297 */ 298 if (ioctl(fd, I_STR, &istr) < 0) { 299 300 if (errno != EINVAL) 301 retval = -1; 302 else 303 method = BMC_IOCTL_METHOD; 304 } 305 306 if (retval == 0) 307 *if_type = method; 308 309 return (retval); 310 } 311 312 static void 313 dump_request(bmc_req_t *request) 314 { 315 int i; 316 317 printf("BMC req.fn : 0x%x\n", request->fn); 318 printf("BMC req.lun : 0x%x\n", request->lun); 319 printf("BMC req.cmd : 0x%x\n", request->cmd); 320 printf("BMC req.datalength : 0x%x\n", request->datalength); 321 printf("BMC req.data : "); 322 323 if (request->datalength > 0) { 324 for (i = 0; i < request->datalength; i++) 325 printf("0x%x ", request->data[i]); 326 } else { 327 printf("<NONE>"); 328 } 329 printf("\n"); 330 } 331 332 static void 333 dump_response(bmc_rsp_t *response) 334 { 335 int i; 336 337 printf("BMC rsp.fn : 0x%x\n", response->fn); 338 printf("BMC rsp.lun : 0x%x\n", response->lun); 339 printf("BMC rsp.cmd : 0x%x\n", response->cmd); 340 printf("BMC rsp.ccode : 0x%x\n", response->ccode); 341 printf("BMC rsp.datalength : 0x%x\n", response->datalength); 342 printf("BMC rsp.data : "); 343 344 if (response->datalength > 0) { 345 for (i = 0; i < response->datalength; i++) 346 printf("0x%x ", response->data[i]); 347 } else { 348 printf("<NONE>"); 349 } 350 printf("\n"); 351 } 352