xref: /openbmc/ipmitool/lib/ipmi_raw.c (revision 169d9ac3)
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  */
32c18ec02fSPetter Reinholdtsen 
33c18ec02fSPetter Reinholdtsen #include <string.h>
34c18ec02fSPetter Reinholdtsen #include <stdlib.h>
35c18ec02fSPetter Reinholdtsen #include <stdio.h>
36c18ec02fSPetter Reinholdtsen 
37c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h>
38c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h>
39c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h>
40c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h>
41c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_raw.h>
42c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h>
43c18ec02fSPetter Reinholdtsen 
44c18ec02fSPetter Reinholdtsen #define IPMI_I2C_MASTER_MAX_SIZE	0x40 /* 64 bytes */
45c18ec02fSPetter Reinholdtsen 
46c18ec02fSPetter Reinholdtsen static int is_valid_param(const char *input_param, uint8_t *uchr_ptr,
47c18ec02fSPetter Reinholdtsen 		const char *label);
48*70099a3cSPat Donlin int ipmi_spd_print(uint8_t *, int);
49c18ec02fSPetter Reinholdtsen 
50c18ec02fSPetter Reinholdtsen /* ipmi_master_write_read  -  Perform I2C write/read transactions
51c18ec02fSPetter Reinholdtsen  *
52c18ec02fSPetter Reinholdtsen  * This function performs an I2C master write-read function through
53c18ec02fSPetter Reinholdtsen  * IPMI interface.  It has a maximum transfer size of 32 bytes.
54c18ec02fSPetter Reinholdtsen  *
55c18ec02fSPetter Reinholdtsen  * @intf:	ipmi interface
56c18ec02fSPetter Reinholdtsen  * @bus:	channel number, i2c bus id and type
57c18ec02fSPetter Reinholdtsen  * @addr:	i2c slave address
58c18ec02fSPetter Reinholdtsen  * @wdata:	data to write
59c18ec02fSPetter Reinholdtsen  * @wsize:	length of data to write (max 64 bytes)
60c18ec02fSPetter Reinholdtsen  * @rsize:	length of data to read (max 64 bytes)
61c18ec02fSPetter Reinholdtsen  *
62c18ec02fSPetter Reinholdtsen  * Returns pointer to IPMI Response
63c18ec02fSPetter Reinholdtsen  */
64c18ec02fSPetter Reinholdtsen struct ipmi_rs *
ipmi_master_write_read(struct ipmi_intf * intf,uint8_t bus,uint8_t addr,uint8_t * wdata,uint8_t wsize,uint8_t rsize)65c18ec02fSPetter Reinholdtsen ipmi_master_write_read(struct ipmi_intf * intf, uint8_t bus, uint8_t addr,
66c18ec02fSPetter Reinholdtsen 		       uint8_t * wdata, uint8_t wsize, uint8_t rsize)
67c18ec02fSPetter Reinholdtsen {
68c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
69c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
70c18ec02fSPetter Reinholdtsen 	uint8_t rqdata[IPMI_I2C_MASTER_MAX_SIZE + 3];
71c18ec02fSPetter Reinholdtsen 
72c18ec02fSPetter Reinholdtsen 	if (rsize > IPMI_I2C_MASTER_MAX_SIZE) {
73c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Master Write-Read: Too many bytes (%d) to read", rsize);
74c18ec02fSPetter Reinholdtsen 		return NULL;
75c18ec02fSPetter Reinholdtsen 	}
76c18ec02fSPetter Reinholdtsen 	if (wsize > IPMI_I2C_MASTER_MAX_SIZE) {
77c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Master Write-Read: Too many bytes (%d) to write", wsize);
78c18ec02fSPetter Reinholdtsen 		return NULL;
79c18ec02fSPetter Reinholdtsen 	}
80c18ec02fSPetter Reinholdtsen 
81c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(struct ipmi_rq));
82c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_APP;
83c18ec02fSPetter Reinholdtsen 	req.msg.cmd = 0x52;	/* master write-read */
84c18ec02fSPetter Reinholdtsen 	req.msg.data = rqdata;
85c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 3;
86c18ec02fSPetter Reinholdtsen 
87c18ec02fSPetter Reinholdtsen 	memset(rqdata, 0, IPMI_I2C_MASTER_MAX_SIZE + 3);
88c18ec02fSPetter Reinholdtsen 	rqdata[0] = bus;	/* channel number, bus id, bus type */
89c18ec02fSPetter Reinholdtsen 	rqdata[1] = addr;	/* slave address */
90c18ec02fSPetter Reinholdtsen 	rqdata[2] = rsize;      /* number of bytes to read */
91c18ec02fSPetter Reinholdtsen 
92c18ec02fSPetter Reinholdtsen 	if (wsize > 0) {
93c18ec02fSPetter Reinholdtsen 		/* copy in data to write */
94c18ec02fSPetter Reinholdtsen 		memcpy(rqdata+3, wdata, wsize);
95c18ec02fSPetter Reinholdtsen 		req.msg.data_len += wsize;
96c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Writing %d bytes to i2cdev %02Xh", wsize, addr);
97c18ec02fSPetter Reinholdtsen 	}
98c18ec02fSPetter Reinholdtsen 
99c18ec02fSPetter Reinholdtsen 	if (rsize > 0) {
100c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Reading %d bytes from i2cdev %02Xh", rsize, addr);
101c18ec02fSPetter Reinholdtsen 	}
102c18ec02fSPetter Reinholdtsen 
103c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
104c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
105c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "I2C Master Write-Read command failed");
106c18ec02fSPetter Reinholdtsen 		return NULL;
107c18ec02fSPetter Reinholdtsen 	}
108c18ec02fSPetter Reinholdtsen 	else if (rsp->ccode > 0) {
109c18ec02fSPetter Reinholdtsen 		switch (rsp->ccode) {
110c18ec02fSPetter Reinholdtsen 		case 0x81:
111c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: Lost Arbitration");
112c18ec02fSPetter Reinholdtsen 			break;
113c18ec02fSPetter Reinholdtsen 		case 0x82:
114c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: Bus Error");
115c18ec02fSPetter Reinholdtsen 			break;
116c18ec02fSPetter Reinholdtsen 		case 0x83:
117c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: NAK on Write");
118c18ec02fSPetter Reinholdtsen 			break;
119c18ec02fSPetter Reinholdtsen 		case 0x84:
120c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: Truncated Read");
121c18ec02fSPetter Reinholdtsen 			break;
122c18ec02fSPetter Reinholdtsen 		default:
123c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: %s",
124c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
125c18ec02fSPetter Reinholdtsen 			break;
126c18ec02fSPetter Reinholdtsen 		}
127c18ec02fSPetter Reinholdtsen 		return NULL;
128c18ec02fSPetter Reinholdtsen 	}
129c18ec02fSPetter Reinholdtsen 
130c18ec02fSPetter Reinholdtsen 	return rsp;
131c18ec02fSPetter Reinholdtsen }
132c18ec02fSPetter Reinholdtsen 
1330ff2d6e4SZdenek Styblik #define RAW_SPD_SIZE	512
134c18ec02fSPetter Reinholdtsen 
135c18ec02fSPetter Reinholdtsen int
ipmi_rawspd_main(struct ipmi_intf * intf,int argc,char ** argv)136c18ec02fSPetter Reinholdtsen ipmi_rawspd_main(struct ipmi_intf * intf, int argc, char ** argv)
137c18ec02fSPetter Reinholdtsen {
138c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
139c18ec02fSPetter Reinholdtsen 	uint8_t msize = IPMI_I2C_MASTER_MAX_SIZE; /* allow to override default */
140c18ec02fSPetter Reinholdtsen 	uint8_t channel = 0;
141c18ec02fSPetter Reinholdtsen 	uint8_t i2cbus = 0;
142c18ec02fSPetter Reinholdtsen 	uint8_t i2caddr = 0;
143c18ec02fSPetter Reinholdtsen 	uint8_t spd_data[RAW_SPD_SIZE];
144c18ec02fSPetter Reinholdtsen 	int i;
145c18ec02fSPetter Reinholdtsen 
146c18ec02fSPetter Reinholdtsen 	memset(spd_data, 0, RAW_SPD_SIZE);
147c18ec02fSPetter Reinholdtsen 
148c18ec02fSPetter Reinholdtsen 	if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
149c18ec02fSPetter Reinholdtsen 		lprintf(LOG_NOTICE, "usage: spd <i2cbus> <i2caddr> [channel] [maxread]");
150c18ec02fSPetter Reinholdtsen 		return 0;
151c18ec02fSPetter Reinholdtsen 	}
152c18ec02fSPetter Reinholdtsen 
153c18ec02fSPetter Reinholdtsen 	if (is_valid_param(argv[0], &i2cbus, "i2cbus") != 0)
154c18ec02fSPetter Reinholdtsen 		return (-1);
155c18ec02fSPetter Reinholdtsen 
156c18ec02fSPetter Reinholdtsen 	if (is_valid_param(argv[1], &i2caddr, "i2caddr") != 0)
157c18ec02fSPetter Reinholdtsen 		return (-1);
158c18ec02fSPetter Reinholdtsen 
159c18ec02fSPetter Reinholdtsen 	if (argc >= 3) {
160c18ec02fSPetter Reinholdtsen 		if (is_valid_param(argv[2], &channel, "channel") != 0)
161c18ec02fSPetter Reinholdtsen 			return (-1);
162c18ec02fSPetter Reinholdtsen 	}
163c18ec02fSPetter Reinholdtsen 
164c18ec02fSPetter Reinholdtsen 	if (argc >= 4) {
165c18ec02fSPetter Reinholdtsen 		if (is_valid_param(argv[3], &msize, "maxread") != 0)
166c18ec02fSPetter Reinholdtsen 			return (-1);
167c18ec02fSPetter Reinholdtsen 	}
168c18ec02fSPetter Reinholdtsen 
169c18ec02fSPetter Reinholdtsen 	i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | 1;
170c18ec02fSPetter Reinholdtsen 
171c18ec02fSPetter Reinholdtsen 	for (i = 0; i < RAW_SPD_SIZE; i+= msize) {
172c18ec02fSPetter Reinholdtsen 		rsp = ipmi_master_write_read(intf, i2cbus, i2caddr,
173c18ec02fSPetter Reinholdtsen 					     (uint8_t *)&i, 1, msize );
174c18ec02fSPetter Reinholdtsen 		if (rsp == NULL) {
175c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
176c18ec02fSPetter Reinholdtsen 			return -1;
177c18ec02fSPetter Reinholdtsen 		}
178c18ec02fSPetter Reinholdtsen 
179c18ec02fSPetter Reinholdtsen 		memcpy(spd_data+i, rsp->data, msize);
180c18ec02fSPetter Reinholdtsen 	}
181c18ec02fSPetter Reinholdtsen 
182c18ec02fSPetter Reinholdtsen 	ipmi_spd_print(spd_data, i);
183c18ec02fSPetter Reinholdtsen 	return 0;
184c18ec02fSPetter Reinholdtsen }
185c18ec02fSPetter Reinholdtsen 
rawi2c_usage(void)186c18ec02fSPetter Reinholdtsen static void rawi2c_usage(void)
187c18ec02fSPetter Reinholdtsen {
188c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "usage: i2c [bus=public|# [chan=#] <i2caddr> <read bytes> [write data]");
189c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "            bus=public is default");
190c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "            chan=0 is default, bus= must be specified to use chan=");
191c18ec02fSPetter Reinholdtsen }
192c18ec02fSPetter Reinholdtsen 
193c18ec02fSPetter Reinholdtsen int
ipmi_rawi2c_main(struct ipmi_intf * intf,int argc,char ** argv)194c18ec02fSPetter Reinholdtsen ipmi_rawi2c_main(struct ipmi_intf * intf, int argc, char ** argv)
195c18ec02fSPetter Reinholdtsen {
196c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
197c18ec02fSPetter Reinholdtsen 	uint8_t wdata[IPMI_I2C_MASTER_MAX_SIZE];
198c18ec02fSPetter Reinholdtsen 	uint8_t i2caddr = 0;
199c18ec02fSPetter Reinholdtsen 	uint8_t rsize = 0;
200c18ec02fSPetter Reinholdtsen 	uint8_t wsize = 0;
201c18ec02fSPetter Reinholdtsen 	unsigned int rbus = 0;
202c18ec02fSPetter Reinholdtsen 	uint8_t bus = 0;
203c18ec02fSPetter Reinholdtsen 	int i = 0;
204c18ec02fSPetter Reinholdtsen 
205c18ec02fSPetter Reinholdtsen 	/* handle bus= argument */
206c18ec02fSPetter Reinholdtsen 	if (argc > 2 && strncmp(argv[0], "bus=", 4) == 0) {
207c18ec02fSPetter Reinholdtsen 		i = 1;
208c18ec02fSPetter Reinholdtsen 		if (strncmp(argv[0], "bus=public", 10) == 0)
209c18ec02fSPetter Reinholdtsen 			bus = 0;
210c18ec02fSPetter Reinholdtsen 		else if (sscanf(argv[0], "bus=%u", &rbus) == 1)
211c18ec02fSPetter Reinholdtsen 			bus = ((rbus & 7) << 1) | 1;
212c18ec02fSPetter Reinholdtsen 		else
213c18ec02fSPetter Reinholdtsen 			bus = 0;
214c18ec02fSPetter Reinholdtsen 
215c18ec02fSPetter Reinholdtsen 		/* handle channel= argument
216c18ec02fSPetter Reinholdtsen 		 * the bus= argument must be supplied first on command line */
217c18ec02fSPetter Reinholdtsen 		if (argc > 3 && strncmp(argv[1], "chan=", 5) == 0) {
218c18ec02fSPetter Reinholdtsen 			i = 2;
219c18ec02fSPetter Reinholdtsen 			if (sscanf(argv[1], "chan=%u", &rbus) == 1)
220c18ec02fSPetter Reinholdtsen 				bus |= rbus << 4;
221c18ec02fSPetter Reinholdtsen 		}
222c18ec02fSPetter Reinholdtsen 	}
223c18ec02fSPetter Reinholdtsen 
224c18ec02fSPetter Reinholdtsen 	if ((argc-i) < 2 || strncmp(argv[0], "help", 4) == 0) {
225c18ec02fSPetter Reinholdtsen 		rawi2c_usage();
226c18ec02fSPetter Reinholdtsen 		return 0;
227c18ec02fSPetter Reinholdtsen 	}
228c18ec02fSPetter Reinholdtsen 	else if (argc-i-2 > IPMI_I2C_MASTER_MAX_SIZE) {
229c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Raw command input limit (%d bytes) exceeded",
230c18ec02fSPetter Reinholdtsen 			IPMI_I2C_MASTER_MAX_SIZE);
231c18ec02fSPetter Reinholdtsen 		return -1;
232c18ec02fSPetter Reinholdtsen 	}
233c18ec02fSPetter Reinholdtsen 
234c18ec02fSPetter Reinholdtsen 	if (is_valid_param(argv[i++], &i2caddr, "i2caddr") != 0)
235c18ec02fSPetter Reinholdtsen 		return (-1);
236c18ec02fSPetter Reinholdtsen 
237c18ec02fSPetter Reinholdtsen 	if (is_valid_param(argv[i++], &rsize, "read size") != 0)
238c18ec02fSPetter Reinholdtsen 		return (-1);
239c18ec02fSPetter Reinholdtsen 
240c18ec02fSPetter Reinholdtsen 	if (i2caddr == 0) {
241c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Invalid I2C address 0");
242c18ec02fSPetter Reinholdtsen 		rawi2c_usage();
243c18ec02fSPetter Reinholdtsen 		return -1;
244c18ec02fSPetter Reinholdtsen 	}
245c18ec02fSPetter Reinholdtsen 
246c18ec02fSPetter Reinholdtsen 	memset(wdata, 0, IPMI_I2C_MASTER_MAX_SIZE);
247c18ec02fSPetter Reinholdtsen 	for (; i < argc; i++) {
248c18ec02fSPetter Reinholdtsen 		uint8_t val = 0;
249c18ec02fSPetter Reinholdtsen 
250c18ec02fSPetter Reinholdtsen 		if (is_valid_param(argv[i], &val, "parameter") != 0)
251c18ec02fSPetter Reinholdtsen 			return (-1);
252c18ec02fSPetter Reinholdtsen 
253c18ec02fSPetter Reinholdtsen 		wdata[wsize] = val;
254c18ec02fSPetter Reinholdtsen 		wsize++;
255c18ec02fSPetter Reinholdtsen 	}
256c18ec02fSPetter Reinholdtsen 
257c18ec02fSPetter Reinholdtsen 	lprintf(LOG_INFO, "RAW I2C REQ (i2caddr=%x readbytes=%d writebytes=%d)",
258c18ec02fSPetter Reinholdtsen 		i2caddr, rsize, wsize);
259c18ec02fSPetter Reinholdtsen 	printbuf(wdata, wsize, "WRITE DATA");
260c18ec02fSPetter Reinholdtsen 
261c18ec02fSPetter Reinholdtsen 	rsp = ipmi_master_write_read(intf, bus, i2caddr, wdata, wsize, rsize);
262c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
263c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
264c18ec02fSPetter Reinholdtsen 		return -1;
265c18ec02fSPetter Reinholdtsen 	}
266c18ec02fSPetter Reinholdtsen 
267c18ec02fSPetter Reinholdtsen 	if (wsize > 0) {
268c18ec02fSPetter Reinholdtsen 		if (verbose || rsize == 0)
269c18ec02fSPetter Reinholdtsen 			printf("Wrote %d bytes to I2C device %02Xh\n", wsize, i2caddr);
270c18ec02fSPetter Reinholdtsen 	}
271c18ec02fSPetter Reinholdtsen 
272c18ec02fSPetter Reinholdtsen 	if (rsize > 0) {
273c18ec02fSPetter Reinholdtsen 		if (verbose || wsize == 0)
274c18ec02fSPetter Reinholdtsen 			printf("Read %d bytes from I2C device %02Xh\n", rsp->data_len, i2caddr);
275c18ec02fSPetter Reinholdtsen 
276c18ec02fSPetter Reinholdtsen 		if (rsp->data_len < rsize)
277c18ec02fSPetter Reinholdtsen 			return -1;
278c18ec02fSPetter Reinholdtsen 
279c18ec02fSPetter Reinholdtsen 		/* print the raw response buffer */
280c18ec02fSPetter Reinholdtsen 		for (i=0; i<rsp->data_len; i++) {
281c18ec02fSPetter Reinholdtsen 			if (((i%16) == 0) && (i != 0))
282c18ec02fSPetter Reinholdtsen 				printf("\n");
283c18ec02fSPetter Reinholdtsen 			printf(" %2.2x", rsp->data[i]);
284c18ec02fSPetter Reinholdtsen 		}
285c18ec02fSPetter Reinholdtsen 		printf("\n");
286c18ec02fSPetter Reinholdtsen 
287c18ec02fSPetter Reinholdtsen 		if (rsp->data_len <= 4) {
288c18ec02fSPetter Reinholdtsen 			uint32_t bit;
289c18ec02fSPetter Reinholdtsen 			int j;
290c18ec02fSPetter Reinholdtsen 			for (i = 0; i < rsp->data_len; i++) {
291c18ec02fSPetter Reinholdtsen 				for (j = 1, bit = 0x80; bit > 0; bit /= 2, j++) {
292c18ec02fSPetter Reinholdtsen 					printf("%s", (rsp->data[i] & bit) ? "1" : "0");
293c18ec02fSPetter Reinholdtsen 				}
294c18ec02fSPetter Reinholdtsen 				printf(" ");
295c18ec02fSPetter Reinholdtsen 			}
296c18ec02fSPetter Reinholdtsen 			printf("\n");
297c18ec02fSPetter Reinholdtsen 		}
298c18ec02fSPetter Reinholdtsen 	}
299c18ec02fSPetter Reinholdtsen 
300c18ec02fSPetter Reinholdtsen 	return 0;
301c18ec02fSPetter Reinholdtsen }
302c18ec02fSPetter Reinholdtsen 
303c18ec02fSPetter Reinholdtsen /* ipmi_raw_help() - print 'raw' help text
304c18ec02fSPetter Reinholdtsen  *
305c18ec02fSPetter Reinholdtsen  * returns void
306c18ec02fSPetter Reinholdtsen  */
307c18ec02fSPetter Reinholdtsen void
ipmi_raw_help()308c18ec02fSPetter Reinholdtsen ipmi_raw_help()
309c18ec02fSPetter Reinholdtsen {
310c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "RAW Commands:  raw <netfn> <cmd> [data]");
311c18ec02fSPetter Reinholdtsen 	print_valstr(ipmi_netfn_vals, "Network Function Codes", LOG_NOTICE);
312c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "(can also use raw hex values)");
313c18ec02fSPetter Reinholdtsen } /* ipmi_raw_help() */
314c18ec02fSPetter Reinholdtsen 
315c18ec02fSPetter Reinholdtsen int
ipmi_raw_main(struct ipmi_intf * intf,int argc,char ** argv)316c18ec02fSPetter Reinholdtsen ipmi_raw_main(struct ipmi_intf * intf, int argc, char ** argv)
317c18ec02fSPetter Reinholdtsen {
318c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
319c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
320c18ec02fSPetter Reinholdtsen 	uint8_t netfn, cmd, lun;
321c18ec02fSPetter Reinholdtsen 	uint16_t netfn_tmp = 0;
322c18ec02fSPetter Reinholdtsen 	int i;
323c18ec02fSPetter Reinholdtsen 	uint8_t data[256];
324c18ec02fSPetter Reinholdtsen 
325c18ec02fSPetter Reinholdtsen 	if (argc == 1 && strncmp(argv[0], "help", 4) == 0) {
326c18ec02fSPetter Reinholdtsen 		ipmi_raw_help();
327c18ec02fSPetter Reinholdtsen 		return 0;
328c18ec02fSPetter Reinholdtsen 	}
329c18ec02fSPetter Reinholdtsen 	else if (argc < 2) {
330c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Not enough parameters given.");
331c18ec02fSPetter Reinholdtsen 		ipmi_raw_help();
332c18ec02fSPetter Reinholdtsen 		return (-1);
333c18ec02fSPetter Reinholdtsen 	}
334c18ec02fSPetter Reinholdtsen 	else if (argc > sizeof(data))
335c18ec02fSPetter Reinholdtsen 	{
336c18ec02fSPetter Reinholdtsen 		lprintf(LOG_NOTICE, "Raw command input limit (256 bytes) exceeded");
337c18ec02fSPetter Reinholdtsen 		return -1;
338c18ec02fSPetter Reinholdtsen 	}
339c18ec02fSPetter Reinholdtsen 
340c18ec02fSPetter Reinholdtsen 	lun = intf->target_lun;
341c18ec02fSPetter Reinholdtsen 	netfn_tmp = str2val(argv[0], ipmi_netfn_vals);
342c18ec02fSPetter Reinholdtsen 	if (netfn_tmp == 0xff) {
343c18ec02fSPetter Reinholdtsen 		if (is_valid_param(argv[0], &netfn, "netfn") != 0)
344c18ec02fSPetter Reinholdtsen 			return (-1);
345c18ec02fSPetter Reinholdtsen 	} else {
346c18ec02fSPetter Reinholdtsen 		if (netfn_tmp >= UINT8_MAX) {
347c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Given netfn \"%s\" is out of range.", argv[0]);
348c18ec02fSPetter Reinholdtsen 			return (-1);
349c18ec02fSPetter Reinholdtsen 		}
350c18ec02fSPetter Reinholdtsen 		netfn = netfn_tmp;
351c18ec02fSPetter Reinholdtsen 	}
352c18ec02fSPetter Reinholdtsen 
353c18ec02fSPetter Reinholdtsen 	if (is_valid_param(argv[1], &cmd, "command") != 0)
354c18ec02fSPetter Reinholdtsen 		return (-1);
355c18ec02fSPetter Reinholdtsen 
356c18ec02fSPetter Reinholdtsen 	memset(data, 0, sizeof(data));
357c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
358c18ec02fSPetter Reinholdtsen 	req.msg.netfn = netfn;
359c18ec02fSPetter Reinholdtsen 	req.msg.lun = lun;
360c18ec02fSPetter Reinholdtsen 	req.msg.cmd = cmd;
361c18ec02fSPetter Reinholdtsen 	req.msg.data = data;
362c18ec02fSPetter Reinholdtsen 
363c18ec02fSPetter Reinholdtsen 	for (i=2; i<argc; i++) {
364c18ec02fSPetter Reinholdtsen 		uint8_t val = 0;
365c18ec02fSPetter Reinholdtsen 
366c18ec02fSPetter Reinholdtsen 		if (is_valid_param(argv[i], &val, "data") != 0)
367c18ec02fSPetter Reinholdtsen 			return (-1);
368c18ec02fSPetter Reinholdtsen 
369c18ec02fSPetter Reinholdtsen 		req.msg.data[i-2] = val;
370c18ec02fSPetter Reinholdtsen 		req.msg.data_len++;
371c18ec02fSPetter Reinholdtsen 	}
372c18ec02fSPetter Reinholdtsen 
373c18ec02fSPetter Reinholdtsen 	lprintf(LOG_INFO,
374c18ec02fSPetter Reinholdtsen            "RAW REQ (channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x data_len=%d)",
375c18ec02fSPetter Reinholdtsen            intf->target_channel & 0x0f, req.msg.netfn,req.msg.lun ,
376c18ec02fSPetter Reinholdtsen            req.msg.cmd, req.msg.data_len);
377c18ec02fSPetter Reinholdtsen 
378c18ec02fSPetter Reinholdtsen 	printbuf(req.msg.data, req.msg.data_len, "RAW REQUEST");
379c18ec02fSPetter Reinholdtsen 
380c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
381c18ec02fSPetter Reinholdtsen 
382c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
383c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Unable to send RAW command "
384c18ec02fSPetter Reinholdtsen 			"(channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x)",
385c18ec02fSPetter Reinholdtsen 			intf->target_channel & 0x0f, req.msg.netfn, req.msg.lun, req.msg.cmd);
386c18ec02fSPetter Reinholdtsen 		return -1;
387c18ec02fSPetter Reinholdtsen 	}
388c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
389c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Unable to send RAW command "
390c18ec02fSPetter Reinholdtsen 			"(channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x rsp=0x%x): %s",
391c18ec02fSPetter Reinholdtsen 			intf->target_channel & 0x0f, req.msg.netfn, req.msg.lun, req.msg.cmd, rsp->ccode,
392c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
393c18ec02fSPetter Reinholdtsen 		return -1;
394c18ec02fSPetter Reinholdtsen 	}
395c18ec02fSPetter Reinholdtsen 
396c18ec02fSPetter Reinholdtsen 	lprintf(LOG_INFO, "RAW RSP (%d bytes)", rsp->data_len);
397c18ec02fSPetter Reinholdtsen 
398c18ec02fSPetter Reinholdtsen 	/* print the raw response buffer */
399c18ec02fSPetter Reinholdtsen 	for (i=0; i<rsp->data_len; i++) {
400c18ec02fSPetter Reinholdtsen 		if (((i%16) == 0) && (i != 0))
401c18ec02fSPetter Reinholdtsen 			printf("\n");
402c18ec02fSPetter Reinholdtsen 		printf(" %2.2x", rsp->data[i]);
403c18ec02fSPetter Reinholdtsen 	}
404c18ec02fSPetter Reinholdtsen 	printf("\n");
405c18ec02fSPetter Reinholdtsen 
406c18ec02fSPetter Reinholdtsen 	return 0;
407c18ec02fSPetter Reinholdtsen }
408c18ec02fSPetter Reinholdtsen 
409c18ec02fSPetter Reinholdtsen /* is_valid_param -
410c18ec02fSPetter Reinholdtsen  *
411c18ec02fSPetter Reinholdtsen  * @input_param: string to convert from
412c18ec02fSPetter Reinholdtsen  * @uchr_ptr: pointer where to store converted value
413c18ec02fSPetter Reinholdtsen  * @label: string used in error message
414c18ec02fSPetter Reinholdtsen  *
415c18ec02fSPetter Reinholdtsen  * returns   0  if parameter is valid
416c18ec02fSPetter Reinholdtsen  * returns (-1) if parameter is invalid/on error
417c18ec02fSPetter Reinholdtsen  */
418c18ec02fSPetter Reinholdtsen int
is_valid_param(const char * input_param,uint8_t * uchr_ptr,const char * label)419c18ec02fSPetter Reinholdtsen is_valid_param(const char *input_param, uint8_t *uchr_ptr, const char *label) {
420c18ec02fSPetter Reinholdtsen 	if (input_param == NULL || label == NULL) {
421c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERROR, "ERROR: NULL pointer passed.");
422c18ec02fSPetter Reinholdtsen 		return (-1);
423c18ec02fSPetter Reinholdtsen 	}
424c18ec02fSPetter Reinholdtsen 	if (str2uchar(input_param, uchr_ptr) == 0)
425c18ec02fSPetter Reinholdtsen 		return 0;
426c18ec02fSPetter Reinholdtsen 
427c18ec02fSPetter Reinholdtsen 	lprintf(LOG_ERR, "Given %s \"%s\" is invalid.", label, input_param);
428c18ec02fSPetter Reinholdtsen 	return (-1);
429c18ec02fSPetter Reinholdtsen }
430