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
ipmi_bmc_close(void * data)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 *
ipmi_bmc_open(ipmi_handle_t * ihp,nvlist_t * params)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
ipmi_bmc_send(void * data,ipmi_cmd_t * cmd,ipmi_cmd_t * response,int * completion)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