1 /* 2 * Copyright (C) 2008 Intel Corporation. 3 * All rights reserved 4 * 5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 6 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 7 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 8 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 9 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 10 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 11 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 12 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 13 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 14 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 15 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 * 17 */ 18 19 /* Theory of operation 20 * 21 * DCMI is the Data Center Management Interface which is a subset of IPMI v2.0. 22 * DCMI incorporates the ability to locate a system with DCMI functionality, 23 * its available temperature sensors, and power limiting control. 24 * 25 * All of the available DCMI commands are contained in a struct with a numeric 26 * value and a string. When the user specifies a command the string is 27 * compared to one of several structs and is then given a numeric value based 28 * on the matched string. A case statement is used to select the desired 29 * action from the user. If an invalid string is entered, or a string that is 30 * not a command option is entered, the available commands are printed to the 31 * screen. This allows the strings to be changed quickly with the DCMI spec. 32 * 33 * Each called function usually executes whichever command was requested to 34 * keep the main() from being overly complicated. 35 * 36 * This code conforms to the 1.0 DCMI Specification 37 * released by Hari Ramachandran of the Intel Corporation 38 */ 39 40 #include <stdlib.h> 41 #include <string.h> 42 #include <stdio.h> 43 #include <math.h> 44 #include <unistd.h> 45 #include <sys/types.h> 46 #include <time.h> 47 #include <netdb.h> 48 49 #include <ipmitool/ipmi_dcmi.h> 50 #include <ipmitool/helper.h> 51 #include <ipmitool/ipmi.h> 52 #include <ipmitool/log.h> 53 #include <ipmitool/ipmi_intf.h> 54 #include <ipmitool/ipmi_strings.h> 55 #include <ipmitool/ipmi_mc.h> 56 #include <ipmitool/ipmi_entity.h> 57 #include <ipmitool/ipmi_constants.h> 58 #include <ipmitool/ipmi_sensor.h> 59 60 #include "../src/plugins/lanplus/lanplus.h" 61 62 #define IPMI_LAN_PORT 0x26f 63 64 extern int verbose; 65 66 static int ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id); 67 68 /******************************************************************************* 69 * The structs below are the DCMI command option strings. They are printed * 70 * when the user does not issue enough options or the wrong ones. The reason * 71 * that the DMCI command strings are in a struct is so that when the * 72 * specification changes, the strings can be changed quickly with out having * 73 * to change a lot of the code in the main(). * 74 ******************************************************************************/ 75 76 /* Main set of DCMI commands */ 77 const struct dcmi_cmd dcmi_cmd_vals[] = { 78 { 0x00, "discover", " Used to discover supported DCMI capabilities" }, 79 { 0x01, "power", " Platform power limit command options" }, 80 { 0x02, "sensors", " Prints the available DCMI sensors" }, 81 { 0x03, "asset_tag", " Prints the platform's asset tag" }, 82 { 0x04, "set_asset_tag", " Sets the platform's asset tag" }, 83 { 0x05, "get_mc_id_string", " Get management controller ID string" }, 84 { 0x06, "set_mc_id_string", " Set management controller ID string" }, 85 { 0x07, "thermalpolicy", " Thermal policy get/set" }, 86 { 0x08, "get_temp_reading", " Get Temperature Readings" }, 87 { 0x09, "get_conf_param", " Get DCMI Config Parameters" }, 88 { 0x0A, "set_conf_param", " Set DCMI Config Parameters" }, 89 { 0x0B, "oob_discover", " Ping/Pong Message for DCMI Discovery" }, 90 { 0xFF, NULL, NULL } 91 }; 92 93 /* get capabilites */ 94 const struct dcmi_cmd dcmi_capable_vals[] = { 95 { 0x01, "platform", " Lists the system capabilities" }, 96 { 0x02, "mandatory_attributes", "Lists SEL, identification and" 97 "temperature attributes" }, 98 { 0x03, "optional_attributes", " Lists power capabilities" }, 99 { 0x04, "managebility access", " Lists OOB channel information" }, 100 { 0xFF, NULL, NULL } 101 }; 102 103 /* platform capabilities 104 * Since they are actually in two bytes, we need three structs to make this 105 * human readable... 106 */ 107 const struct dcmi_cmd dcmi_mandatory_platform_capabilities[] = { 108 { 0x01, "Identification support available", "" }, 109 { 0x02, "SEL logging available", "" }, 110 { 0x03, "Chassis power available", "" }, 111 { 0x04, "Temperature monitor available", "" }, 112 { 0xFF, NULL, NULL } 113 }; 114 115 /* optional capabilities */ 116 const struct dcmi_cmd dcmi_optional_platform_capabilities[] = { 117 { 0x01, "Power management available", "" }, 118 { 0xFF, NULL, NULL } 119 }; 120 121 /* access capabilties */ 122 const struct dcmi_cmd dcmi_management_access_capabilities[] = { 123 { 0x01, "In-band KCS channel available", "" }, 124 { 0x02, "Out-of-band serial TMODE available", "" }, 125 { 0x03, "Out-of-band secondary LAN channel available", "" }, 126 { 0x04, "Out-of-band primary LAN channel available", "" }, 127 { 0x05, "SOL enabled", "" }, 128 { 0x06, "VLAN capable", "" }, 129 { 0xFF, NULL, NULL } 130 }; 131 132 /* identification capabilities */ 133 const struct dcmi_cmd dcmi_id_capabilities_vals[] = { 134 { 0x01, "GUID", "" }, 135 { 0x02, "DHCP hostname", "" }, 136 { 0x03, "Asset tag", "" }, 137 { 0xFF, NULL, NULL } 138 }; 139 140 /* Configuration parameters*/ 141 const struct dcmi_cmd dcmi_conf_param_vals[] = { 142 { 0x01, "activate_dhcp", "\tActivate DHCP"}, 143 { 0x02, "dhcp_config", "\tDHCP Configuration" }, 144 { 0x03, "init", "\t\tInitial timeout interval" }, 145 { 0x04, "timeout", "\t\tServer contact timeout interval" }, 146 { 0x05, "retry", "\t\tServer contact retry interval" }, 147 { 0xFF, NULL, NULL } 148 }; 149 150 151 /* temperature monitoring capabilities */ 152 const struct dcmi_cmd dcmi_temp_monitoring_vals[] = { 153 { 0x01, "inlet", " Inlet air temperature sensors" }, 154 { 0x02, "cpu", " CPU temperature sensors" }, 155 { 0x03, "baseboard", "Baseboard temperature sensors" }, 156 { 0xff, NULL, NULL } 157 }; 158 159 /* These are not comands. These are the DCMI temp sensors and their numbers 160 * If new sensors are added, they need to be added to this list with their 161 * sensor number 162 */ 163 const struct dcmi_cmd dcmi_discvry_snsr_vals[] = { 164 { 0x40, "Inlet", " Inlet air temperature sensors" }, 165 { 0x41, "CPU", " CPU temperature sensors" }, 166 { 0x42, "Baseboard", "Baseboard temperature sensors" }, 167 { 0xff, NULL, NULL } 168 }; 169 170 /* Temperature Readings */ 171 const struct dcmi_cmd dcmi_temp_read_vals[] = { 172 { 0x40, "Inlet", "Inlet air temperature(40h) " }, 173 { 0x41, "CPU", "CPU temperature sensors(41h) " }, 174 { 0x42, "Baseboard", "Baseboard temperature sensors(42h) " }, 175 { 0xff, NULL, NULL } 176 }; 177 178 /* power management/control commands */ 179 const struct dcmi_cmd dcmi_pwrmgmt_vals[] = { 180 { 0x00, "reading", " Get power related readings from the system" }, 181 { 0x01, "get_limit", " Get the configured power limits" }, 182 { 0x02, "set_limit", " Set a power limit option" }, 183 { 0x03, "activate", " Activate the set power limit" }, 184 { 0x04, "deactivate", "Deactivate the set power limit" }, 185 { 0xFF, NULL, NULL } 186 }; 187 188 /* set power limit commands */ 189 const struct dcmi_cmd dcmi_pwrmgmt_set_usage_vals[] = { 190 { 0x00, "action", " <no_action | sel_logging | power_off>" }, 191 { 0x01, "limit", " <number in Watts>" }, 192 { 0x02, "correction", "<number in milliseconds>" }, 193 { 0x03, "sample", " <number in seconds>" }, 194 { 0xFF, NULL, NULL } 195 }; 196 197 /* power management/get action commands */ 198 const struct dcmi_cmd dcmi_pwrmgmt_get_action_vals[] = { 199 { 0x00, "No Action", ""}, 200 { 0x01, "Hard Power Off & Log Event to SEL", ""}, 201 202 { 0x02, "OEM reserved (02h)", ""}, 203 { 0x03, "OEM reserved (03h)", ""}, 204 { 0x04, "OEM reserved (04h)", ""}, 205 { 0x05, "OEM reserved (05h)", ""}, 206 { 0x06, "OEM reserved (06h)", ""}, 207 { 0x07, "OEM reserved (07h)", ""}, 208 { 0x08, "OEM reserved (08h)", ""}, 209 { 0x09, "OEM reserved (09h)", ""}, 210 { 0x0a, "OEM reserved (0ah)", ""}, 211 { 0x0b, "OEM reserved (0bh)", ""}, 212 { 0x0c, "OEM reserved (0ch)", ""}, 213 { 0x0d, "OEM reserved (0dh)", ""}, 214 { 0x0e, "OEM reserved (0eh)", ""}, 215 { 0x0f, "OEM reserved (0fh)", ""}, 216 { 0x10, "OEM reserved (10h)", ""}, 217 218 { 0x11, "Log Event to SEL", ""}, 219 { 0xFF, NULL, NULL } 220 }; 221 222 /* power management/set action commands */ 223 const struct dcmi_cmd dcmi_pwrmgmt_action_vals[] = { 224 { 0x00, "no_action", "No Action"}, 225 { 0x01, "power_off", "Hard Power Off & Log Event to SEL"}, 226 { 0x11, "sel_logging", "Log Event to SEL"}, 227 228 { 0x02, "oem_02", "OEM reserved (02h)"}, 229 { 0x03, "oem_03", "OEM reserved (03h)"}, 230 { 0x04, "oem_04", "OEM reserved (04h)"}, 231 { 0x05, "oem_05", "OEM reserved (05h)"}, 232 { 0x06, "oem_06", "OEM reserved (06h)"}, 233 { 0x07, "oem_07", "OEM reserved (07h)"}, 234 { 0x08, "oem_08", "OEM reserved (08h)"}, 235 { 0x09, "oem_09", "OEM reserved (09h)"}, 236 { 0x0a, "oem_0a", "OEM reserved (0ah)"}, 237 { 0x0b, "oem_0b", "OEM reserved (0bh)"}, 238 { 0x0c, "oem_0c", "OEM reserved (0ch)"}, 239 { 0x0d, "oem_0d", "OEM reserved (0dh)"}, 240 { 0x0e, "oem_0e", "OEM reserved (0eh)"}, 241 { 0x0f, "oem_0f", "OEM reserved (0fh)"}, 242 { 0x10, "oem_10", "OEM reserved (10h)"}, 243 244 { 0xFF, NULL, NULL } 245 }; 246 247 /* thermal policy action commands */ 248 const struct dcmi_cmd dcmi_thermalpolicy_vals[] = { 249 { 0x00, "get", "Get thermal policy" }, 250 { 0x01, "set", "Set thermal policy" }, 251 { 0xFF, NULL, NULL } 252 }; 253 254 /* thermal policy action commands */ 255 const struct dcmi_cmd dcmi_confparameters_vals[] = { 256 { 0x00, "get", "Get configuration parameters" }, 257 { 0x01, "set", "Set configuration parameters" }, 258 { 0xFF, NULL, NULL } 259 }; 260 261 /* entityIDs used in thermap policy */ 262 const struct dcmi_cmd dcmi_thermalpolicy_set_parameters_vals[] = { 263 { 0x00, "volatile", " Current Power Cycle" }, 264 { 0x01, "nonvolatile", "Set across power cycles" }, 265 { 0x01, "poweroff", " Hard Power Off system" }, 266 { 0x00, "nopoweroff", " No 'Hard Power Off' action" }, 267 { 0x01, "sel", " Log event to SEL" }, 268 { 0x00, "nosel", " No 'Log event to SEL' action" }, 269 { 0x00, "disabled", " Disabled" }, 270 { 0x00, NULL, NULL } 271 }; 272 273 274 /* DCMI command specific completion code results per 1.0 spec 275 * 80h - parameter not supported. 276 * 81h - attempt to set the ‘set in progress’ value (in parameter #0) when not 277 * in the ‘set complete’ state. (This completion code provides a way to 278 * recognize that another party has already ‘claimed’ the parameters) 279 * 82h - attempt to write read-only parameter 280 * 82h - set not supported on selected channel (e.g. channel is session-less.) 281 * 83h - access mode not supported 282 * 84h – Power Limit out of range 283 * 85h – Correction Time out of range 284 * 89h – Statistics Reporting Period out of range 285 */ 286 const struct valstr dcmi_ccode_vals[] = { 287 { 0x80, "Parameter not supported" }, 288 { 0x81, "Something else has already claimed these parameters" }, 289 { 0x82, "Not supported or failed to write a read-only parameter" }, 290 { 0x83, "Access mode is not supported" }, 291 { 0x84, "Power/Thermal limit out of range" }, 292 { 0x85, "Correction/Exception time out of range" }, 293 { 0x89, "Sample/Statistics Reporting period out of range" }, 294 { 0x8A, "Power limit already active" }, 295 { 0xFF, NULL } 296 }; 297 298 /* End strings */ 299 300 /* This was taken from print_valstr() from helper.c. It serves the same 301 * purpose but with out the extra formatting. This function simply prints 302 * the dcmi_cmd struct provided. verthorz specifies to print vertically or 303 * horizontally. If the string is printed horizontally then a | will be 304 * printed between each instance of vs[i].str until it is NULL 305 * 306 * @vs: value string list to print 307 * @title: name of this value string list 308 * @loglevel: what log level to print, -1 for stdout 309 * @verthorz: printed vertically or horizontally, 0 or 1 310 */ 311 void 312 print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel, 313 int verthorz) 314 { 315 int i; 316 317 if (vs == NULL) 318 return; 319 320 if (title != NULL) { 321 if (loglevel < 0) 322 printf("\n%s\n", title); 323 else 324 lprintf(loglevel, "\n%s", title); 325 } 326 for (i = 0; vs[i].str != NULL; i++) { 327 if (loglevel < 0) { 328 if (vs[i].val < 256) 329 if (verthorz == 0) 330 printf(" %s %s\n", vs[i].str, vs[i].desc); 331 else 332 printf("%s", vs[i].str); 333 else if (verthorz == 0) 334 printf(" %s %s\n", vs[i].str, vs[i].desc); 335 else 336 printf("%s", vs[i].str); 337 } else { 338 if (vs[i].val < 256) 339 lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc); 340 else 341 lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc); 342 } 343 /* Check to see if this is NOT the last element in vs.str if true 344 * print the | else don't print anything. 345 */ 346 if ((verthorz == 1) && (vs[i+1].str != NULL)) 347 printf(" | "); 348 } 349 if (verthorz == 0) { 350 if (loglevel < 0) { 351 printf("\n"); 352 } else { 353 lprintf(loglevel, ""); 354 } 355 } 356 } 357 358 /* This was taken from str2val() from helper.c. It serves the same 359 * purpose but with the addition of a desc field from the structure. 360 * This function converts the str from the dcmi_cmd struct provided to the 361 * value associated to the compared string in the struct. 362 * 363 * @str: string to compare against 364 * @vs: dcmi_cmd structure 365 */ 366 uint16_t 367 str2val2(const char *str, const struct dcmi_cmd *vs) 368 { 369 int i; 370 if (vs == NULL || str == NULL) { 371 return 0; 372 } 373 for (i = 0; vs[i].str != NULL; i++) { 374 if (strncasecmp(vs[i].str, str, 375 __maxlen(str, vs[i].str)) == 0) { 376 return vs[i].val; 377 } 378 } 379 return vs[i].val; 380 } 381 382 /* This was taken from val2str() from helper.c. It serves the same 383 * purpose but with the addition of a desc field from the structure. 384 * This function converts the val and returns a string from the dcmi_cmd 385 * struct provided in the struct. 386 * 387 * @val: value to compare against 388 * @vs: dcmi_cmd structure 389 */ 390 const char * 391 val2str2(uint16_t val, const struct dcmi_cmd *vs) 392 { 393 static char un_str[32]; 394 int i; 395 396 if (vs == NULL) 397 return NULL; 398 399 for (i = 0; vs[i].str != NULL; i++) { 400 if (vs[i].val == val) 401 return vs[i].str; 402 } 403 memset(un_str, 0, 32); 404 snprintf(un_str, 32, "Unknown (0x%x)", val); 405 return un_str; 406 } 407 408 /* check the DCMI response from the BMC 409 * @rsp: Response data structure 410 */ 411 static int 412 chk_rsp(struct ipmi_rs * rsp) 413 { 414 /* if the response from the intf is NULL then the BMC is experiencing 415 * some issue and cannot complete the command 416 */ 417 if (rsp == NULL) { 418 lprintf(LOG_ERR, "\n Unable to get DCMI information"); 419 return 1; 420 } 421 /* if the completion code is greater than zero there was an error. We'll 422 * use val2str from helper.c to print the error from either the DCMI 423 * completion code struct or the generic IPMI completion_code_vals struct 424 */ 425 if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) { 426 lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)", 427 val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode); 428 return 1; 429 } else if (rsp->ccode > 0) { 430 lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)", 431 val2str(rsp->ccode, completion_code_vals), rsp->ccode); 432 return 1; 433 } 434 /* check to make sure this is a DCMI firmware */ 435 if(rsp->data[0] != IPMI_DCMI) { 436 printf("\n A valid DCMI command was not returned! (%x)", rsp->data[0]); 437 return 1; 438 } 439 return 0; 440 } 441 442 /* Get capabilities ipmi response 443 * 444 * This function returns the available capabilities of the platform. 445 * The reason it returns in the rsp struct is so that it can be used for other 446 * purposes. 447 * 448 * returns ipmi response structure 449 * 450 * @intf: ipmi interface handler 451 * @selector: Parameter selector 452 */ 453 struct ipmi_rs * 454 ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector) 455 { 456 struct ipmi_rq req; /* request data to send to the BMC */ 457 uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */ 458 459 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 460 msg_data[1] = selector; 461 462 memset(&req, 0, sizeof(req)); 463 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */ 464 req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */ 465 req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */ 466 req.msg.data_len = 2; /* How many times does req.msg.data need to read */ 467 468 return intf->sendrecv(intf, &req); 469 } 470 /* end capabilities struct */ 471 472 /* Displays capabilities from structure 473 * returns void 474 * 475 * @cmd: dcmi_cmd structure 476 * @data_val: holds value of what to display 477 */ 478 void 479 display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val) 480 { 481 uint8_t i; 482 for (i = 0x01; cmd[i-1].val != 0xFF; i++) { 483 if (data_val & (1<<(i-1))) { 484 printf(" %s\n", val2str2(i, cmd)); 485 } 486 } 487 } 488 489 static int 490 ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf) 491 { 492 # ifndef IPMI_INTF_LANPLUS 493 lprintf(LOG_ERR, 494 "DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled."); 495 return (-1); 496 # else 497 int rc; 498 struct ipmi_session *s; 499 500 if (intf->opened == 0 && intf->open != NULL) { 501 if (intf->open(intf) < 0) 502 return (-1); 503 } 504 if (intf == NULL || intf->session == NULL) 505 return -1; 506 507 s = intf->session; 508 509 if (s->port == 0) 510 s->port = IPMI_LAN_PORT; 511 if (s->privlvl == 0) 512 s->privlvl = IPMI_SESSION_PRIV_ADMIN; 513 if (s->timeout == 0) 514 s->timeout = IPMI_LAN_TIMEOUT; 515 if (s->retry == 0) 516 s->retry = IPMI_LAN_RETRY; 517 518 if (s->hostname == NULL || strlen((const char *)s->hostname) == 0) { 519 lprintf(LOG_ERR, "No hostname specified!"); 520 return -1; 521 } 522 523 intf->abort = 1; 524 intf->session->sol_data.sequence_number = 1; 525 526 if (ipmi_intf_socket_connect (intf) == -1) { 527 lprintf(LOG_ERR, "Could not open socket!"); 528 return -1; 529 } 530 531 if (intf->fd < 0) { 532 lperror(LOG_ERR, "Connect to %s failed", 533 s->hostname); 534 intf->close(intf); 535 return -1; 536 } 537 538 intf->opened = 1; 539 540 /* Lets ping/pong */ 541 return ipmiv2_lan_ping(intf); 542 # endif 543 } 544 545 /* This is the get DCMI Capabilities function to see what the BMC supports. 546 * 547 * returns 0 with out error -1 with any errors 548 * 549 * @intf: ipmi interface handler 550 * @selector: selection parameter 551 */ 552 static int 553 ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector) 554 { 555 uint8_t i; 556 uint8_t bit_shifter = 0; 557 struct capabilities cape; 558 struct ipmi_rs * rsp; 559 rsp = ipmi_dcmi_getcapabilities(intf, selector); 560 561 if(chk_rsp(rsp)) 562 return -1; 563 564 /* if there were no errors, the command worked! */ 565 memcpy(&cape, rsp->data, sizeof (cape)); 566 /* check to make sure that this is a 1.0/1.1/1.5 command */ 567 if ((cape.conformance != IPMI_DCMI_CONFORM) 568 && (cape.conformance != IPMI_DCMI_1_1_CONFORM) 569 && (cape.conformance != IPMI_DCMI_1_5_CONFORM)) { 570 lprintf(LOG_ERR, 571 "ERROR! This command is not available on this platform"); 572 return -1; 573 } 574 /* check to make sure that this is a rev .01 or .02 */ 575 if (cape.revision != 0x01 && cape.revision != 0x02) { 576 lprintf(LOG_ERR, 577 "ERROR! This command is not compatible with this version"); 578 return -1; 579 } 580 /* 0x01 - platform capabilities 581 * 0x02 - Manageability Access Capabilities 582 * 0x03 - SEL Capability 583 * 0x04 - Identification Capability 584 * 0x05 - LAN Out-Of-Band Capability 585 * 0x06 - Serial Out-Of-Band TMODE Capability 586 */ 587 switch (selector) { 588 case 0x01: 589 printf(" Supported DCMI capabilities:\n"); 590 /* loop through each of the entries in the first byte from the 591 * struct 592 */ 593 printf("\n Mandatory platform capabilties\n"); 594 display_capabilities_attributes( 595 dcmi_mandatory_platform_capabilities, cape.data_byte1); 596 /* loop through each of the entries in the second byte from the 597 * struct 598 */ 599 printf("\n Optional platform capabilties\n"); 600 display_capabilities_attributes( 601 dcmi_optional_platform_capabilities, cape.data_byte2); 602 /* loop through each of the entries in the third byte from the 603 * struct 604 */ 605 printf("\n Managebility access capabilties\n"); 606 display_capabilities_attributes( 607 dcmi_management_access_capabilities, cape.data_byte3); 608 break; 609 case 0x02: 610 printf("\n Mandatory platform attributes:\n"); 611 /* byte 1 & 2 data */ 612 printf("\n SEL Attributes: "); 613 printf("\n SEL automatic rollover is "); 614 /* mask the 2nd byte of the data response with 10000000b or 0x80 615 * because of the endian-ness the 15th bit is in the second byte 616 */ 617 if ((cape.data_byte2 & 0x80)) 618 printf("enabled"); 619 else 620 printf("not present"); 621 /* since the number of SEL entries is split across the two data 622 * bytes we will need to bit shift and append them together again 623 */ 624 /* cast cape.data_byte1 as 16 bits */ 625 uint16_t sel_entries = (uint16_t)cape.data_byte1; 626 /* or sel_entries with byte 2 and shift it 8 places */ 627 sel_entries |= (uint16_t)cape.data_byte2 << 8; 628 printf("\n %d SEL entries\n", sel_entries & 0xFFF); 629 /* byte 3 data */ 630 printf("\n Identification Attributes: \n"); 631 display_capabilities_attributes( 632 dcmi_id_capabilities_vals, cape.data_byte3); 633 /* byte 4 data */ 634 printf("\n Temperature Monitoring Attributes: \n"); 635 display_capabilities_attributes(dcmi_temp_monitoring_vals, 636 cape.data_byte4); 637 break; 638 case 0x03: 639 printf("\n Optional Platform Attributes: \n"); 640 /* Power Management */ 641 printf("\n Power Management:\n"); 642 if (cape.data_byte1 == 0x40) { 643 printf(" Slave address of device: 20h (BMC)\n" ); 644 } else { 645 printf(" Slave address of device: %xh (8bits)" 646 "(Satellite/External controller)\n", 647 cape.data_byte1); 648 } 649 /* Controller channel number (4-7) bits */ 650 if ((cape.data_byte2>>4) == 0x00) { 651 printf(" Channel number is 0h (Primary BMC)\n"); 652 } else { 653 printf(" Channel number is %xh \n", 654 (cape.data_byte2>>4)); 655 } 656 /* Device revision (0-3) */ 657 printf(" Device revision is %d \n", 658 cape.data_byte2 &0xf); 659 break; 660 case 0x04: 661 /* LAN */ 662 printf("\n Manageability Access Attributes: \n"); 663 if (cape.data_byte1 == 0xFF) { 664 printf(" Primary LAN channel is not available for OOB\n"); 665 } else { 666 printf(" Primary LAN channel number: %d is available\n", 667 cape.data_byte1); 668 } 669 if (cape.data_byte2 == 0xFF) { 670 printf(" Secondary LAN channel is not available for OOB\n"); 671 } else { 672 printf(" Secondary LAN channel number: %d is available\n", 673 cape.data_byte2); 674 } 675 /* serial */ 676 if (cape.data_byte3 == 0xFF) { 677 printf(" No serial channel is available\n"); 678 } else { 679 printf(" Serial channel number: %d is available\n", 680 cape.data_byte3); 681 } 682 break; 683 default: 684 return -1; 685 } 686 return 0; 687 /* return intf->sendrecv(intf, &req); */ 688 } 689 690 /* This is the get asset tag command. This checks the length of the asset tag 691 * with the first read, then reads n number of bytes thereafter to get the 692 * complete asset tag. 693 * 694 * @intf: ipmi interface handler 695 * @offset: where to start reading the asset tag 696 * @length: how much to read 697 * 698 * returns ipmi_rs structure 699 */ 700 struct ipmi_rs * 701 ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length) 702 { 703 struct ipmi_rq req; /* request data to send to the BMC */ 704 uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */ 705 706 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 707 msg_data[1] = offset; /* offset 0 */ 708 msg_data[2] = length; /* read one byte */ 709 710 memset(&req, 0, sizeof(req)); 711 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 712 req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */ 713 req.msg.data = msg_data; /* msg_data above */ 714 req.msg.data_len = 3; /* How many times does req.msg.data need to read */ 715 return intf->sendrecv(intf, &req); 716 } 717 718 /* This is the get asset tag command. The function first checks to see if the 719 * platform is capable of getting the asset tag by calling the getcapabilities 720 * function and checking the response. Then it checks the length of the asset 721 * tag with the first read, then x number of reads thereafter to get the asset 722 * complete asset tag then print it. 723 * 724 * @intf: ipmi interface handler 725 * 726 * returns 0 if no failure, -1 with a failure 727 */ 728 static int 729 ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf) 730 { 731 uint8_t data_byte2; 732 struct ipmi_rs * rsp; /* ipmi response */ 733 uint8_t taglength = 0; 734 uint8_t getlength = 0; 735 uint8_t offset = 0; 736 uint8_t i; 737 /* now let's get the asset tag length */ 738 rsp = ipmi_dcmi_getassettag(intf, 0, 0); 739 if (chk_rsp(rsp)) { 740 return -1; 741 } 742 taglength = rsp->data[1]; 743 printf("\n Asset tag: "); 744 while (taglength) { 745 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 746 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 747 rsp = ipmi_dcmi_getassettag(intf, offset, getlength); 748 /* macro has no effect here where can generate sig segv 749 * if rsp occurs with null 750 */ 751 if (rsp != NULL) { 752 GOOD_ASSET_TAG_CCODE(rsp->ccode); 753 } 754 if (chk_rsp(rsp)) { 755 return -1; 756 } 757 for (i=0; i<getlength; i++) { 758 printf("%c", rsp->data[i+2]); 759 } 760 offset += getlength; 761 taglength -= getlength; 762 } 763 printf("\n"); 764 return 0; 765 } 766 767 /* This is the set asset tag command. This checks the length of the asset tag 768 * with the first read, then reads n number of bytes thereafter to set the 769 * complete asset tag. 770 * 771 * @intf: ipmi interface handler 772 * @offset: offset to write 773 * @length: number of bytes to write (16 bytes maximum) 774 * @data: data to write 775 * 776 * returns ipmi_rs structure 777 */ 778 struct ipmi_rs * 779 ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length, 780 uint8_t *data) 781 { 782 struct ipmi_rq req; /* request data to send to the BMC */ 783 uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */ 784 785 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 786 msg_data[1] = offset; /* offset 0 */ 787 msg_data[2] = length; /* read one byte */ 788 789 memset(&req, 0, sizeof(req)); 790 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 791 req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */ 792 req.msg.data = msg_data; /* msg_data above */ 793 /* How many times does req.msg.data need to read */ 794 req.msg.data_len = length + 3; 795 memcpy(req.msg.data + 3, data, length); 796 797 return intf->sendrecv(intf, &req); 798 } 799 800 static int 801 ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data) 802 { 803 uint8_t data_byte2; 804 struct ipmi_rs * rsp; /* ipmi response */ 805 uint8_t tmpData[DCMI_MAX_BYTE_SIZE]; 806 uint8_t taglength = 0; 807 uint8_t getlength = 0; 808 uint8_t offset = 0; 809 uint8_t i; 810 811 /* now let's get the asset tag length */ 812 taglength = strlen(data); 813 if (taglength > 64){ 814 lprintf(LOG_ERR, "\nValue is too long."); 815 return -1; 816 } 817 printf("\n Set Asset Tag: "); 818 while (taglength) { 819 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 820 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 821 memcpy(tmpData, data + offset, getlength); 822 rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData); 823 if (chk_rsp(rsp)) { 824 return -1; 825 } 826 for (i=0; i<getlength; i++) { 827 printf("%c", tmpData[i]); 828 } 829 offset += getlength; 830 taglength -= getlength; 831 } 832 printf("\n"); 833 return 0; 834 } 835 836 /* Management Controller Identifier String is provided in order to accommodate 837 * the requirement for the management controllers to identify themselves. 838 * 839 * @intf: ipmi interface handler 840 * @offset: offset to read 841 * @length: number of bytes to read (16 bytes maximum) 842 * 843 * returns ipmi_rs structure 844 */ 845 struct ipmi_rs * 846 ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length) 847 { 848 struct ipmi_rq req; /* request data to send to the BMC */ 849 uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */ 850 851 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 852 msg_data[1] = offset; /* offset 0 */ 853 msg_data[2] = length; /* read one byte */ 854 855 memset(&req, 0, sizeof(req)); 856 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 857 req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */ 858 req.msg.data = msg_data; /* msg_data above */ 859 /* How many times does req.msg.data need to read */ 860 req.msg.data_len = 3; 861 return intf->sendrecv(intf, &req); 862 } 863 864 static int 865 ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf) 866 { 867 uint8_t data_byte2; 868 struct ipmi_rs * rsp; /* ipmi response */ 869 uint8_t taglength = 0; 870 uint8_t getlength = 0; 871 uint8_t offset = 0; 872 uint8_t i; 873 874 /* now let's get the asset tag length */ 875 rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1); 876 877 if (chk_rsp(rsp)) { 878 return -1; 879 } 880 881 taglength = rsp->data[1]; 882 883 printf("\n Get Management Controller Identifier String: "); 884 while (taglength) { 885 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 886 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 887 rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength); 888 889 if (chk_rsp(rsp)) { 890 return -1; 891 } 892 for (i=0; i<getlength; i++) { 893 printf("%c", rsp->data[i+2]); 894 } 895 offset += getlength; 896 taglength -= getlength; 897 } 898 printf("\n"); 899 return 0; 900 } 901 902 /* Management Controller Identifier String is provided in order to accommodate 903 * the requirement for the management controllers to identify themselves. 904 * 905 * @intf: ipmi interface handler 906 * @offset: offset to write 907 * @length: number of bytes to write (16 bytes maximum) 908 * @data: data to write 909 * 910 * returns ipmi_rs structure 911 */ 912 struct ipmi_rs * 913 ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length, 914 uint8_t *data) 915 { 916 struct ipmi_rq req; /* request data to send to the BMC */ 917 uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */ 918 919 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 920 msg_data[1] = offset; /* offset 0 */ 921 msg_data[2] = length; /* read one byte */ 922 923 memset(&req, 0, sizeof(req)); 924 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 925 req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */ 926 req.msg.data = msg_data; /* msg_data above */ 927 /* How many times does req.msg.data need to read */ 928 req.msg.data_len = 3 + length; 929 memcpy(req.msg.data + 3, data, length); 930 931 return intf->sendrecv(intf, &req); 932 } 933 934 /* Set Asset Tag command provides ability for the management console to set the 935 * asset tag as appropriate. Management controller is not responsible for the 936 * data format used for the Asset Tag once modified by IPDC. 937 * 938 * @intf: ipmi interface handler 939 * 940 * returns 0 if no failure, -1 with a failure 941 */ 942 static int 943 ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data) 944 { 945 uint8_t data_byte2; 946 struct ipmi_rs * rsp; /* ipmi response */ 947 uint8_t tmpData[DCMI_MAX_BYTE_SIZE]; 948 uint8_t taglength = 0; 949 uint8_t getlength = 0; 950 uint8_t offset = 0; 951 uint8_t i; 952 953 data += '\0'; 954 taglength = strlen(data) +1; 955 956 if (taglength > 64) { 957 lprintf(LOG_ERR, "\nValue is too long."); 958 return -1; 959 } 960 961 printf("\n Set Management Controller Identifier String Command: "); 962 while (taglength) { 963 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 964 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 965 memcpy(tmpData, data + offset, getlength); 966 rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData); 967 /* because after call "Set mc id string" RMCP+ will go down 968 * we have no "rsp" 969 */ 970 if (strncmp(intf->name, "lanplus", 7)) { 971 if (chk_rsp(rsp)) { 972 return -1; 973 } 974 } 975 for (i=0; i<getlength; i++) { 976 printf("%c", tmpData[i]); 977 } 978 offset += getlength; 979 taglength -= getlength; 980 } 981 printf("\n"); 982 return 0; 983 } 984 985 /* Issues a discovery command to see what sensors are available on the target. 986 * system. 987 * 988 * @intf: ipmi interface handler 989 * @isnsr: entity ID 990 * @offset: offset (Entity instace start) 991 * 992 * returns ipmi_rs structure 993 */ 994 struct ipmi_rs * 995 ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset) 996 { 997 struct ipmi_rq req; /* ipmi request struct */ 998 uint8_t msg_data[5]; /* number of request data bytes */ 999 1000 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1001 msg_data[1] = 0x01; /* Senser Type = Temp (01h) */ 1002 msg_data[2] = isnsr; /* Sensor Number */ 1003 msg_data[3] = 0x00; /* Entity Instance, set to read all instances */ 1004 msg_data[4] = offset; /* Entity instace start */ 1005 1006 memset(&req, 0, sizeof(req)); 1007 req.msg.netfn = IPMI_NETFN_DCGRP; 1008 req.msg.cmd = IPMI_DCMI_GETSNSR; 1009 req.msg.data = msg_data; /* Contents above */ 1010 req.msg.data_len = 5; /* how many times does req.msg.data need to read */ 1011 1012 return intf->sendrecv(intf, &req); 1013 } 1014 1015 /* DCMI sensor discovery 1016 * Uses the dcmi_discvry_snsr_vals struct to print its string and 1017 * uses the numeric values to request the sensor sdr record id. 1018 * 1019 * @intf: ipmi interface handler 1020 * @isnsr: entity ID 1021 * @ient: sensor entity id 1022 */ 1023 static int 1024 ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr) 1025 { 1026 int i = 0; 1027 struct ipmi_rs * rsp; /* ipmi response */ 1028 uint8_t records = 0; 1029 int8_t instances = 0; 1030 uint8_t offset = 0; 1031 uint16_t record_id = 0; 1032 uint8_t id_buff[16]; /* enough for 8 record IDs */ 1033 rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0); 1034 if (chk_rsp(rsp)) { 1035 return -1; 1036 } 1037 instances = rsp->data[1]; 1038 printf("\n%s: %d temperature sensor%s found:\n", 1039 val2str2(isnsr, dcmi_discvry_snsr_vals), 1040 instances, 1041 (instances > 1) ? "s" : ""); 1042 while(instances > 0) { 1043 ipmi_dcmi_discvry_snsr(intf, isnsr, offset); 1044 if (chk_rsp(rsp)) { 1045 return -1; 1046 } 1047 records = rsp->data[2]; 1048 /* cache the data since it may be destroyed by subsequent 1049 * ipmi_xxx calls 1050 */ 1051 memcpy(id_buff, &rsp->data[3], 16); 1052 for (i=0; i<records; i++) { 1053 /* Record ID is in little endian format */ 1054 record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i]; 1055 printf("Record ID 0x%04x: ", record_id); 1056 ipmi_print_sensor_info(intf, record_id); 1057 } 1058 offset += 8; 1059 instances -= records; 1060 } 1061 return 0; 1062 } 1063 /* end sensor discovery */ 1064 1065 /* Power Management get power reading 1066 * 1067 * @intf: ipmi interface handler 1068 */ 1069 static int 1070 ipmi_dcmi_pwr_rd(struct ipmi_intf * intf) 1071 { 1072 struct ipmi_rs * rsp; 1073 struct ipmi_rq req; 1074 struct power_reading val; 1075 struct tm tm_t; 1076 time_t t; 1077 uint8_t msg_data[4]; /* number of request data bytes */ 1078 memset(&tm_t, 0, sizeof(tm_t)); 1079 memset(&t, 0, sizeof(t)); 1080 1081 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1082 msg_data[1] = 0x01; /* Mode Power Status */ 1083 msg_data[2] = 0x00; /* reserved */ 1084 msg_data[3] = 0x00; /* reserved */ 1085 1086 memset(&req, 0, sizeof(req)); 1087 req.msg.netfn = IPMI_NETFN_DCGRP; 1088 req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */ 1089 req.msg.data = msg_data; /* msg_data above */ 1090 req.msg.data_len = 4; /* how many times does req.msg.data need to read */ 1091 1092 rsp = intf->sendrecv(intf, &req); 1093 1094 if (chk_rsp(rsp)) { 1095 return -1; 1096 } 1097 /* rsp->data[0] is equal to response data byte 2 in spec */ 1098 /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */ 1099 memcpy(&val, rsp->data, sizeof (val)); 1100 t = val.time_stamp; 1101 gmtime_r(&t, &tm_t); 1102 printf("\n"); 1103 printf(" Instantaneous power reading: %8d Watts\n", 1104 val.curr_pwr); 1105 printf(" Minimum during sampling period: %8d Watts\n", 1106 val.min_sample); 1107 printf(" Maximum during sampling period: %8d Watts\n", 1108 val.max_sample); 1109 printf(" Average power reading over sample period: %8d Watts\n", 1110 val.avg_pwr); 1111 printf(" IPMI timestamp: %s", 1112 asctime(&tm_t)); 1113 printf(" Sampling period: %08d Milliseconds\n", 1114 val.sample); 1115 printf(" Power reading state is: "); 1116 /* mask the rsp->data so that we only care about bit 6 */ 1117 if((val.state & 0x40) == 0x40) { 1118 printf("activated"); 1119 } else { 1120 printf("deactivated"); 1121 } 1122 printf("\n\n"); 1123 return 0; 1124 } 1125 /* end Power Management get reading */ 1126 1127 1128 /* This is the get thermalpolicy command. 1129 * 1130 * @intf: ipmi interface handler 1131 */ 1132 int 1133 ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID, 1134 uint8_t entityInstance) 1135 { 1136 struct ipmi_rs * rsp; 1137 struct ipmi_rq req; 1138 struct thermal_limit val; 1139 uint8_t msg_data[3]; /* number of request data bytes */ 1140 1141 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1142 msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/ 1143 msg_data[2] = entityInstance; /* Entity Instance */ 1144 1145 memset(&req, 0, sizeof(req)); 1146 req.msg.netfn = IPMI_NETFN_DCGRP; 1147 req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */ 1148 req.msg.data = msg_data; /* msg_data above */ 1149 req.msg.data_len = 3; /* how many times does req.msg.data need to read */ 1150 1151 rsp = intf->sendrecv(intf, &req); 1152 1153 if (chk_rsp(rsp)) { 1154 return -1; 1155 } 1156 /* rsp->data[0] is equal to response data byte 2 in spec */ 1157 memcpy(&val, rsp->data, sizeof (val)); 1158 printf("\n"); 1159 printf(" Persistance flag is: %s\n", 1160 ((val.exceptionActions & 0x80) ? "set" : "notset")); 1161 printf(" Exception Actions, taken if the Temperature Limit exceeded:\n"); 1162 printf(" Hard Power Off system and log event: %s\n", 1163 ((val.exceptionActions & 0x40) ? "active":"inactive")); 1164 printf(" Log event to SEL only: %s\n", 1165 ((val.exceptionActions & 0x20) ? "active":"inactive")); 1166 printf(" Temperature Limit %d degrees\n", 1167 val.tempLimit); 1168 printf(" Exception Time %d seconds\n", 1169 val.exceptionTime); 1170 printf("\n\n"); 1171 return 0; 1172 } 1173 1174 /* This is the set thermalpolicy command. 1175 * 1176 * @intf: ipmi interface handler 1177 */ 1178 int 1179 ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf, 1180 uint8_t entityID, 1181 uint8_t entityInst, 1182 uint8_t persistanceFlag, 1183 uint8_t actionHardPowerOff, 1184 uint8_t actionLogToSEL, 1185 uint8_t tempLimit, 1186 uint8_t samplingTimeLSB, 1187 uint8_t samplingTimeMSB) 1188 { 1189 struct ipmi_rs * rsp; 1190 struct ipmi_rq req; 1191 uint8_t msg_data[7]; /* number of request data bytes */ 1192 1193 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1194 msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/ 1195 msg_data[2] = entityInst; /* Entity Instance */ 1196 /* persistance and actions or disabled if no actions */ 1197 msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) | 1198 ((actionHardPowerOff? 1 : 0) << 6) | 1199 ((actionLogToSEL ? 1 : 0) << 5)); 1200 msg_data[4] = tempLimit; 1201 msg_data[5] = samplingTimeLSB; 1202 msg_data[6] = samplingTimeMSB; 1203 1204 memset(&req, 0, sizeof(req)); 1205 req.msg.netfn = IPMI_NETFN_DCGRP; 1206 /* Get thermal policy reading */ 1207 req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT; 1208 req.msg.data = msg_data; /* msg_data above */ 1209 /* how many times does req.msg.data need to read */ 1210 req.msg.data_len = 7; 1211 1212 rsp = intf->sendrecv(intf, &req); 1213 if (chk_rsp(rsp)) { 1214 return -1; 1215 } 1216 /* rsp->data[0] is equal to response data byte 2 in spec */ 1217 printf("\nThermal policy %d for %0Xh entity successfully set.\n\n", 1218 entityInst, entityID); 1219 return 0; 1220 } 1221 1222 /* This is Get Temperature Readings Command 1223 * 1224 * returns ipmi response structure 1225 * 1226 * @intf: ipmi interface handler 1227 */ 1228 struct ipmi_rs * 1229 ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf, 1230 uint8_t entityID, 1231 uint8_t entityInst, 1232 uint8_t entityInstStart) 1233 { 1234 struct ipmi_rq req; 1235 uint8_t msg_data[5]; /* number of request data bytes */ 1236 1237 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1238 msg_data[1] = 0x01; /* Sensor type */ 1239 msg_data[2] = entityID; /* Entity Instance */ 1240 msg_data[3] = entityInst; 1241 msg_data[4] = entityInstStart; 1242 1243 memset(&req, 0, sizeof(req)); 1244 req.msg.netfn = IPMI_NETFN_DCGRP; 1245 req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */ 1246 req.msg.data = msg_data; /* msg_data above */ 1247 /* how many times does req.msg.data need to read */ 1248 req.msg.data_len = 5; 1249 return intf->sendrecv(intf, &req); 1250 } 1251 1252 static int 1253 ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf) 1254 { 1255 struct ipmi_rs * rsp; 1256 int i,j, tota_inst, get_inst, offset = 0; 1257 /* Print sensor description */ 1258 printf("\n\tEntity ID\t\t\tEntity Instance\t Temp. Readings"); 1259 for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) { 1260 /* get all of the information about this sensor */ 1261 rsp = ipmi_dcmi_get_temp_readings(intf, 1262 dcmi_temp_read_vals[i].val, 0, 0); 1263 if (chk_rsp(rsp)) { 1264 continue; 1265 } 1266 /* Total number of available instances for the Entity ID */ 1267 offset = 0; 1268 tota_inst = rsp->data[1]; 1269 while (tota_inst > 0) { 1270 get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ? 1271 DCMI_MAX_BYTE_TEMP_READ_SIZE : 1272 (tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE)); 1273 rsp = ipmi_dcmi_get_temp_readings(intf, 1274 dcmi_temp_read_vals[i].val, offset, 0); 1275 if (chk_rsp(rsp)) { 1276 continue; 1277 } 1278 /* Number of sets of Temperature Data in this 1279 * response (Max 8 per response) 1280 */ 1281 for (j=0; j < rsp->data[2]*2; j=j+2) { 1282 /* Print Instance temperature info */ 1283 printf("\n%s",dcmi_temp_read_vals[i].desc); 1284 printf("\t\t%i\t\t%c%i C", rsp->data[j+4], 1285 ((rsp->data[j+3]) >> 7) ? 1286 '-' : '+', (rsp->data[j+3] & 127)); 1287 } 1288 offset += get_inst; 1289 tota_inst -= get_inst; 1290 } 1291 } 1292 return 0; 1293 } 1294 1295 /* This is Get DCMI Config Parameters Command 1296 * 1297 * returns ipmi response structure 1298 * 1299 * @intf: ipmi interface handler 1300 */ 1301 struct ipmi_rs * 1302 ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector) 1303 { 1304 struct ipmi_rq req; 1305 uint8_t msg_data[3]; /* number of request data bytes */ 1306 1307 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1308 msg_data[1] = param_selector; /* Parameter selector */ 1309 /* Set Selector. Selects a given set of parameters under a given Parameter 1310 * selector value. 00h if parameter doesn't use a Set Selector. 1311 */ 1312 msg_data[2] = 0x00; 1313 1314 memset(&req, 0, sizeof(req)); 1315 req.msg.netfn = IPMI_NETFN_DCGRP; 1316 req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */ 1317 req.msg.data = msg_data; /* Contents above */ 1318 /* how many times does req.msg.data need to read */ 1319 req.msg.data_len = 3; 1320 return intf->sendrecv(intf, &req); 1321 } 1322 1323 static int 1324 ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf) 1325 { 1326 struct ipmi_rs * rsp; 1327 const int dcmi_conf_params = 5; 1328 int param_selector; 1329 uint16_t tmp_value = 0; 1330 /* We are not interested in parameter 1 which always will return 0 */ 1331 for (param_selector = 2 ; param_selector <= dcmi_conf_params; 1332 param_selector++) { 1333 rsp = ipmi_dcmi_getconfparam(intf, param_selector); 1334 if (chk_rsp(rsp)) { 1335 return -1; 1336 } 1337 /* Time to print what we have got */ 1338 switch(param_selector) { 1339 case 2: 1340 tmp_value = (rsp->data[4])& 1; 1341 printf("\n\tDHCP Discovery method\t: "); 1342 printf("\n\t\tManagement Controller ID String is %s", 1343 tmp_value ? "enabled" : "disabled"); 1344 printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s", 1345 ((rsp->data[4])& 2) ? "enabled" : "disabled" ); 1346 break; 1347 case 3: 1348 printf("\n\tInitial timeout interval\t: %i seconds", 1349 rsp->data[4]); 1350 break; 1351 case 4: 1352 printf("\n\tServer contact timeout interval\t: %i seconds", 1353 rsp->data[4] + (rsp->data[5]<<8)); 1354 break; 1355 case 5: 1356 printf("\n\tServer contact retry interval\t: %i seconds", 1357 rsp->data[4] + (rsp->data[5] << 8)); 1358 break; 1359 default: 1360 printf("\n\tConfiguration Parameter not supported."); 1361 } 1362 } 1363 return 0; 1364 } 1365 1366 /* This is Set DCMI Config Parameters Command 1367 * 1368 * returns ipmi response structure 1369 * 1370 * @intf: ipmi interface handler 1371 */ 1372 struct ipmi_rs * 1373 ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector, 1374 uint16_t value) 1375 { 1376 struct ipmi_rq req; 1377 uint8_t msg_data[5]; /* number of request data bytes */ 1378 1379 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1380 msg_data[1] = param_selector; /* Parameter selector */ 1381 /* Set Selector (use 00h for parameters that only have one set). */ 1382 msg_data[2] = 0x00; 1383 1384 if (param_selector > 3) { 1385 /* One bite more */ 1386 msg_data[3] = value & 0xFF; 1387 msg_data[4] = value >> 8; 1388 } else { 1389 msg_data[3] = value; 1390 } 1391 1392 memset(&req, 0, sizeof(req)); 1393 req.msg.netfn = IPMI_NETFN_DCGRP; 1394 req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */ 1395 req.msg.data = msg_data; /* Contents above */ 1396 if (param_selector > 3) { 1397 /* One bite more */ 1398 /* how many times does req.msg.data need to read */ 1399 req.msg.data_len = 5; 1400 } else { 1401 /* how many times does req.msg.data need to read */ 1402 req.msg.data_len = 4; 1403 } 1404 return intf->sendrecv(intf, &req); 1405 } 1406 1407 /* Power Management get limit ipmi response 1408 * 1409 * This function returns the currently set power management settings as an 1410 * ipmi response structure. The reason it returns in the rsp struct is so 1411 * that it can be used in the set limit [slimit()] function to populate 1412 * un-changed or un-edited values. 1413 * 1414 * returns ipmi response structure 1415 * 1416 * @intf: ipmi interface handler 1417 */ 1418 struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf) 1419 { 1420 struct ipmi_rq req; 1421 uint8_t msg_data[3]; /* number of request data bytes */ 1422 1423 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1424 msg_data[1] = 0x00; /* reserved */ 1425 msg_data[2] = 0x00; /* reserved */ 1426 1427 memset(&req, 0, sizeof(req)); 1428 req.msg.netfn = IPMI_NETFN_DCGRP; 1429 req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */ 1430 req.msg.data = msg_data; /* Contents above */ 1431 /* how many times does req.msg.data need to read */ 1432 req.msg.data_len = 3; 1433 1434 return intf->sendrecv(intf, &req); 1435 } 1436 /* end Power Management get limit response */ 1437 1438 /* Power Management print the get limit command 1439 * 1440 * This function calls the get limit function that returns an ipmi response. 1441 * 1442 * returns 0 else 1 with error 1443 * @intf: ipmi interface handler 1444 */ 1445 static int 1446 ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf) 1447 { 1448 struct ipmi_rs * rsp; 1449 struct power_limit val; 1450 uint8_t realCc = 0xff; 1451 1452 rsp = ipmi_dcmi_pwr_glimit(intf); 1453 /* rsp can be a null so check response before any operation 1454 * on it to avoid sig segv 1455 */ 1456 if (rsp != NULL) { 1457 realCc = rsp->ccode; 1458 GOOD_PWR_GLIMIT_CCODE(rsp->ccode); 1459 } 1460 if (chk_rsp(rsp)) { 1461 return -1; 1462 } 1463 /* rsp->data[0] is equal to response data byte 2 in spec */ 1464 /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */ 1465 memcpy(&val, rsp->data, sizeof (val)); 1466 printf("\n Current Limit State: %s\n", 1467 (realCc == 0) ? 1468 "Power Limit Active" : "No Active Power Limit"); 1469 printf(" Exception actions: %s\n", 1470 val2str2(val.action, dcmi_pwrmgmt_get_action_vals)); 1471 printf(" Power Limit: %i Watts\n", val.limit); 1472 printf(" Correction time: %i milliseconds\n", val.correction); 1473 printf(" Sampling period: %i seconds\n", val.sample); 1474 printf("\n"); 1475 return 0; 1476 } 1477 /* end print get limit */ 1478 1479 /* Power Management set limit 1480 * 1481 * Undocumented bounds: 1482 * Power limit: 0 - 0xFFFF 1483 * Correction period 5750ms to 28751ms or 0x1676 to 0x704F 1484 * sample period: 3 sec to 65 sec and 69+ 1485 * 1486 * @intf: ipmi interface handler 1487 * @option: Power option to change 1488 * @value: Value of the desired change 1489 */ 1490 static int 1491 ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option, 1492 const char * value) 1493 { 1494 struct ipmi_rs * rsp; /* ipmi response */ 1495 struct ipmi_rq req; /* ipmi request (to send) */ 1496 struct power_limit val; 1497 uint8_t msg_data[15]; /* number of request data bytes */ 1498 uint32_t lvalue = 0; 1499 int i; 1500 1501 rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */ 1502 # if 0 1503 { 1504 unsigned char counter = 0; 1505 printf("DATA (%d): ", rsp->data_len); 1506 for(counter = 0; counter < rsp->data_len; counter ++) { 1507 printf("%02X ", rsp->data[counter]); 1508 } 1509 printf("\n"); 1510 } 1511 # endif 1512 /* rsp can be a null so check response before any operation on it to 1513 * avoid sig segv 1514 */ 1515 if (rsp != NULL) { 1516 GOOD_PWR_GLIMIT_CCODE(rsp->ccode); 1517 } 1518 if (chk_rsp(rsp)) { 1519 return -1; 1520 } 1521 memcpy(&val, rsp->data, sizeof (val)); 1522 /* same as above; sets the values of the val struct 1523 * DCMI group ID * 1524 * val.grp_id = rsp->data[0]; 1525 * exception action * 1526 * val.action = rsp->data[3]; * 1527 * 1528 * power limit in Watts * 1529 * store 16 bits of the rsp from the 4th entity * 1530 * val.limit = *(uint16_t*)(&rsp->data[4]); 1531 * correction period in mS * 1532 * store 32 bits of the rsp from the 6th entity * 1533 * val.correction = *(uint32_t*)(&rsp->data[6]); 1534 * store 16 bits of the rsp from the 12th entity * 1535 * sample period in seconds * 1536 * val.sample = *(uint16_t*)(&rsp->data[12]); 1537 */ 1538 lprintf(LOG_INFO, 1539 "DCMI IN Limit=%d Correction=%d Action=%d Sample=%d\n", 1540 val.limit, val.correction, val.action, val.sample); 1541 switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) { 1542 case 0x00: 1543 /* action */ 1544 switch (str2val2(value, dcmi_pwrmgmt_action_vals)) { 1545 case 0x00: 1546 /* no_action */ 1547 val.action = 0; 1548 break; 1549 case 0x01: 1550 /* power_off */ 1551 val.action = 1; 1552 break; 1553 case 0x02: 1554 /* OEM reserved action */ 1555 val.action = 0x02; 1556 break; 1557 case 0x03: 1558 /* OEM reserved action */ 1559 val.action = 0x03; 1560 break; 1561 case 0x04: 1562 /* OEM reserved action */ 1563 val.action = 0x04; 1564 break; 1565 case 0x05: 1566 /* OEM reserved action */ 1567 val.action = 0x05; 1568 break; 1569 case 0x06: 1570 /* OEM reserved action */ 1571 val.action = 0x06; 1572 break; 1573 case 0x07: 1574 /* OEM reserved action */ 1575 val.action = 0x07; 1576 break; 1577 case 0x08: 1578 /* OEM reserved action */ 1579 val.action = 0x08; 1580 break; 1581 case 0x09: 1582 /* OEM reserved action */ 1583 val.action = 0x09; 1584 break; 1585 case 0x0a: 1586 /* OEM reserved action */ 1587 val.action = 0x0a; 1588 break; 1589 case 0x0b: 1590 /* OEM reserved action */ 1591 val.action = 0x0b; 1592 break; 1593 case 0x0c: 1594 /* OEM reserved action */ 1595 val.action = 0x0c; 1596 break; 1597 case 0x0d: 1598 /* OEM reserved action */ 1599 val.action = 0x0d; 1600 break; 1601 case 0x0e: 1602 /* OEM reserved action */ 1603 val.action = 0x0e; 1604 break; 1605 case 0x0f: 1606 /* OEM reserved action */ 1607 val.action = 0x0f; 1608 break; 1609 case 0x10: 1610 /* OEM reserved action */ 1611 val.action = 0x10; 1612 break; 1613 case 0x11: 1614 /* sel_logging*/ 1615 val.action = 0x11; 1616 break; 1617 case 0xFF: 1618 /* error - not a string we knew what to do with */ 1619 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1620 option, value); 1621 return -1; 1622 } 1623 break; 1624 case 0x01: 1625 /* limit */ 1626 if (str2uint(value, &lvalue) != 0) { 1627 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1628 option, value); 1629 return (-1); 1630 } 1631 val.limit = *(uint16_t*)(&lvalue); 1632 break; 1633 case 0x02: 1634 /* correction */ 1635 if (str2uint(value, &lvalue) != 0) { 1636 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1637 option, value); 1638 return (-1); 1639 } 1640 val.correction = *(uint32_t*)(&lvalue); 1641 break; 1642 case 0x03: 1643 /* sample */ 1644 if (str2uint(value, &lvalue) != 0) { 1645 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1646 option, value); 1647 return (-1); 1648 } 1649 val.sample = *(uint16_t*)(&lvalue); 1650 break; 1651 case 0xff: 1652 /* no valid options */ 1653 return -1; 1654 } 1655 lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample); 1656 1657 msg_data[0] = val.grp_id; /* Group Extension Identification */ 1658 msg_data[1] = 0x00; /* reserved */ 1659 msg_data[2] = 0x00; /* reserved */ 1660 msg_data[3] = 0x00; /* reserved */ 1661 msg_data[4] = val.action; /* exception action; 0x00 disables it */ 1662 1663 /* fill msg_data[5] with the first 16 bits of val.limit */ 1664 *(uint16_t*)(&msg_data[5]) = val.limit; 1665 /* msg_data[5] = 0xFF; 1666 * msg_data[6] = 0xFF; 1667 */ 1668 /* fill msg_data[7] with the first 32 bits of val.correction */ 1669 *(uint32_t*)(&msg_data[7]) = val.correction; 1670 /* msg_data[7] = 0x76; 1671 * msg_data[8] = 0x16; 1672 * msg_data[9] = 0x00; 1673 * msg_data[10] = 0x00; 1674 */ 1675 msg_data[11] = 0x00; /* reserved */ 1676 msg_data[12] = 0x00; /* reserved */ 1677 /* fill msg_data[7] with the first 16 bits of val.sample */ 1678 *(uint16_t*)(&msg_data[13]) = val.sample; 1679 /* msg_data[13] = 0x03; */ 1680 memset(&req, 0, sizeof(req)); 1681 req.msg.netfn = IPMI_NETFN_DCGRP; 1682 req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */ 1683 req.msg.data = msg_data; /* Contents above */ 1684 /* how many times does req.msg.data need to read */ 1685 req.msg.data_len = 15; 1686 1687 rsp = intf->sendrecv(intf, &req); 1688 1689 if (chk_rsp(rsp)) { 1690 return -1; 1691 } 1692 return 0; 1693 } 1694 /* end Power Management set limit */ 1695 1696 /* Power Management activate deactivate 1697 * 1698 * @intf: ipmi interface handler 1699 * @option: uint8_t - 0 to deactivate or 1 to activate 1700 */ 1701 static int 1702 ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option) 1703 { 1704 struct ipmi_rs * rsp; 1705 struct ipmi_rq req; 1706 uint8_t msg_data[4]; /* number of request data bytes */ 1707 1708 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1709 msg_data[1] = option; /* 0 = Deactivate 1 = Activate */ 1710 msg_data[2] = 0x00; /* reserved */ 1711 msg_data[3] = 0x00; /* reserved */ 1712 1713 memset(&req, 0, sizeof(req)); 1714 req.msg.netfn = IPMI_NETFN_DCGRP; 1715 req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */ 1716 req.msg.data = msg_data; /* Contents above */ 1717 req.msg.data_len = 4; /* how mant times does req.msg.data need to read */ 1718 1719 rsp = intf->sendrecv(intf, &req); 1720 if (chk_rsp(rsp)) { 1721 return -1; 1722 } 1723 printf("\n Power limit successfully "); 1724 if (option == 0x00) { 1725 printf("deactivated"); 1726 } else { 1727 printf("activated"); 1728 } 1729 printf("\n"); 1730 return 0; 1731 } 1732 /* end power management activate/deactivate */ 1733 1734 /* main 1735 * 1736 * @intf: dcmi interface handler 1737 * @argc: argument count 1738 * @argv: argument vector 1739 */ 1740 int 1741 ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv) 1742 { 1743 int rc = 0; 1744 uint8_t ctl = 0; 1745 int i, ii, instances; 1746 struct ipmi_rs *rsp; 1747 1748 if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) { 1749 print_strs(dcmi_cmd_vals, 1750 "Data Center Management Interface commands", 1751 -1, 0); 1752 return -1; 1753 } 1754 /* start the cmd requested */ 1755 switch (str2val2(argv[0], dcmi_cmd_vals)) { 1756 case 0x00: 1757 /* discover capabilities*/ 1758 for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) { 1759 if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) { 1760 printf("Error discovering %s capabilities!\n", 1761 val2str2(i, dcmi_capable_vals)); 1762 return -1; 1763 } 1764 } 1765 break; 1766 case 0x01: 1767 /* power */ 1768 argv++; 1769 if (argv[0] == NULL) { 1770 print_strs(dcmi_pwrmgmt_vals, "power <command>", 1771 -1, 0); 1772 return -1; 1773 } 1774 /* power management */ 1775 switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) { 1776 case 0x00: 1777 /* get reading */ 1778 rc = ipmi_dcmi_pwr_rd(intf); 1779 break; 1780 case 0x01: 1781 /* get limit */ 1782 /* because the get limit function is also used to 1783 * populate unchanged values for the set limit 1784 * command it returns an ipmi response structure 1785 */ 1786 rc = ipmi_dcmi_pwr_prnt_glimit(intf); 1787 break; 1788 case 0x02: 1789 /* set limit */ 1790 if (argc < 4) { 1791 print_strs(dcmi_pwrmgmt_set_usage_vals, 1792 "set_limit <parameter> <value>", 1793 -1, 0); 1794 return -1; 1795 } 1796 if ( argc == 10) { 1797 /* Let`s initialize dcmi power parameters */ 1798 struct ipmi_rq req; 1799 uint8_t data[256]; 1800 uint16_t sample = 0; 1801 uint16_t limit = 0; 1802 uint32_t correction = 0; 1803 1804 memset(data, 0, sizeof(data)); 1805 memset(&req, 0, sizeof(req)); 1806 1807 req.msg.netfn = IPMI_NETFN_DCGRP; 1808 req.msg.lun = 0x00; 1809 req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */ 1810 req.msg.data = data; /* Contents above */ 1811 req.msg.data_len = 15; 1812 1813 data[0] = IPMI_DCMI; /* Group Extension Identification */ 1814 data[1] = 0x0; /* reserved */ 1815 data[2] = 0x0; /* reserved */ 1816 data[3] = 0x0; /* reserved */ 1817 1818 /* action */ 1819 switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) { 1820 case 0x00: 1821 /* no_action */ 1822 data[4] = 0x00; 1823 break; 1824 case 0x01: 1825 /* power_off */ 1826 data[4] = 0x01; 1827 break; 1828 case 0x11: 1829 /* sel_logging*/ 1830 data[4] = 0x11; 1831 break; 1832 case 0xFF: 1833 /* error - not a string we knew what to do with */ 1834 lprintf(LOG_ERR, "Given Action '%s' is invalid.", 1835 argv[2]); 1836 return -1; 1837 } 1838 /* limit */ 1839 if (str2ushort(argv[4], &limit) != 0) { 1840 lprintf(LOG_ERR, 1841 "Given Limit '%s' is invalid.", 1842 argv[4]); 1843 return (-1); 1844 } 1845 data[5] = limit >> 0; 1846 data[6] = limit >> 8; 1847 /* correction */ 1848 if (str2uint(argv[6], &correction) != 0) { 1849 lprintf(LOG_ERR, 1850 "Given Correction '%s' is invalid.", 1851 argv[6]); 1852 return (-1); 1853 } 1854 data[7] = correction >> 0; 1855 data[8] = correction >> 8; 1856 data[9] = correction >> 16; 1857 data[10] = correction >> 24; 1858 data[11] = 0x00; /* reserved */ 1859 data[12] = 0x00; /* reserved */ 1860 /* sample */ 1861 if (str2ushort(argv[8], &sample) != 0) { 1862 lprintf(LOG_ERR, 1863 "Given Sample '%s' is invalid.", 1864 argv[8]); 1865 return (-1); 1866 } 1867 data[13] = sample >> 0; 1868 data[14] = sample >> 8; 1869 1870 rsp = intf->sendrecv(intf, &req); 1871 if (chk_rsp(rsp)) { 1872 return -1; 1873 } 1874 } else { 1875 /* loop through each parameter and value until we have neither */ 1876 while ((argv[1] != NULL) && (argv[2] != NULL)) { 1877 rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]); 1878 /* catch any error that the set limit function returned */ 1879 if (rc > 0) { 1880 print_strs(dcmi_pwrmgmt_set_usage_vals, 1881 "set_limit <parameter> <value>", -1, 0); 1882 return -1; 1883 } 1884 /* the first argument is the command and the second is the 1885 * value. Move argv two places; what is now 3 will be 1 1886 */ 1887 argv+=2; 1888 } 1889 } 1890 rc = ipmi_dcmi_pwr_prnt_glimit(intf); 1891 break; 1892 case 0x03: 1893 /* activate */ 1894 rc = ipmi_dcmi_pwr_actdeact(intf, 1); 1895 break; 1896 case 0x04: 1897 /* deactivate */ 1898 rc = ipmi_dcmi_pwr_actdeact(intf, 0); 1899 break; 1900 default: 1901 /* no valid options */ 1902 print_strs(dcmi_pwrmgmt_vals, 1903 "power <command>", -1, 0); 1904 break; 1905 } 1906 /* power mgmt end */ 1907 break; 1908 /* end power command */ 1909 case 0x02: 1910 /* sensor print */ 1911 /* Look for each item in the dcmi_discvry_snsr_vals struct 1912 * and if it exists, print the sdr record id(s) for it. 1913 * Use the val from each one as the sensor number. 1914 */ 1915 for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) { 1916 /* get all of the information about this sensor */ 1917 rc = ipmi_dcmi_prnt_discvry_snsr(intf, 1918 dcmi_discvry_snsr_vals[i].val); 1919 } 1920 break; 1921 /* end sensor print */ 1922 case 0x03: 1923 /* asset tag */ 1924 if(ipmi_dcmi_prnt_getassettag(intf) < 0) { 1925 lprintf(LOG_ERR, "Error getting asset tag!"); 1926 return -1; 1927 } 1928 break; 1929 /* end asset tag */ 1930 case 0x04: 1931 { 1932 /* set asset tag */ 1933 if (argc == 1 ) { 1934 print_strs(dcmi_cmd_vals, 1935 "Data Center Management Interface commands", 1936 -1, 0); 1937 return -1; 1938 } 1939 if (ipmi_dcmi_prnt_setassettag(intf, argv[1]) < 0) { 1940 lprintf(LOG_ERR, "\nError setting asset tag!"); 1941 return -1; 1942 } 1943 break; 1944 } 1945 /* end set asset tag */ 1946 case 0x05: 1947 /* get management controller identifier string */ 1948 if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) { 1949 lprintf(LOG_ERR, 1950 "Error getting management controller identifier string!"); 1951 return -1; 1952 } 1953 break; 1954 /* end get management controller identifier string */ 1955 case 0x06: 1956 { 1957 /* set management controller identifier string */ 1958 if (argc == 1 ) { 1959 print_strs(dcmi_cmd_vals, 1960 "Data Center Management Interface commands", 1961 -1, 0); 1962 return -1; 1963 } 1964 if (ipmi_dcmi_prnt_setmngctrlids(intf, argv[1]) < 0) { 1965 lprintf(LOG_ERR, 1966 "Error setting management controller identifier string!"); 1967 return -1; 1968 } 1969 break; 1970 } 1971 /* end set management controller identifier string */ 1972 case 0x07: 1973 { 1974 uint8_t entityID = 0; 1975 uint8_t entityInst = 0; 1976 uint8_t persistanceFlag; 1977 uint8_t actionHardPowerOff; 1978 uint8_t actionLogToSEL; 1979 uint8_t tempLimit = 0; 1980 uint8_t samplingTimeLSB; 1981 uint8_t samplingTimeMSB; 1982 uint16_t samplingTime = 0; 1983 /* Thermal policy get/set */ 1984 /* dcmitool dcmi thermalpolicy get */ 1985 switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) { 1986 case 0x00: 1987 if (argc < 4) { 1988 lprintf(LOG_NOTICE, "Get <entityID> <instanceID>"); 1989 return -1; 1990 } 1991 if (str2uchar(argv[2], &entityID) != 0) { 1992 lprintf(LOG_ERR, 1993 "Given Entity ID '%s' is invalid.", 1994 argv[2]); 1995 return (-1); 1996 } 1997 if (str2uchar(argv[3], &entityInst) != 0) { 1998 lprintf(LOG_ERR, 1999 "Given Instance ID '%s' is invalid.", 2000 argv[3]); 2001 return (-1); 2002 } 2003 rc = ipmi_dcmi_getthermalpolicy(intf, entityID, entityInst); 2004 break; 2005 case 0x01: 2006 if (argc < 4) { 2007 lprintf(LOG_NOTICE, "Set <entityID> <instanceID>"); 2008 return -1; 2009 } else if (argc < 9) { 2010 print_strs(dcmi_thermalpolicy_set_parameters_vals, 2011 "Set thermalpolicy instance parameters: " 2012 "<volatile/nonvolatile/disabled> " 2013 "<poweroff/nopoweroff/disabled> " 2014 "<sel/nosel/disabled> <templimitByte> <exceptionTime>", 2015 -1, 0); 2016 return -1; 2017 } 2018 if (str2uchar(argv[2], &entityID) != 0) { 2019 lprintf(LOG_ERR, 2020 "Given Entity ID '%s' is invalid.", 2021 argv[2]); 2022 return (-1); 2023 } 2024 if (str2uchar(argv[3], &entityInst) != 0) { 2025 lprintf(LOG_ERR, 2026 "Given Instance ID '%s' is invalid.", 2027 argv[3]); 2028 return (-1); 2029 } 2030 persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals); 2031 actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals); 2032 actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals); 2033 if (str2uchar(argv[7], &tempLimit) != 0) { 2034 lprintf(LOG_ERR, 2035 "Given Temp Limit '%s' is invalid.", 2036 argv[7]); 2037 return (-1); 2038 } 2039 if (str2ushort(argv[8], &samplingTime) != 0) { 2040 lprintf(LOG_ERR, 2041 "Given Sampling Time '%s' is invalid.", 2042 argv[8]); 2043 return (-1); 2044 } 2045 samplingTimeLSB = (samplingTime & 0xFF); 2046 samplingTimeMSB = ((samplingTime & 0xFF00) >> 8); 2047 2048 rc = ipmi_dcmi_setthermalpolicy(intf, 2049 entityID, 2050 entityInst, 2051 persistanceFlag, 2052 actionHardPowerOff, 2053 actionLogToSEL, 2054 tempLimit, 2055 samplingTimeLSB, 2056 samplingTimeMSB); 2057 2058 break; 2059 default: 2060 print_strs(dcmi_thermalpolicy_vals, 2061 "thermalpolicy <command>", 2062 -1, 0); 2063 return -1; 2064 } 2065 break; 2066 } 2067 case 0x08: 2068 if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) { 2069 lprintf(LOG_ERR, 2070 "Error get temperature readings!"); 2071 } 2072 break; 2073 case 0x09: 2074 if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) { 2075 lprintf(LOG_ERR, 2076 "Error Get DCMI Configuration Parameters!"); 2077 }; 2078 break; 2079 case 0x0A: 2080 { 2081 switch (argc) { 2082 case 2: 2083 if (strncmp(argv[1], "activate_dhcp", 13) != 0) { 2084 print_strs( dcmi_conf_param_vals, 2085 "DCMI Configuration Parameters", 2086 -1, 0); 2087 return -1; 2088 } 2089 break; 2090 default: 2091 if (argc != 3 || strncmp(argv[1], "help", 4) == 0) { 2092 print_strs(dcmi_conf_param_vals, 2093 "DCMI Configuration Parameters", 2094 -1, 0); 2095 return -1; 2096 } 2097 } 2098 if (strncmp(argv[1], "activate_dhcp", 13) == 0) { 2099 rsp = ipmi_dcmi_setconfparam(intf, 1, 1); 2100 } else { 2101 uint16_t tmp_val = 0; 2102 if (str2ushort(argv[2], &tmp_val) != 0) { 2103 lprintf(LOG_ERR, 2104 "Given %s '%s' is invalid.", 2105 argv[1], argv[2]); 2106 return (-1); 2107 } 2108 rsp = ipmi_dcmi_setconfparam(intf, 2109 str2val2(argv[1], dcmi_conf_param_vals), 2110 tmp_val); 2111 } 2112 if (chk_rsp(rsp)) { 2113 lprintf(LOG_ERR, 2114 "Error Set DCMI Configuration Parameters!"); 2115 } 2116 break; 2117 } 2118 case 0x0B: 2119 { 2120 if (intf->session == NULL) { 2121 lprintf(LOG_ERR, 2122 "\nOOB discovery is available only via RMCP interface."); 2123 return -1; 2124 } 2125 if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) { 2126 lprintf(LOG_ERR, "\nOOB discovering capabilities failed."); 2127 return -1; 2128 } 2129 break; 2130 } 2131 default: 2132 /* couldn't detect what the user entered */ 2133 print_strs(dcmi_cmd_vals, 2134 "Data Center Management Interface commands", 2135 -1, 0); 2136 return -1; 2137 break; 2138 } 2139 printf("\n"); 2140 return 0; 2141 } 2142 2143 /* Display DCMI sensor information 2144 * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the 2145 * target Record ID. Then either ipmi_sensor_print_full or 2146 * ipmi_sensor_print_compact is called to print the data 2147 * 2148 * @intf: ipmi interface handler 2149 * @rec_id: target Record ID 2150 */ 2151 static int 2152 ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id) 2153 { 2154 struct sdr_get_rs *header; 2155 struct ipmi_sdr_iterator *itr; 2156 int rc = 0; 2157 uint8_t *rec = NULL; 2158 2159 itr = ipmi_sdr_start(intf, 0); 2160 if (itr == NULL) { 2161 lprintf(LOG_ERR, "Unable to open SDR for reading"); 2162 return (-1); 2163 } 2164 2165 while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) { 2166 if (header->id == rec_id) { 2167 break; 2168 } 2169 } 2170 if (header == NULL) { 2171 lprintf(LOG_DEBUG, "header == NULL"); 2172 ipmi_sdr_end(intf, itr); 2173 return (-1); 2174 } 2175 /* yes, we found the SDR for this record ID, now get full record */ 2176 rec = ipmi_sdr_get_record(intf, header, itr); 2177 if (rec == NULL) { 2178 lprintf(LOG_DEBUG, "rec == NULL"); 2179 ipmi_sdr_end(intf, itr); 2180 return (-1); 2181 } 2182 if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) || 2183 (header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) { 2184 rc = ipmi_sdr_print_rawentry(intf, header->type, 2185 rec, header->length); 2186 } else { 2187 rc = (-1); 2188 } 2189 free(rec); 2190 rec = NULL; 2191 ipmi_sdr_end(intf, itr); 2192 return rc; 2193 } 2194