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;
104*989f2807SJerry Jelinek 
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;
108*989f2807SJerry Jelinek 
109*989f2807SJerry Jelinek 	(void) memset(&req, 0, sizeof (struct ipmi_req));
110*989f2807SJerry Jelinek 
111*989f2807SJerry Jelinek 	req.addr = (unsigned char *) &bmc_addr;
112*989f2807SJerry Jelinek 	req.addr_len = sizeof (bmc_addr);
113*989f2807SJerry Jelinek 
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) {
1329113a79cSeschrock 		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s",
1339113a79cSeschrock 		    strerror(errno));
1349113a79cSeschrock 		return (-1);
1359113a79cSeschrock 	}
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 	}
1419113a79cSeschrock 
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) {
149*989f2807SJerry Jelinek 		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s",
150*989f2807SJerry Jelinek 		    strerror(errno));
1519113a79cSeschrock 		return (-1);
152*989f2807SJerry Jelinek 	}
1539113a79cSeschrock 
154*989f2807SJerry Jelinek 	if (recv.recv_type != IPMI_RESPONSE_RECV_TYPE) {
1559113a79cSeschrock 		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE,
156*989f2807SJerry Jelinek 		    "unknown BMC message type %d", recv.recv_type);
1579113a79cSeschrock 		return (-1);
1589113a79cSeschrock 	}
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];
166*989f2807SJerry Jelinek 		response->ic_dlen = 0;
167*989f2807SJerry Jelinek 		response->ic_data = NULL;
168*989f2807SJerry Jelinek 	} else {
169*989f2807SJerry Jelinek 		*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]);
173*989f2807SJerry Jelinek 	}
174*989f2807SJerry Jelinek 
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