19113a79cSeschrock /* 29113a79cSeschrock * CDDL HEADER START 39113a79cSeschrock * 49113a79cSeschrock * The contents of this file are subject to the terms of the 59113a79cSeschrock * Common Development and Distribution License (the "License"). 69113a79cSeschrock * You may not use this file except in compliance with the License. 79113a79cSeschrock * 89113a79cSeschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99113a79cSeschrock * or http://www.opensolaris.org/os/licensing. 109113a79cSeschrock * See the License for the specific language governing permissions 119113a79cSeschrock * and limitations under the License. 129113a79cSeschrock * 139113a79cSeschrock * When distributing Covered Code, include this CDDL HEADER in each 149113a79cSeschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159113a79cSeschrock * If applicable, add the following below this CDDL HEADER, with the 169113a79cSeschrock * fields enclosed by brackets "[]" replaced with your own identifying 179113a79cSeschrock * information: Portions Copyright [yyyy] [name of copyright owner] 189113a79cSeschrock * 199113a79cSeschrock * CDDL HEADER END 209113a79cSeschrock */ 219113a79cSeschrock /* 2281d9f076SRobert Johnston * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 239113a79cSeschrock * Use is subject to license terms. 24*989f2807SJerry Jelinek * Copyright 2012 Joyent, Inc. All rights reserved. 259113a79cSeschrock */ 269113a79cSeschrock 279113a79cSeschrock #include <errno.h> 289113a79cSeschrock #include <fcntl.h> 299113a79cSeschrock #include <libipmi.h> 309113a79cSeschrock #include <stddef.h> 319113a79cSeschrock #include <stdio.h> 329113a79cSeschrock #include <stdlib.h> 339113a79cSeschrock #include <string.h> 349113a79cSeschrock #include <stropts.h> 359113a79cSeschrock #include <unistd.h> 369113a79cSeschrock 37*989f2807SJerry Jelinek #include <sys/ipmi.h> 389113a79cSeschrock 399113a79cSeschrock #include "ipmi_impl.h" 409113a79cSeschrock 419113a79cSeschrock /* 42*989f2807SJerry Jelinek * IPMI transport for the local BMC at /dev/ipmi0. 439113a79cSeschrock */ 449113a79cSeschrock 459113a79cSeschrock typedef struct ipmi_bmc { 469113a79cSeschrock ipmi_handle_t *ib_ihp; /* ipmi handle */ 47*989f2807SJerry Jelinek int ib_fd; /* /dev/ipmi0 filedescriptor */ 489113a79cSeschrock uint32_t ib_msgseq; /* message sequence number */ 49*989f2807SJerry Jelinek uint8_t *ib_msg; /* message buffer */ 509113a79cSeschrock size_t ib_msglen; /* size of message buffer */ 519113a79cSeschrock } ipmi_bmc_t; 529113a79cSeschrock 53*989f2807SJerry Jelinek #define BMC_DEV "/dev/ipmi0" 549113a79cSeschrock 559113a79cSeschrock static void 569113a79cSeschrock ipmi_bmc_close(void *data) 579113a79cSeschrock { 589113a79cSeschrock ipmi_bmc_t *ibp = data; 599113a79cSeschrock 609113a79cSeschrock ipmi_free(ibp->ib_ihp, ibp->ib_msg); 619113a79cSeschrock 629113a79cSeschrock (void) close(ibp->ib_fd); 639113a79cSeschrock 649113a79cSeschrock ipmi_free(ibp->ib_ihp, ibp); 659113a79cSeschrock } 669113a79cSeschrock 6781d9f076SRobert Johnston /*ARGSUSED*/ 689113a79cSeschrock static void * 6981d9f076SRobert Johnston ipmi_bmc_open(ipmi_handle_t *ihp, nvlist_t *params) 709113a79cSeschrock { 719113a79cSeschrock ipmi_bmc_t *ibp; 729113a79cSeschrock 739113a79cSeschrock if ((ibp = ipmi_zalloc(ihp, sizeof (ipmi_bmc_t))) == NULL) 749113a79cSeschrock return (NULL); 759113a79cSeschrock ibp->ib_ihp = ihp; 769113a79cSeschrock 77*989f2807SJerry Jelinek /* open /dev/ipmi0 */ 789113a79cSeschrock if ((ibp->ib_fd = open(BMC_DEV, O_RDWR)) < 0) { 799113a79cSeschrock ipmi_free(ihp, ibp); 809113a79cSeschrock (void) ipmi_set_error(ihp, EIPMI_BMC_OPEN_FAILED, "%s", 819113a79cSeschrock strerror(errno)); 829113a79cSeschrock return (NULL); 839113a79cSeschrock } 849113a79cSeschrock 85*989f2807SJerry Jelinek if ((ibp->ib_msg = (uint8_t *)ipmi_zalloc(ihp, BUFSIZ)) == NULL) { 869113a79cSeschrock ipmi_bmc_close(ibp); 879113a79cSeschrock return (NULL); 889113a79cSeschrock } 899113a79cSeschrock ibp->ib_msglen = BUFSIZ; 909113a79cSeschrock 919113a79cSeschrock return (ibp); 929113a79cSeschrock } 939113a79cSeschrock 949113a79cSeschrock static int 959113a79cSeschrock ipmi_bmc_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response, 969113a79cSeschrock int *completion) 979113a79cSeschrock { 989113a79cSeschrock ipmi_bmc_t *ibp = data; 99*989f2807SJerry Jelinek struct ipmi_req req; 100*989f2807SJerry Jelinek struct ipmi_recv recv; 101*989f2807SJerry Jelinek struct ipmi_addr addr; 102*989f2807SJerry Jelinek fd_set rset; 103*989f2807SJerry Jelinek struct ipmi_system_interface_addr bmc_addr; 1049113a79cSeschrock 105*989f2807SJerry Jelinek bmc_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; 106*989f2807SJerry Jelinek bmc_addr.channel = IPMI_BMC_CHANNEL; 107*989f2807SJerry Jelinek bmc_addr.lun = cmd->ic_lun; 1089113a79cSeschrock 109*989f2807SJerry Jelinek (void) memset(&req, 0, sizeof (struct ipmi_req)); 1109113a79cSeschrock 111*989f2807SJerry Jelinek req.addr = (unsigned char *) &bmc_addr; 112*989f2807SJerry Jelinek req.addr_len = sizeof (bmc_addr); 1139113a79cSeschrock 114*989f2807SJerry Jelinek req.msgid = ibp->ib_msgseq++; 115*989f2807SJerry Jelinek req.msg.netfn = cmd->ic_netfn; 116*989f2807SJerry Jelinek req.msg.cmd = cmd->ic_cmd; 117*989f2807SJerry Jelinek req.msg.data = cmd->ic_data; 118*989f2807SJerry Jelinek req.msg.data_len = cmd->ic_dlen; 119*989f2807SJerry Jelinek 120*989f2807SJerry Jelinek if (ioctl(ibp->ib_fd, IPMICTL_SEND_COMMAND, &req) < 0) { 1219113a79cSeschrock (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_PUTMSG, "%s", 1229113a79cSeschrock strerror(errno)); 1239113a79cSeschrock return (-1); 1249113a79cSeschrock } 1259113a79cSeschrock 1269113a79cSeschrock /* get the response from the BMC */ 1279113a79cSeschrock 128*989f2807SJerry Jelinek FD_ZERO(&rset); 129*989f2807SJerry Jelinek FD_SET(ibp->ib_fd, &rset); 130*989f2807SJerry Jelinek 131*989f2807SJerry Jelinek if (select(ibp->ib_fd + 1, &rset, NULL, NULL, NULL) < 0) { 132*989f2807SJerry Jelinek (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", 133*989f2807SJerry Jelinek strerror(errno)); 134*989f2807SJerry Jelinek return (-1); 135*989f2807SJerry Jelinek } 136*989f2807SJerry Jelinek if (FD_ISSET(ibp->ib_fd, &rset) == 0) { 137*989f2807SJerry Jelinek (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", 138*989f2807SJerry Jelinek "No data available"); 139*989f2807SJerry Jelinek return (-1); 140*989f2807SJerry Jelinek } 141*989f2807SJerry Jelinek 142*989f2807SJerry Jelinek recv.addr = (unsigned char *) &addr; 143*989f2807SJerry Jelinek recv.addr_len = sizeof (addr); 144*989f2807SJerry Jelinek recv.msg.data = (unsigned char *)ibp->ib_msg; 145*989f2807SJerry Jelinek recv.msg.data_len = ibp->ib_msglen; 146*989f2807SJerry Jelinek 147*989f2807SJerry Jelinek /* get data */ 148*989f2807SJerry Jelinek if (ioctl(ibp->ib_fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) { 1499113a79cSeschrock (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", 1509113a79cSeschrock strerror(errno)); 1519113a79cSeschrock return (-1); 1529113a79cSeschrock } 1539113a79cSeschrock 154*989f2807SJerry Jelinek if (recv.recv_type != IPMI_RESPONSE_RECV_TYPE) { 155*989f2807SJerry Jelinek (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, 156*989f2807SJerry Jelinek "unknown BMC message type %d", recv.recv_type); 157*989f2807SJerry Jelinek return (-1); 158*989f2807SJerry Jelinek } 1599113a79cSeschrock 160*989f2807SJerry Jelinek response->ic_netfn = recv.msg.netfn; 161*989f2807SJerry Jelinek /* The lun is not returned in addr, return the lun passed in */ 162*989f2807SJerry Jelinek response->ic_lun = cmd->ic_lun; 163*989f2807SJerry Jelinek response->ic_cmd = recv.msg.cmd; 164*989f2807SJerry Jelinek if (recv.msg.data[0] != 0) { 165*989f2807SJerry Jelinek *completion = recv.msg.data[0]; 1669113a79cSeschrock response->ic_dlen = 0; 1679113a79cSeschrock response->ic_data = NULL; 1689113a79cSeschrock } else { 1699113a79cSeschrock *completion = 0; 170*989f2807SJerry Jelinek response->ic_dlen = (recv.msg.data_len > 0) ? 171*989f2807SJerry Jelinek recv.msg.data_len - 1 : 0; 172*989f2807SJerry Jelinek response->ic_data = &(recv.msg.data[1]); 1739113a79cSeschrock } 1749113a79cSeschrock 1759113a79cSeschrock return (0); 1769113a79cSeschrock } 1779113a79cSeschrock 1789113a79cSeschrock ipmi_transport_t ipmi_transport_bmc = { 1799113a79cSeschrock ipmi_bmc_open, 1809113a79cSeschrock ipmi_bmc_close, 1819113a79cSeschrock ipmi_bmc_send 1829113a79cSeschrock }; 183