1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2012 Joyent, Inc. All rights reserved. 25 */ 26 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <libipmi.h> 30 #include <stddef.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <stropts.h> 35 #include <unistd.h> 36 37 #include <sys/ipmi.h> 38 39 #include "ipmi_impl.h" 40 41 /* 42 * IPMI transport for the local BMC at /dev/ipmi0. 43 */ 44 45 typedef struct ipmi_bmc { 46 ipmi_handle_t *ib_ihp; /* ipmi handle */ 47 int ib_fd; /* /dev/ipmi0 filedescriptor */ 48 uint32_t ib_msgseq; /* message sequence number */ 49 uint8_t *ib_msg; /* message buffer */ 50 size_t ib_msglen; /* size of message buffer */ 51 } ipmi_bmc_t; 52 53 #define BMC_DEV "/dev/ipmi0" 54 55 static void 56 ipmi_bmc_close(void *data) 57 { 58 ipmi_bmc_t *ibp = data; 59 60 ipmi_free(ibp->ib_ihp, ibp->ib_msg); 61 62 (void) close(ibp->ib_fd); 63 64 ipmi_free(ibp->ib_ihp, ibp); 65 } 66 67 /*ARGSUSED*/ 68 static void * 69 ipmi_bmc_open(ipmi_handle_t *ihp, nvlist_t *params) 70 { 71 ipmi_bmc_t *ibp; 72 73 if ((ibp = ipmi_zalloc(ihp, sizeof (ipmi_bmc_t))) == NULL) 74 return (NULL); 75 ibp->ib_ihp = ihp; 76 77 /* open /dev/ipmi0 */ 78 if ((ibp->ib_fd = open(BMC_DEV, O_RDWR)) < 0) { 79 ipmi_free(ihp, ibp); 80 (void) ipmi_set_error(ihp, EIPMI_BMC_OPEN_FAILED, "%s", 81 strerror(errno)); 82 return (NULL); 83 } 84 85 if ((ibp->ib_msg = (uint8_t *)ipmi_zalloc(ihp, BUFSIZ)) == NULL) { 86 ipmi_bmc_close(ibp); 87 return (NULL); 88 } 89 ibp->ib_msglen = BUFSIZ; 90 91 return (ibp); 92 } 93 94 static int 95 ipmi_bmc_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response, 96 int *completion) 97 { 98 ipmi_bmc_t *ibp = data; 99 struct ipmi_req req; 100 struct ipmi_recv recv; 101 struct ipmi_addr addr; 102 fd_set rset; 103 struct ipmi_system_interface_addr bmc_addr; 104 105 bmc_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; 106 bmc_addr.channel = IPMI_BMC_CHANNEL; 107 bmc_addr.lun = cmd->ic_lun; 108 109 (void) memset(&req, 0, sizeof (struct ipmi_req)); 110 111 req.addr = (unsigned char *) &bmc_addr; 112 req.addr_len = sizeof (bmc_addr); 113 114 req.msgid = ibp->ib_msgseq++; 115 req.msg.netfn = cmd->ic_netfn; 116 req.msg.cmd = cmd->ic_cmd; 117 req.msg.data = cmd->ic_data; 118 req.msg.data_len = cmd->ic_dlen; 119 120 if (ioctl(ibp->ib_fd, IPMICTL_SEND_COMMAND, &req) < 0) { 121 (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_PUTMSG, "%s", 122 strerror(errno)); 123 return (-1); 124 } 125 126 /* get the response from the BMC */ 127 128 FD_ZERO(&rset); 129 FD_SET(ibp->ib_fd, &rset); 130 131 if (select(ibp->ib_fd + 1, &rset, NULL, NULL, NULL) < 0) { 132 (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", 133 strerror(errno)); 134 return (-1); 135 } 136 if (FD_ISSET(ibp->ib_fd, &rset) == 0) { 137 (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", 138 "No data available"); 139 return (-1); 140 } 141 142 recv.addr = (unsigned char *) &addr; 143 recv.addr_len = sizeof (addr); 144 recv.msg.data = (unsigned char *)ibp->ib_msg; 145 recv.msg.data_len = ibp->ib_msglen; 146 147 /* get data */ 148 if (ioctl(ibp->ib_fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) { 149 (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", 150 strerror(errno)); 151 return (-1); 152 } 153 154 if (recv.recv_type != IPMI_RESPONSE_RECV_TYPE) { 155 (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, 156 "unknown BMC message type %d", recv.recv_type); 157 return (-1); 158 } 159 160 response->ic_netfn = recv.msg.netfn; 161 /* The lun is not returned in addr, return the lun passed in */ 162 response->ic_lun = cmd->ic_lun; 163 response->ic_cmd = recv.msg.cmd; 164 if (recv.msg.data[0] != 0) { 165 *completion = recv.msg.data[0]; 166 response->ic_dlen = 0; 167 response->ic_data = NULL; 168 } else { 169 *completion = 0; 170 response->ic_dlen = (recv.msg.data_len > 0) ? 171 recv.msg.data_len - 1 : 0; 172 response->ic_data = &(recv.msg.data[1]); 173 } 174 175 return (0); 176 } 177 178 ipmi_transport_t ipmi_transport_bmc = { 179 ipmi_bmc_open, 180 ipmi_bmc_close, 181 ipmi_bmc_send 182 }; 183