xref: /openbmc/ipmitool/src/plugins/open/open.c (revision 33f9336e8522af712563699089c3227531586cdd)
1c18ec02fSPetter Reinholdtsen /*
2c18ec02fSPetter Reinholdtsen  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3c18ec02fSPetter Reinholdtsen  *
4c18ec02fSPetter Reinholdtsen  * Redistribution and use in source and binary forms, with or without
5c18ec02fSPetter Reinholdtsen  * modification, are permitted provided that the following conditions
6c18ec02fSPetter Reinholdtsen  * are met:
7c18ec02fSPetter Reinholdtsen  *
8c18ec02fSPetter Reinholdtsen  * Redistribution of source code must retain the above copyright
9c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer.
10c18ec02fSPetter Reinholdtsen  *
11c18ec02fSPetter Reinholdtsen  * Redistribution in binary form must reproduce the above copyright
12c18ec02fSPetter Reinholdtsen  * notice, this list of conditions and the following disclaimer in the
13c18ec02fSPetter Reinholdtsen  * documentation and/or other materials provided with the distribution.
14c18ec02fSPetter Reinholdtsen  *
15c18ec02fSPetter Reinholdtsen  * Neither the name of Sun Microsystems, Inc. or the names of
16c18ec02fSPetter Reinholdtsen  * contributors may be used to endorse or promote products derived
17c18ec02fSPetter Reinholdtsen  * from this software without specific prior written permission.
18c18ec02fSPetter Reinholdtsen  *
19c18ec02fSPetter Reinholdtsen  * This software is provided "AS IS," without a warranty of any kind.
20c18ec02fSPetter Reinholdtsen  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21c18ec02fSPetter Reinholdtsen  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22c18ec02fSPetter Reinholdtsen  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23c18ec02fSPetter Reinholdtsen  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24c18ec02fSPetter Reinholdtsen  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25c18ec02fSPetter Reinholdtsen  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26c18ec02fSPetter Reinholdtsen  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27c18ec02fSPetter Reinholdtsen  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28c18ec02fSPetter Reinholdtsen  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29c18ec02fSPetter Reinholdtsen  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30c18ec02fSPetter Reinholdtsen  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31c18ec02fSPetter Reinholdtsen  */
32ce02ffafSZdenek Styblik #define _POSIX_SOURCE
33c18ec02fSPetter Reinholdtsen 
34c18ec02fSPetter Reinholdtsen #include <stdio.h>
35c18ec02fSPetter Reinholdtsen #include <fcntl.h>
36c18ec02fSPetter Reinholdtsen #include <unistd.h>
37c18ec02fSPetter Reinholdtsen #include <sys/ioctl.h>
38c18ec02fSPetter Reinholdtsen #include <errno.h>
39c18ec02fSPetter Reinholdtsen #include <stdlib.h>
40c18ec02fSPetter Reinholdtsen #include <string.h>
41c18ec02fSPetter Reinholdtsen #include <sys/types.h>
42ce02ffafSZdenek Styblik #include <sys/select.h>
43c18ec02fSPetter Reinholdtsen #include <sys/stat.h>
44c18ec02fSPetter Reinholdtsen 
45c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h>
46c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h>
47c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h>
48c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h>
49c18ec02fSPetter Reinholdtsen 
50c18ec02fSPetter Reinholdtsen #if defined(HAVE_CONFIG_H)
51c18ec02fSPetter Reinholdtsen # include <config.h>
52c18ec02fSPetter Reinholdtsen #endif
53c18ec02fSPetter Reinholdtsen 
54c18ec02fSPetter Reinholdtsen #if defined(HAVE_SYS_IOCCOM_H)
55c18ec02fSPetter Reinholdtsen # include <sys/ioccom.h>
56c18ec02fSPetter Reinholdtsen #endif
57c18ec02fSPetter Reinholdtsen 
58c18ec02fSPetter Reinholdtsen #if defined(HAVE_OPENIPMI_H)
59c18ec02fSPetter Reinholdtsen # if defined(HAVE_LINUX_COMPILER_H)
60c18ec02fSPetter Reinholdtsen #  include <linux/compiler.h>
61c18ec02fSPetter Reinholdtsen # endif
62c18ec02fSPetter Reinholdtsen # include <linux/ipmi.h>
63c18ec02fSPetter Reinholdtsen #elif defined(HAVE_FREEBSD_IPMI_H)
64c18ec02fSPetter Reinholdtsen /* FreeBSD OpenIPMI-compatible header */
65c18ec02fSPetter Reinholdtsen # include <sys/ipmi.h>
66c18ec02fSPetter Reinholdtsen #else
67c18ec02fSPetter Reinholdtsen # include "open.h"
68c18ec02fSPetter Reinholdtsen #endif
69c18ec02fSPetter Reinholdtsen 
7023e9340bSZdenek Styblik /**
7123e9340bSZdenek Styblik  * Maximum input message size for KCS/SMIC is 40 with 2 utility bytes and
7223e9340bSZdenek Styblik  * 38 bytes of data.
7323e9340bSZdenek Styblik  * Maximum input message size for BT is 42 with 4 utility bytes and
7423e9340bSZdenek Styblik  * 38 bytes of data.
7523e9340bSZdenek Styblik  */
7623e9340bSZdenek Styblik #define IPMI_OPENIPMI_MAX_RQ_DATA_SIZE 38
7723e9340bSZdenek Styblik 
7823e9340bSZdenek Styblik /**
7923e9340bSZdenek Styblik  * Maximum output message size for KCS/SMIC is 38 with 2 utility bytes, a byte
8023e9340bSZdenek Styblik  * for completion code and 35 bytes of data.
8123e9340bSZdenek Styblik  * Maximum output message size for BT is 40 with 4 utility bytes, a byte
8223e9340bSZdenek Styblik  * for completion code and 35 bytes of data.
8323e9340bSZdenek Styblik  */
8423e9340bSZdenek Styblik #define IPMI_OPENIPMI_MAX_RS_DATA_SIZE 35
8523e9340bSZdenek Styblik 
86c18ec02fSPetter Reinholdtsen extern int verbose;
87c18ec02fSPetter Reinholdtsen 
88c18ec02fSPetter Reinholdtsen static int
ipmi_openipmi_open(struct ipmi_intf * intf)89c18ec02fSPetter Reinholdtsen ipmi_openipmi_open(struct ipmi_intf * intf)
90c18ec02fSPetter Reinholdtsen {
91c18ec02fSPetter Reinholdtsen 	int i = 0;
92c18ec02fSPetter Reinholdtsen 
93c18ec02fSPetter Reinholdtsen 	char ipmi_dev[16];
94c18ec02fSPetter Reinholdtsen 	char ipmi_devfs[16];
95c18ec02fSPetter Reinholdtsen 	char ipmi_devfs2[16];
96c18ec02fSPetter Reinholdtsen 	int devnum = 0;
97c18ec02fSPetter Reinholdtsen 
98c18ec02fSPetter Reinholdtsen 	devnum = intf->devnum;
99c18ec02fSPetter Reinholdtsen 
100c18ec02fSPetter Reinholdtsen 	sprintf(ipmi_dev, "/dev/ipmi%d", devnum);
101c18ec02fSPetter Reinholdtsen 	sprintf(ipmi_devfs, "/dev/ipmi/%d", devnum);
102c18ec02fSPetter Reinholdtsen 	sprintf(ipmi_devfs2, "/dev/ipmidev/%d", devnum);
103c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Using ipmi device %d", devnum);
104c18ec02fSPetter Reinholdtsen 
105c18ec02fSPetter Reinholdtsen 	intf->fd = open(ipmi_dev, O_RDWR);
106c18ec02fSPetter Reinholdtsen 
107c18ec02fSPetter Reinholdtsen 	if (intf->fd < 0) {
108c18ec02fSPetter Reinholdtsen 		intf->fd = open(ipmi_devfs, O_RDWR);
109c18ec02fSPetter Reinholdtsen 		if (intf->fd < 0) {
110c18ec02fSPetter Reinholdtsen 			intf->fd = open(ipmi_devfs2, O_RDWR);
111c18ec02fSPetter Reinholdtsen 		}
112c18ec02fSPetter Reinholdtsen 		if (intf->fd < 0) {
113c18ec02fSPetter Reinholdtsen 			lperror(LOG_ERR, "Could not open device at %s or %s or %s",
114c18ec02fSPetter Reinholdtsen 			ipmi_dev, ipmi_devfs , ipmi_devfs2);
115c18ec02fSPetter Reinholdtsen 			return -1;
116c18ec02fSPetter Reinholdtsen 		}
117c18ec02fSPetter Reinholdtsen 	}
118c18ec02fSPetter Reinholdtsen 
119c18ec02fSPetter Reinholdtsen 	if (ioctl(intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i) < 0) {
120c18ec02fSPetter Reinholdtsen 		lperror(LOG_ERR, "Could not enable event receiver");
121c18ec02fSPetter Reinholdtsen 		return -1;
122c18ec02fSPetter Reinholdtsen 	}
123c18ec02fSPetter Reinholdtsen 
124c18ec02fSPetter Reinholdtsen 	intf->opened = 1;
125c18ec02fSPetter Reinholdtsen 
126c18ec02fSPetter Reinholdtsen    /* This is never set to 0, the default is IPMI_BMC_SLAVE_ADDR */
127c18ec02fSPetter Reinholdtsen 	if (intf->my_addr != 0) {
128c18ec02fSPetter Reinholdtsen 		if (intf->set_my_addr(intf, intf->my_addr) < 0) {
129c18ec02fSPetter Reinholdtsen 			lperror(LOG_ERR, "Could not set IPMB address");
130c18ec02fSPetter Reinholdtsen 			return -1;
131c18ec02fSPetter Reinholdtsen 		}
132c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Set IPMB address to 0x%x",
133c18ec02fSPetter Reinholdtsen 			intf->my_addr );
134c18ec02fSPetter Reinholdtsen 	}
135c18ec02fSPetter Reinholdtsen 
136c18ec02fSPetter Reinholdtsen 	intf->manufacturer_id = ipmi_get_oem(intf);
137c18ec02fSPetter Reinholdtsen 	return intf->fd;
138c18ec02fSPetter Reinholdtsen }
139c18ec02fSPetter Reinholdtsen static int
ipmi_openipmi_set_my_addr(struct ipmi_intf * intf,uint8_t addr)140c18ec02fSPetter Reinholdtsen ipmi_openipmi_set_my_addr(struct ipmi_intf *intf, uint8_t addr)
141c18ec02fSPetter Reinholdtsen {
142c18ec02fSPetter Reinholdtsen 	unsigned int a = addr;
143c18ec02fSPetter Reinholdtsen 	if (ioctl(intf->fd, IPMICTL_SET_MY_ADDRESS_CMD, &a) < 0) {
144c18ec02fSPetter Reinholdtsen 		lperror(LOG_ERR, "Could not set IPMB address");
145c18ec02fSPetter Reinholdtsen 		return -1;
146c18ec02fSPetter Reinholdtsen 	}
147c18ec02fSPetter Reinholdtsen 	intf->my_addr = addr;
148c18ec02fSPetter Reinholdtsen 	return 0;
149c18ec02fSPetter Reinholdtsen }
150c18ec02fSPetter Reinholdtsen 
151c18ec02fSPetter Reinholdtsen static void
ipmi_openipmi_close(struct ipmi_intf * intf)152c18ec02fSPetter Reinholdtsen ipmi_openipmi_close(struct ipmi_intf * intf)
153c18ec02fSPetter Reinholdtsen {
154c18ec02fSPetter Reinholdtsen 	if (intf->fd >= 0) {
155c18ec02fSPetter Reinholdtsen 		close(intf->fd);
156c18ec02fSPetter Reinholdtsen 		intf->fd = -1;
157c18ec02fSPetter Reinholdtsen 	}
158c18ec02fSPetter Reinholdtsen 
159c18ec02fSPetter Reinholdtsen 	intf->opened = 0;
160c18ec02fSPetter Reinholdtsen 	intf->manufacturer_id = IPMI_OEM_UNKNOWN;
161c18ec02fSPetter Reinholdtsen }
162c18ec02fSPetter Reinholdtsen 
163c18ec02fSPetter Reinholdtsen static struct ipmi_rs *
ipmi_openipmi_send_cmd(struct ipmi_intf * intf,struct ipmi_rq * req)164c18ec02fSPetter Reinholdtsen ipmi_openipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
165c18ec02fSPetter Reinholdtsen {
166c18ec02fSPetter Reinholdtsen 	struct ipmi_recv recv;
167c18ec02fSPetter Reinholdtsen 	struct ipmi_addr addr;
168c18ec02fSPetter Reinholdtsen 	struct ipmi_system_interface_addr bmc_addr = {
169*70984dcaSZdenek Styblik 		.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
170*70984dcaSZdenek Styblik 		.channel = IPMI_BMC_CHANNEL,
171c18ec02fSPetter Reinholdtsen 	};
172c18ec02fSPetter Reinholdtsen 	struct ipmi_ipmb_addr ipmb_addr = {
173*70984dcaSZdenek Styblik 		.addr_type = IPMI_IPMB_ADDR_TYPE,
174c18ec02fSPetter Reinholdtsen 	};
175c18ec02fSPetter Reinholdtsen 	struct ipmi_req _req;
176c18ec02fSPetter Reinholdtsen 	static struct ipmi_rs rsp;
177c18ec02fSPetter Reinholdtsen 	static int curr_seq = 0;
178c18ec02fSPetter Reinholdtsen 	fd_set rset;
179c18ec02fSPetter Reinholdtsen 
180c18ec02fSPetter Reinholdtsen 	uint8_t * data = NULL;
181c18ec02fSPetter Reinholdtsen 	int data_len = 0;
182c18ec02fSPetter Reinholdtsen 
183c18ec02fSPetter Reinholdtsen 
184c18ec02fSPetter Reinholdtsen 	if (intf == NULL || req == NULL)
185c18ec02fSPetter Reinholdtsen 		return NULL;
186c18ec02fSPetter Reinholdtsen 
187c18ec02fSPetter Reinholdtsen 	ipmb_addr.channel = intf->target_channel & 0x0f;
188c18ec02fSPetter Reinholdtsen 
189c18ec02fSPetter Reinholdtsen 	if (intf->opened == 0 && intf->open != NULL)
190c18ec02fSPetter Reinholdtsen 		if (intf->open(intf) < 0)
191c18ec02fSPetter Reinholdtsen 			return NULL;
192c18ec02fSPetter Reinholdtsen 
193f49c9eecSParthasarathy Bhuvaragan 	if (verbose > 2) {
194f49c9eecSParthasarathy Bhuvaragan 		fprintf(stderr, "OpenIPMI Request Message Header:\n");
195f49c9eecSParthasarathy Bhuvaragan 		fprintf(stderr, "  netfn     = 0x%x\n",  req->msg.netfn );
196f49c9eecSParthasarathy Bhuvaragan 		fprintf(stderr, "  cmd       = 0x%x\n", req->msg.cmd);
197f49c9eecSParthasarathy Bhuvaragan 		printbuf(req->msg.data, req->msg.data_len, "OpenIPMI Request Message Data");
198f49c9eecSParthasarathy Bhuvaragan 	}
199f49c9eecSParthasarathy Bhuvaragan 
200f49c9eecSParthasarathy Bhuvaragan 
201c18ec02fSPetter Reinholdtsen 
202c18ec02fSPetter Reinholdtsen 	/*
203c18ec02fSPetter Reinholdtsen 	 * setup and send message
204c18ec02fSPetter Reinholdtsen 	 */
205c18ec02fSPetter Reinholdtsen 
206c18ec02fSPetter Reinholdtsen 	memset(&_req, 0, sizeof(struct ipmi_req));
207c18ec02fSPetter Reinholdtsen 
208c18ec02fSPetter Reinholdtsen 	if (intf->target_addr != 0 &&
209c18ec02fSPetter Reinholdtsen 	    intf->target_addr != intf->my_addr) {
210c18ec02fSPetter Reinholdtsen 		/* use IPMB address if needed */
211c18ec02fSPetter Reinholdtsen 		ipmb_addr.slave_addr = intf->target_addr;
212c18ec02fSPetter Reinholdtsen 		ipmb_addr.lun = req->msg.lun;
213c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Sending request 0x%x to "
214c18ec02fSPetter Reinholdtsen 			"IPMB target @ 0x%x:0x%x (from 0x%x)",
215c18ec02fSPetter Reinholdtsen 			req->msg.cmd,
216c18ec02fSPetter Reinholdtsen 			intf->target_addr,intf->target_channel, intf->my_addr);
217c18ec02fSPetter Reinholdtsen 
218c18ec02fSPetter Reinholdtsen 		if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) {
219c18ec02fSPetter Reinholdtsen 		   uint8_t index = 0;
220c18ec02fSPetter Reinholdtsen 
221c18ec02fSPetter Reinholdtsen 		   lprintf(LOG_DEBUG, "Encapsulating data sent to "
222c18ec02fSPetter Reinholdtsen 			   "end target [0x%02x,0x%02x] using transit [0x%02x,0x%02x] from 0x%x ",
223c18ec02fSPetter Reinholdtsen 			   (0x40 | intf->target_channel),
224c18ec02fSPetter Reinholdtsen 			   intf->target_addr,
225c18ec02fSPetter Reinholdtsen 			   intf->transit_channel,
226c18ec02fSPetter Reinholdtsen 			   intf->transit_addr,
227c18ec02fSPetter Reinholdtsen 			   intf->my_addr
228c18ec02fSPetter Reinholdtsen 			   );
229c18ec02fSPetter Reinholdtsen 
230c18ec02fSPetter Reinholdtsen 		   /* Convert Message to 'Send Message' */
231c18ec02fSPetter Reinholdtsen 		   /* Supplied req : req , internal req : _req  */
232c18ec02fSPetter Reinholdtsen 
233c18ec02fSPetter Reinholdtsen 		   if (verbose > 4) {
234c18ec02fSPetter Reinholdtsen 		      fprintf(stderr, "Converting message:\n");
235c18ec02fSPetter Reinholdtsen 		      fprintf(stderr, "  netfn     = 0x%x\n",  req->msg.netfn );
236c18ec02fSPetter Reinholdtsen 		      fprintf(stderr, "  cmd       = 0x%x\n", req->msg.cmd);
237a6f34c90SParthasarathy Bhuvaragan 		      if (req->msg.data && req->msg.data_len) {
238c18ec02fSPetter Reinholdtsen 			 fprintf(stderr, "  data_len  = %d\n", req->msg.data_len);
239c18ec02fSPetter Reinholdtsen 			 fprintf(stderr, "  data      = %s\n",
240c18ec02fSPetter Reinholdtsen 				 buf2str(req->msg.data,req->msg.data_len));
241c18ec02fSPetter Reinholdtsen 		      }
242c18ec02fSPetter Reinholdtsen 		   }
243c18ec02fSPetter Reinholdtsen 
244c18ec02fSPetter Reinholdtsen 		   /* Modify target address to use 'transit' instead */
245c18ec02fSPetter Reinholdtsen 		   ipmb_addr.slave_addr = intf->transit_addr;
246c18ec02fSPetter Reinholdtsen 		   ipmb_addr.channel    = intf->transit_channel;
247c18ec02fSPetter Reinholdtsen 
248c18ec02fSPetter Reinholdtsen 		   /* FIXME backup "My address" */
249c18ec02fSPetter Reinholdtsen 		   data_len = req->msg.data_len + 8;
250c18ec02fSPetter Reinholdtsen 		   data = malloc(data_len);
251c18ec02fSPetter Reinholdtsen 		   if (data == NULL) {
252c18ec02fSPetter Reinholdtsen 		      lprintf(LOG_ERR, "ipmitool: malloc failure");
253c18ec02fSPetter Reinholdtsen 		      return NULL;
254c18ec02fSPetter Reinholdtsen 		   }
255c18ec02fSPetter Reinholdtsen 
256c18ec02fSPetter Reinholdtsen 		   memset(data, 0, data_len);
257c18ec02fSPetter Reinholdtsen 
258c18ec02fSPetter Reinholdtsen 		   data[index++] = (0x40|intf->target_channel);
259c18ec02fSPetter Reinholdtsen 		   data[index++] = intf->target_addr;
260c18ec02fSPetter Reinholdtsen 		   data[index++] = (  req->msg.netfn << 2 ) |  req->msg.lun ;
261c18ec02fSPetter Reinholdtsen 		   data[index++] = ipmi_csum(data+1, 2);
262c18ec02fSPetter Reinholdtsen 		   data[index++] = 0xFF;    /* normally 0x20 , overwritten by IPMC  */
263c18ec02fSPetter Reinholdtsen 		   data[index++] = ( (0)  << 2) | 0 ;           /* FIXME */
264c18ec02fSPetter Reinholdtsen 		   data[index++] = req->msg.cmd;
265c18ec02fSPetter Reinholdtsen 		   memcpy( (data+index) , req->msg.data, req->msg.data_len);
266c18ec02fSPetter Reinholdtsen 		   index += req->msg.data_len;
267c18ec02fSPetter Reinholdtsen 		   data[index++] = ipmi_csum( (data+4),(req->msg.data_len + 3)  );
268c18ec02fSPetter Reinholdtsen 
269c18ec02fSPetter Reinholdtsen 		   if (verbose > 4) {
270c18ec02fSPetter Reinholdtsen 		      fprintf(stderr, "Encapsulated message:\n");
271c18ec02fSPetter Reinholdtsen 		      fprintf(stderr, "  netfn     = 0x%x\n", IPMI_NETFN_APP  );
272c18ec02fSPetter Reinholdtsen 		      fprintf(stderr, "  cmd       = 0x%x\n", 0x34 );
273c18ec02fSPetter Reinholdtsen 		      if (data && data_len) {
274c18ec02fSPetter Reinholdtsen 			 fprintf(stderr, "  data_len  = %d\n", data_len);
275c18ec02fSPetter Reinholdtsen 			 fprintf(stderr, "  data      = %s\n",
276c18ec02fSPetter Reinholdtsen 				 buf2str(data,data_len));
277c18ec02fSPetter Reinholdtsen 		      }
278c18ec02fSPetter Reinholdtsen 		   }
279c18ec02fSPetter Reinholdtsen 		}
280c18ec02fSPetter Reinholdtsen 		_req.addr = (unsigned char *) &ipmb_addr;
281c18ec02fSPetter Reinholdtsen 		_req.addr_len = sizeof(ipmb_addr);
282c18ec02fSPetter Reinholdtsen 	} else {
283c18ec02fSPetter Reinholdtsen 	   /* otherwise use system interface */
284c18ec02fSPetter Reinholdtsen 	   lprintf(LOG_DEBUG+2, "Sending request 0x%x to "
285c18ec02fSPetter Reinholdtsen 		   "System Interface", req->msg.cmd);
286c18ec02fSPetter Reinholdtsen 	   bmc_addr.lun = req->msg.lun;
287c18ec02fSPetter Reinholdtsen 	   _req.addr = (unsigned char *) &bmc_addr;
288c18ec02fSPetter Reinholdtsen 	   _req.addr_len = sizeof(bmc_addr);
289c18ec02fSPetter Reinholdtsen 	}
290c18ec02fSPetter Reinholdtsen 
291c18ec02fSPetter Reinholdtsen 	_req.msgid = curr_seq++;
292c18ec02fSPetter Reinholdtsen 
293c18ec02fSPetter Reinholdtsen 	/* In case of a bridge request */
294c18ec02fSPetter Reinholdtsen 	if( data != NULL && data_len != 0 ) {
295c18ec02fSPetter Reinholdtsen 	   _req.msg.data = data;
296c18ec02fSPetter Reinholdtsen 	   _req.msg.data_len = data_len;
297c18ec02fSPetter Reinholdtsen 	   _req.msg.netfn = IPMI_NETFN_APP;
298c18ec02fSPetter Reinholdtsen 	   _req.msg.cmd   = 0x34;
299c18ec02fSPetter Reinholdtsen 
300c18ec02fSPetter Reinholdtsen 	} else {
301c18ec02fSPetter Reinholdtsen 	   _req.msg.data = req->msg.data;
302c18ec02fSPetter Reinholdtsen 	   _req.msg.data_len = req->msg.data_len;
303c18ec02fSPetter Reinholdtsen 	   _req.msg.netfn = req->msg.netfn;
304c18ec02fSPetter Reinholdtsen 	   _req.msg.cmd = req->msg.cmd;
305c18ec02fSPetter Reinholdtsen 	}
306c18ec02fSPetter Reinholdtsen 
307c18ec02fSPetter Reinholdtsen 	if (ioctl(intf->fd, IPMICTL_SEND_COMMAND, &_req) < 0) {
308c18ec02fSPetter Reinholdtsen 	   lperror(LOG_ERR, "Unable to send command");
309c18ec02fSPetter Reinholdtsen 	   if (data != NULL) {
310c18ec02fSPetter Reinholdtsen 	      free(data);
311c18ec02fSPetter Reinholdtsen 				data = NULL;
312c18ec02fSPetter Reinholdtsen 		 }
313c18ec02fSPetter Reinholdtsen 	   return NULL;
314c18ec02fSPetter Reinholdtsen 	}
315c18ec02fSPetter Reinholdtsen 
316c18ec02fSPetter Reinholdtsen 	/*
317c18ec02fSPetter Reinholdtsen 	 * wait for and retrieve response
318c18ec02fSPetter Reinholdtsen 	 */
319c18ec02fSPetter Reinholdtsen 
320c18ec02fSPetter Reinholdtsen 	if (intf->noanswer) {
321c18ec02fSPetter Reinholdtsen 	   if (data != NULL) {
322c18ec02fSPetter Reinholdtsen 	      free(data);
323c18ec02fSPetter Reinholdtsen 				data = NULL;
324c18ec02fSPetter Reinholdtsen 		 }
325c18ec02fSPetter Reinholdtsen 	   return NULL;
326c18ec02fSPetter Reinholdtsen 	}
327c18ec02fSPetter Reinholdtsen 
328c18ec02fSPetter Reinholdtsen 	FD_ZERO(&rset);
329c18ec02fSPetter Reinholdtsen 	FD_SET(intf->fd, &rset);
330c18ec02fSPetter Reinholdtsen 
331c18ec02fSPetter Reinholdtsen 	if (select(intf->fd+1, &rset, NULL, NULL, NULL) < 0) {
332c18ec02fSPetter Reinholdtsen 	   lperror(LOG_ERR, "I/O Error");
333c18ec02fSPetter Reinholdtsen 	   if (data != NULL) {
334c18ec02fSPetter Reinholdtsen 	      free(data);
335c18ec02fSPetter Reinholdtsen 				data = NULL;
336c18ec02fSPetter Reinholdtsen 		 }
337c18ec02fSPetter Reinholdtsen 	   return NULL;
338c18ec02fSPetter Reinholdtsen 	}
339c18ec02fSPetter Reinholdtsen 	if (FD_ISSET(intf->fd, &rset) == 0) {
340c18ec02fSPetter Reinholdtsen 	   lprintf(LOG_ERR, "No data available");
341c18ec02fSPetter Reinholdtsen 	   if (data != NULL) {
342c18ec02fSPetter Reinholdtsen 	      free(data);
343c18ec02fSPetter Reinholdtsen 				data = NULL;
344c18ec02fSPetter Reinholdtsen 		 }
345c18ec02fSPetter Reinholdtsen 	   return NULL;
346c18ec02fSPetter Reinholdtsen 	}
347c18ec02fSPetter Reinholdtsen 
348c18ec02fSPetter Reinholdtsen 	recv.addr = (unsigned char *) &addr;
349c18ec02fSPetter Reinholdtsen 	recv.addr_len = sizeof(addr);
350c18ec02fSPetter Reinholdtsen 	recv.msg.data = rsp.data;
351c18ec02fSPetter Reinholdtsen 	recv.msg.data_len = sizeof(rsp.data);
352c18ec02fSPetter Reinholdtsen 
353c18ec02fSPetter Reinholdtsen 	/* get data */
354c18ec02fSPetter Reinholdtsen 	if (ioctl(intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) {
355c18ec02fSPetter Reinholdtsen 	   lperror(LOG_ERR, "Error receiving message");
356c18ec02fSPetter Reinholdtsen 	   if (errno != EMSGSIZE) {
357c18ec02fSPetter Reinholdtsen 	      if (data != NULL) {
358c18ec02fSPetter Reinholdtsen 					free(data);
359c18ec02fSPetter Reinholdtsen 					data = NULL;
360c18ec02fSPetter Reinholdtsen 				}
361c18ec02fSPetter Reinholdtsen 	      return NULL;
362c18ec02fSPetter Reinholdtsen 	   }
363c18ec02fSPetter Reinholdtsen 	}
364c18ec02fSPetter Reinholdtsen 
365c18ec02fSPetter Reinholdtsen 	if (verbose > 4) {
366c18ec02fSPetter Reinholdtsen 	   fprintf(stderr, "Got message:");
367c18ec02fSPetter Reinholdtsen 	   fprintf(stderr, "  type      = %d\n", recv.recv_type);
368c18ec02fSPetter Reinholdtsen 	   fprintf(stderr, "  channel   = 0x%x\n", addr.channel);
369c18ec02fSPetter Reinholdtsen 	   fprintf(stderr, "  msgid     = %ld\n", recv.msgid);
370c18ec02fSPetter Reinholdtsen 	   fprintf(stderr, "  netfn     = 0x%x\n", recv.msg.netfn);
371c18ec02fSPetter Reinholdtsen 	   fprintf(stderr, "  cmd       = 0x%x\n", recv.msg.cmd);
372c18ec02fSPetter Reinholdtsen 	   if (recv.msg.data && recv.msg.data_len) {
373c18ec02fSPetter Reinholdtsen 	      fprintf(stderr, "  data_len  = %d\n", recv.msg.data_len);
374c18ec02fSPetter Reinholdtsen 	      fprintf(stderr, "  data      = %s\n",
375c18ec02fSPetter Reinholdtsen 		      buf2str(recv.msg.data, recv.msg.data_len));
376c18ec02fSPetter Reinholdtsen 	   }
377c18ec02fSPetter Reinholdtsen 	}
378c18ec02fSPetter Reinholdtsen 
379c18ec02fSPetter Reinholdtsen 	if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) {
380c18ec02fSPetter Reinholdtsen 	   /* ipmb_addr.transit_slave_addr = intf->transit_addr; */
381c18ec02fSPetter Reinholdtsen 	   lprintf(LOG_DEBUG, "Decapsulating data received from transit "
382c18ec02fSPetter Reinholdtsen 		   "IPMB target @ 0x%x", intf->transit_addr);
383c18ec02fSPetter Reinholdtsen 
384c18ec02fSPetter Reinholdtsen 	   /* comp code */
385c18ec02fSPetter Reinholdtsen 	   /* Check data */
386c18ec02fSPetter Reinholdtsen 
387c18ec02fSPetter Reinholdtsen 	   if( recv.msg.data[0] == 0 ) {
388c18ec02fSPetter Reinholdtsen 	      recv.msg.netfn = recv.msg.data[2] >> 2;
389c18ec02fSPetter Reinholdtsen 	      recv.msg.cmd   = recv.msg.data[6];
390c18ec02fSPetter Reinholdtsen 
391c18ec02fSPetter Reinholdtsen 	      recv.msg.data = memmove(recv.msg.data ,recv.msg.data+7 , recv.msg.data_len - 7);
392c18ec02fSPetter Reinholdtsen 	      recv.msg.data_len -=8;
393c18ec02fSPetter Reinholdtsen 
394c18ec02fSPetter Reinholdtsen 	      if (verbose > 4) {
395c18ec02fSPetter Reinholdtsen 		 fprintf(stderr, "Decapsulated  message:\n");
396c18ec02fSPetter Reinholdtsen 		 fprintf(stderr, "  netfn     = 0x%x\n",   recv.msg.netfn );
397c18ec02fSPetter Reinholdtsen 		 fprintf(stderr, "  cmd       = 0x%x\n",  recv.msg.cmd);
398c18ec02fSPetter Reinholdtsen 		 if (recv.msg.data && recv.msg.data_len) {
399c18ec02fSPetter Reinholdtsen 		    fprintf(stderr, "  data_len  = %d\n",  recv.msg.data_len);
400c18ec02fSPetter Reinholdtsen 		    fprintf(stderr, "  data      = %s\n",
401c18ec02fSPetter Reinholdtsen 			    buf2str(recv.msg.data,recv.msg.data_len));
402c18ec02fSPetter Reinholdtsen 		 }
403c18ec02fSPetter Reinholdtsen 	      }
404c18ec02fSPetter Reinholdtsen 	   }
405c18ec02fSPetter Reinholdtsen 	}
406c18ec02fSPetter Reinholdtsen 
407c18ec02fSPetter Reinholdtsen 	/* save completion code */
408c18ec02fSPetter Reinholdtsen 	rsp.ccode = recv.msg.data[0];
409c18ec02fSPetter Reinholdtsen 	rsp.data_len = recv.msg.data_len - 1;
410c18ec02fSPetter Reinholdtsen 
411c18ec02fSPetter Reinholdtsen 	/* save response data for caller */
412c18ec02fSPetter Reinholdtsen 	if (rsp.ccode == 0 && rsp.data_len > 0) {
413c18ec02fSPetter Reinholdtsen 	   memmove(rsp.data, rsp.data + 1, rsp.data_len);
4142c7a5f91SZdenek Styblik 	   rsp.data[rsp.data_len] = 0;
415c18ec02fSPetter Reinholdtsen 	}
416c18ec02fSPetter Reinholdtsen 
417c18ec02fSPetter Reinholdtsen 	if (data != NULL) {
418c18ec02fSPetter Reinholdtsen 	   free(data);
419c18ec02fSPetter Reinholdtsen 		 data = NULL;
420c18ec02fSPetter Reinholdtsen 	}
421c18ec02fSPetter Reinholdtsen 
422c18ec02fSPetter Reinholdtsen 	return &rsp;
423c18ec02fSPetter Reinholdtsen }
424c18ec02fSPetter Reinholdtsen 
ipmi_openipmi_setup(struct ipmi_intf * intf)42523e9340bSZdenek Styblik int ipmi_openipmi_setup(struct ipmi_intf * intf)
42623e9340bSZdenek Styblik {
42723e9340bSZdenek Styblik 	/* set default payload size */
42823e9340bSZdenek Styblik 	intf->max_request_data_size = IPMI_OPENIPMI_MAX_RQ_DATA_SIZE;
42923e9340bSZdenek Styblik 	intf->max_response_data_size = IPMI_OPENIPMI_MAX_RS_DATA_SIZE;
43023e9340bSZdenek Styblik 
43123e9340bSZdenek Styblik 	return 0;
43223e9340bSZdenek Styblik }
43323e9340bSZdenek Styblik 
434c18ec02fSPetter Reinholdtsen struct ipmi_intf ipmi_open_intf = {
435*70984dcaSZdenek Styblik 	.name = "open",
436*70984dcaSZdenek Styblik 	.desc = "Linux OpenIPMI Interface",
437*70984dcaSZdenek Styblik 	.setup = ipmi_openipmi_setup,
438*70984dcaSZdenek Styblik 	.open = ipmi_openipmi_open,
439*70984dcaSZdenek Styblik 	.close = ipmi_openipmi_close,
440*70984dcaSZdenek Styblik 	.sendrecv = ipmi_openipmi_send_cmd,
441*70984dcaSZdenek Styblik 	.set_my_addr = ipmi_openipmi_set_my_addr,
442*70984dcaSZdenek Styblik 	.my_addr = IPMI_BMC_SLAVE_ADDR,
443*70984dcaSZdenek Styblik 	.target_addr = 0, /* init so -m local_addr does not cause bridging */
444c18ec02fSPetter Reinholdtsen };
445