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