xref: /openbmc/ipmitool/lib/ipmi_raw.c (revision 531569ec)
1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 
37 #include <ipmitool/ipmi.h>
38 #include <ipmitool/log.h>
39 #include <ipmitool/helper.h>
40 #include <ipmitool/ipmi_intf.h>
41 #include <ipmitool/ipmi_raw.h>
42 #include <ipmitool/ipmi_fru.h>
43 #include <ipmitool/ipmi_strings.h>
44 
45 #define IPMI_I2C_MASTER_MAX_SIZE	0x40 /* 64 bytes */
46 
47 static int is_valid_param(const char *input_param, uint8_t *uchr_ptr,
48 		const char *label);
49 
50 /* ipmi_master_write_read  -  Perform I2C write/read transactions
51  *
52  * This function performs an I2C master write-read function through
53  * IPMI interface.  It has a maximum transfer size of 32 bytes.
54  *
55  * @intf:	ipmi interface
56  * @bus:	channel number, i2c bus id and type
57  * @addr:	i2c slave address
58  * @wdata:	data to write
59  * @wsize:	length of data to write (max 64 bytes)
60  * @rsize:	length of data to read (max 64 bytes)
61  *
62  * Returns pointer to IPMI Response
63  */
64 struct ipmi_rs *
65 ipmi_master_write_read(struct ipmi_intf * intf, uint8_t bus, uint8_t addr,
66 		       uint8_t * wdata, uint8_t wsize, uint8_t rsize)
67 {
68 	struct ipmi_rq req;
69 	struct ipmi_rs * rsp;
70 	uint8_t rqdata[IPMI_I2C_MASTER_MAX_SIZE + 3];
71 
72 	if (rsize > IPMI_I2C_MASTER_MAX_SIZE) {
73 		lprintf(LOG_ERR, "Master Write-Read: Too many bytes (%d) to read", rsize);
74 		return NULL;
75 	}
76 	if (wsize > IPMI_I2C_MASTER_MAX_SIZE) {
77 		lprintf(LOG_ERR, "Master Write-Read: Too many bytes (%d) to write", wsize);
78 		return NULL;
79 	}
80 
81 	memset(&req, 0, sizeof(struct ipmi_rq));
82 	req.msg.netfn = IPMI_NETFN_APP;
83 	req.msg.cmd = 0x52;	/* master write-read */
84 	req.msg.data = rqdata;
85 	req.msg.data_len = 3;
86 
87 	memset(rqdata, 0, IPMI_I2C_MASTER_MAX_SIZE + 3);
88 	rqdata[0] = bus;	/* channel number, bus id, bus type */
89 	rqdata[1] = addr;	/* slave address */
90 	rqdata[2] = rsize;      /* number of bytes to read */
91 
92 	if (wsize > 0) {
93 		/* copy in data to write */
94 		memcpy(rqdata+3, wdata, wsize);
95 		req.msg.data_len += wsize;
96 		lprintf(LOG_DEBUG, "Writing %d bytes to i2cdev %02Xh", wsize, addr);
97 	}
98 
99 	if (rsize > 0) {
100 		lprintf(LOG_DEBUG, "Reading %d bytes from i2cdev %02Xh", rsize, addr);
101 	}
102 
103 	rsp = intf->sendrecv(intf, &req);
104 	if (rsp == NULL) {
105 		lprintf(LOG_ERR, "I2C Master Write-Read command failed");
106 		return NULL;
107 	}
108 	else if (rsp->ccode > 0) {
109 		switch (rsp->ccode) {
110 		case 0x81:
111 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: Lost Arbitration");
112 			break;
113 		case 0x82:
114 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: Bus Error");
115 			break;
116 		case 0x83:
117 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: NAK on Write");
118 			break;
119 		case 0x84:
120 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: Truncated Read");
121 			break;
122 		default:
123 			lprintf(LOG_ERR, "I2C Master Write-Read command failed: %s",
124 				val2str(rsp->ccode, completion_code_vals));
125 			break;
126 		}
127 		return NULL;
128 	}
129 
130 	return rsp;
131 }
132 
133 #define RAW_SPD_SIZE	512
134 
135 int
136 ipmi_rawspd_main(struct ipmi_intf * intf, int argc, char ** argv)
137 {
138 	struct ipmi_rs *rsp;
139 	uint8_t msize = IPMI_I2C_MASTER_MAX_SIZE; /* allow to override default */
140 	uint8_t channel = 0;
141 	uint8_t i2cbus = 0;
142 	uint8_t i2caddr = 0;
143 	uint8_t spd_data[RAW_SPD_SIZE];
144 	int i;
145 
146 	memset(spd_data, 0, RAW_SPD_SIZE);
147 
148 	if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
149 		lprintf(LOG_NOTICE, "usage: spd <i2cbus> <i2caddr> [channel] [maxread]");
150 		return 0;
151 	}
152 
153 	if (is_valid_param(argv[0], &i2cbus, "i2cbus") != 0)
154 		return (-1);
155 
156 	if (is_valid_param(argv[1], &i2caddr, "i2caddr") != 0)
157 		return (-1);
158 
159 	if (argc >= 3) {
160 		if (is_valid_param(argv[2], &channel, "channel") != 0)
161 			return (-1);
162 	}
163 
164 	if (argc >= 4) {
165 		if (is_valid_param(argv[3], &msize, "maxread") != 0)
166 			return (-1);
167 	}
168 
169 	i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | 1;
170 
171 	for (i = 0; i < RAW_SPD_SIZE; i+= msize) {
172 		rsp = ipmi_master_write_read(intf, i2cbus, i2caddr,
173 					     (uint8_t *)&i, 1, msize );
174 		if (rsp == NULL) {
175 			lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
176 			return -1;
177 		}
178 
179 		memcpy(spd_data+i, rsp->data, msize);
180 	}
181 
182 	ipmi_spd_print(spd_data, i);
183 	return 0;
184 }
185 
186 static void rawi2c_usage(void)
187 {
188 	lprintf(LOG_NOTICE, "usage: i2c [bus=public|# [chan=#] <i2caddr> <read bytes> [write data]");
189 	lprintf(LOG_NOTICE, "            bus=public is default");
190 	lprintf(LOG_NOTICE, "            chan=0 is default, bus= must be specified to use chan=");
191 }
192 
193 int
194 ipmi_rawi2c_main(struct ipmi_intf * intf, int argc, char ** argv)
195 {
196 	struct ipmi_rs * rsp;
197 	uint8_t wdata[IPMI_I2C_MASTER_MAX_SIZE];
198 	uint8_t i2caddr = 0;
199 	uint8_t rsize = 0;
200 	uint8_t wsize = 0;
201 	unsigned int rbus = 0;
202 	uint8_t bus = 0;
203 	int i = 0;
204 
205 	/* handle bus= argument */
206 	if (argc > 2 && strncmp(argv[0], "bus=", 4) == 0) {
207 		i = 1;
208 		if (strncmp(argv[0], "bus=public", 10) == 0)
209 			bus = 0;
210 		else if (sscanf(argv[0], "bus=%u", &rbus) == 1)
211 			bus = ((rbus & 7) << 1) | 1;
212 		else
213 			bus = 0;
214 
215 		/* handle channel= argument
216 		 * the bus= argument must be supplied first on command line */
217 		if (argc > 3 && strncmp(argv[1], "chan=", 5) == 0) {
218 			i = 2;
219 			if (sscanf(argv[1], "chan=%u", &rbus) == 1)
220 				bus |= rbus << 4;
221 		}
222 	}
223 
224 	if ((argc-i) < 2 || strncmp(argv[0], "help", 4) == 0) {
225 		rawi2c_usage();
226 		return 0;
227 	}
228 	else if (argc-i-2 > IPMI_I2C_MASTER_MAX_SIZE) {
229 		lprintf(LOG_ERR, "Raw command input limit (%d bytes) exceeded",
230 			IPMI_I2C_MASTER_MAX_SIZE);
231 		return -1;
232 	}
233 
234 	if (is_valid_param(argv[i++], &i2caddr, "i2caddr") != 0)
235 		return (-1);
236 
237 	if (is_valid_param(argv[i++], &rsize, "read size") != 0)
238 		return (-1);
239 
240 	if (i2caddr == 0) {
241 		lprintf(LOG_ERR, "Invalid I2C address 0");
242 		rawi2c_usage();
243 		return -1;
244 	}
245 
246 	memset(wdata, 0, IPMI_I2C_MASTER_MAX_SIZE);
247 	for (; i < argc; i++) {
248 		uint8_t val = 0;
249 
250 		if (is_valid_param(argv[i], &val, "parameter") != 0)
251 			return (-1);
252 
253 		wdata[wsize] = val;
254 		wsize++;
255 	}
256 
257 	lprintf(LOG_INFO, "RAW I2C REQ (i2caddr=%x readbytes=%d writebytes=%d)",
258 		i2caddr, rsize, wsize);
259 	printbuf(wdata, wsize, "WRITE DATA");
260 
261 	rsp = ipmi_master_write_read(intf, bus, i2caddr, wdata, wsize, rsize);
262 	if (rsp == NULL) {
263 		lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
264 		return -1;
265 	}
266 
267 	if (wsize > 0) {
268 		if (verbose || rsize == 0)
269 			printf("Wrote %d bytes to I2C device %02Xh\n", wsize, i2caddr);
270 	}
271 
272 	if (rsize > 0) {
273 		if (verbose || wsize == 0)
274 			printf("Read %d bytes from I2C device %02Xh\n", rsp->data_len, i2caddr);
275 
276 		if (rsp->data_len < rsize)
277 			return -1;
278 
279 		/* print the raw response buffer */
280 		for (i=0; i<rsp->data_len; i++) {
281 			if (((i%16) == 0) && (i != 0))
282 				printf("\n");
283 			printf(" %2.2x", rsp->data[i]);
284 		}
285 		printf("\n");
286 
287 		if (rsp->data_len <= 4) {
288 			uint32_t bit;
289 			int j;
290 			for (i = 0; i < rsp->data_len; i++) {
291 				for (j = 1, bit = 0x80; bit > 0; bit /= 2, j++) {
292 					printf("%s", (rsp->data[i] & bit) ? "1" : "0");
293 				}
294 				printf(" ");
295 			}
296 			printf("\n");
297 		}
298 	}
299 
300 	return 0;
301 }
302 
303 /* ipmi_raw_help() - print 'raw' help text
304  *
305  * returns void
306  */
307 void
308 ipmi_raw_help()
309 {
310 	lprintf(LOG_NOTICE, "RAW Commands:  raw <netfn> <cmd> [data]");
311 	print_valstr(ipmi_netfn_vals, "Network Function Codes", LOG_NOTICE);
312 	lprintf(LOG_NOTICE, "(can also use raw hex values)");
313 } /* ipmi_raw_help() */
314 
315 int
316 ipmi_raw_main(struct ipmi_intf * intf, int argc, char ** argv)
317 {
318 	struct ipmi_rs * rsp;
319 	struct ipmi_rq req;
320 	uint8_t netfn, cmd, lun;
321 	uint16_t netfn_tmp = 0;
322 	int i;
323 	uint8_t data[256];
324 
325 	if (argc == 1 && strncmp(argv[0], "help", 4) == 0) {
326 		ipmi_raw_help();
327 		return 0;
328 	}
329 	else if (argc < 2) {
330 		lprintf(LOG_ERR, "Not enough parameters given.");
331 		ipmi_raw_help();
332 		return (-1);
333 	}
334 	else if (argc > sizeof(data))
335 	{
336 		lprintf(LOG_NOTICE, "Raw command input limit (256 bytes) exceeded");
337 		return -1;
338 	}
339 
340 	ipmi_intf_session_set_timeout(intf, 15);
341 	ipmi_intf_session_set_retry(intf, 1);
342 
343 	lun = intf->target_lun;
344 	netfn_tmp = str2val(argv[0], ipmi_netfn_vals);
345 	if (netfn_tmp == 0xff) {
346 		if (is_valid_param(argv[0], &netfn, "netfn") != 0)
347 			return (-1);
348 	} else {
349 		if (netfn_tmp >= UINT8_MAX) {
350 			lprintf(LOG_ERR, "Given netfn \"%s\" is out of range.", argv[0]);
351 			return (-1);
352 		}
353 		netfn = netfn_tmp;
354 	}
355 
356 	if (is_valid_param(argv[1], &cmd, "command") != 0)
357 		return (-1);
358 
359 	memset(data, 0, sizeof(data));
360 	memset(&req, 0, sizeof(req));
361 	req.msg.netfn = netfn;
362 	req.msg.lun = lun;
363 	req.msg.cmd = cmd;
364 	req.msg.data = data;
365 
366 	for (i=2; i<argc; i++) {
367 		uint8_t val = 0;
368 
369 		if (is_valid_param(argv[i], &val, "data") != 0)
370 			return (-1);
371 
372 		req.msg.data[i-2] = val;
373 		req.msg.data_len++;
374 	}
375 
376 	lprintf(LOG_INFO,
377            "RAW REQ (channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x data_len=%d)",
378            intf->target_channel & 0x0f, req.msg.netfn,req.msg.lun ,
379            req.msg.cmd, req.msg.data_len);
380 
381 	printbuf(req.msg.data, req.msg.data_len, "RAW REQUEST");
382 
383 	rsp = intf->sendrecv(intf, &req);
384 
385 	if (rsp == NULL) {
386 		lprintf(LOG_ERR, "Unable to send RAW command "
387 			"(channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x)",
388 			intf->target_channel & 0x0f, req.msg.netfn, req.msg.lun, req.msg.cmd);
389 		return -1;
390 	}
391 	if (rsp->ccode > 0) {
392 		lprintf(LOG_ERR, "Unable to send RAW command "
393 			"(channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x rsp=0x%x): %s",
394 			intf->target_channel & 0x0f, req.msg.netfn, req.msg.lun, req.msg.cmd, rsp->ccode,
395 			val2str(rsp->ccode, completion_code_vals));
396 		return -1;
397 	}
398 
399 	lprintf(LOG_INFO, "RAW RSP (%d bytes)", rsp->data_len);
400 
401 	/* print the raw response buffer */
402 	for (i=0; i<rsp->data_len; i++) {
403 		if (((i%16) == 0) && (i != 0))
404 			printf("\n");
405 		printf(" %2.2x", rsp->data[i]);
406 	}
407 	printf("\n");
408 
409 	return 0;
410 }
411 
412 /* is_valid_param -
413  *
414  * @input_param: string to convert from
415  * @uchr_ptr: pointer where to store converted value
416  * @label: string used in error message
417  *
418  * returns   0  if parameter is valid
419  * returns (-1) if parameter is invalid/on error
420  */
421 int
422 is_valid_param(const char *input_param, uint8_t *uchr_ptr, const char *label) {
423 	if (input_param == NULL || label == NULL) {
424 		lprintf(LOG_ERROR, "ERROR: NULL pointer passed.");
425 		return (-1);
426 	}
427 	if (str2uchar(input_param, uchr_ptr) == 0)
428 		return 0;
429 
430 	lprintf(LOG_ERR, "Given %s \"%s\" is invalid.", label, input_param);
431 	return (-1);
432 }
433