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 extern int csv_output; 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 /* 299 * Start of Node Manager Operations 300 */ 301 302 const struct dcmi_cmd dcmi_sampling_vals[] = { 303 { 0x05, "5_sec", "" }, 304 { 0x0f, "15_sec", "" }, 305 { 0x1E, "30_sec", "" }, 306 { 0x41, "1_min", "" }, 307 { 0x43, "3_min", "" }, 308 { 0x47, "7_min", "" }, 309 { 0x4F, "15_min", "" }, 310 { 0x5E, "30_min", "" }, 311 { 0x81, "1_hour", ""}, 312 { 0x00, NULL, NULL }, 313 }; 314 315 /* Primary Node Manager commands */ 316 const struct dcmi_cmd nm_cmd_vals[] = { 317 { 0x00, "discover", "Discover Node Manager " }, 318 { 0x01, "capability", "Get Node Manager Capabilities" }, 319 { 0x02, "control", "Enable/Disable Policy Control" }, 320 { 0x03, "policy", "Add/Remove Policies" }, 321 { 0x04, "statistics", "Get Statistics" }, 322 { 0x05, "power", "Set Power Draw Range" }, 323 { 0x06, "suspend", "Set/Get Policy suspend periods" }, 324 { 0x07, "reset", "Reset Statistics" }, 325 { 0x08, "alert", "Set/Get/Clear Alert destination" }, 326 { 0x09, "threshold", "Set/Get Alert Thresholds" }, 327 { 0xFF, NULL, NULL }, 328 }; 329 330 const struct dcmi_cmd nm_ctl_cmds[] = { 331 { 0x01, "enable", " <control scope>" }, 332 { 0x00, "disable", "<control scope>"}, 333 { 0xFF, NULL, NULL }, 334 }; 335 336 const struct dcmi_cmd nm_ctl_domain[] = { 337 { 0x00, "global", "" }, 338 { 0x02, "per_domain", "<platform|CPU|Memory> (default is platform)" }, 339 { 0x04, "per_policy", "<0-7>" }, 340 { 0xFF, NULL, NULL }, 341 }; 342 343 /* Node Manager Domain codes */ 344 const struct dcmi_cmd nm_domain_vals[] = { 345 { 0x00, "platform", "" }, 346 { 0x01, "CPU", "" }, 347 { 0x02, "Memory", "" }, 348 { 0x03, "protection", "" }, 349 { 0x04, "I/O", "" }, 350 { 0xFF, NULL, NULL }, 351 }; 352 353 const struct dcmi_cmd nm_version_vals[] = { 354 { 0x01, "1.0", "" }, 355 { 0x02, "1.5", "" }, 356 { 0x03, "2.0", "" }, 357 { 0x04, "2.5", "" }, 358 { 0x05, "3.0", "" }, 359 { 0xFF, NULL, NULL }, 360 }; 361 362 const struct dcmi_cmd nm_capability_opts[] = { 363 { 0x01, "domain", "<platform|CPU|Memory> (default is platform)" }, 364 { 0x02, "inlet", "Inlet temp trigger" }, 365 { 0x03, "missing", "Missing Power reading trigger" }, 366 { 0x04, "reset", "Time after Host reset trigger" }, 367 { 0x05, "boot", "Boot time policy" }, 368 { 0xFF, NULL, NULL }, 369 }; 370 371 const struct dcmi_cmd nm_policy_type_vals[] = { 372 { 0x00, "No trigger, use Power Limit", "" }, 373 { 0x01, "Inlet temp trigger", "" }, 374 { 0x02, "Missing Power reading trigger", "" }, 375 { 0x03, "Time after Host reset trigger", "" }, 376 { 0x04, "number of cores to disable at boot time", "" }, 377 { 0xFF, NULL, NULL }, 378 }; 379 380 const struct dcmi_cmd nm_stats_opts[] = { 381 { 0x01, "domain", "<platform|CPU|Memory> (default is platform)" }, 382 { 0x02, "policy_id", "<0-7>" }, 383 { 0xFF, NULL, NULL }, 384 }; 385 386 const struct dcmi_cmd nm_stats_mode[] = { 387 { 0x01, "power", "global power" }, 388 { 0x02, "temps", "inlet temperature" }, 389 { 0x11, "policy_power", "per policy power" }, 390 { 0x12, "policy_temps", "per policy inlet temp" }, 391 { 0x13, "policy_throt", "per policy throttling stats" }, 392 { 0x1B, "requests", "unhandled requests" }, 393 { 0x1C, "response", "response time" }, 394 { 0x1D, "cpu_throttling", "CPU throttling" }, 395 { 0x1E, "mem_throttling", "memory throttling" }, 396 { 0x1F, "comm_fail", "host communication failures" }, 397 { 0xFF, NULL, NULL }, 398 }; 399 400 const struct dcmi_cmd nm_policy_action[] = { 401 { 0x00, "get", "nm policy get policy_id <0-7> [domain <platform|CPU|Memory>]" }, 402 { 0x04, "add", "nm policy add policy_id <0-7> [domain <platform|CPU|Memory>] correction auto|soft|hard power <watts>|inlet <temp> trig_lim <param> stats <seconds> enable|disable" }, 403 { 0x05, "remove", "nm policy remove policy_id <0-7> [domain <platform|CPU|Memory>]" }, 404 { 0x06, "limiting", "nm policy limiting [domain <platform|CPU|Memory>]" }, 405 { 0xFF, NULL, NULL }, 406 }; 407 const struct dcmi_cmd nm_policy_options[] = { 408 { 0x01, "enable", "" }, 409 { 0x02, "disable", "" }, 410 { 0x03, "domain", "" }, 411 { 0x04, "inlet", "inlet air temp full limiting (SCRAM)"}, 412 { 0x06, "correction", "auto, soft, hard" }, 413 { 0x08, "power", "power limit in watts" }, 414 { 0x09, "trig_lim", "time to send alert" }, 415 { 0x0A, "stats", "moving window averaging time" }, 416 { 0x0B, "policy_id", "policy number" }, 417 { 0x0C, "volatile", "save policy in volatiel memory" }, 418 { 0x0D, "cores_off", "at boot time, disable N cores" }, 419 { 0xFF, NULL, NULL }, 420 }; 421 422 /* if "trigger" command used from nm_policy_options */ 423 const struct dcmi_cmd nm_trigger[] = { 424 { 0x00, "none", "" }, 425 { 0x01, "temp", "" }, 426 { 0x02, "reset", "" }, 427 { 0x03, "boot", "" }, 428 { 0xFF, NULL, NULL }, 429 }; 430 431 /* if "correction" used from nm_policy_options */ 432 const struct dcmi_cmd nm_correction[] = { 433 { 0x00, "auto", "" }, 434 { 0x01, "soft", "" }, 435 { 0x02, "hard", "" }, 436 { 0xFF, NULL, NULL }, 437 }; 438 439 /* returned codes from get policy */ 440 const struct dcmi_cmd nm_correction_vals[] = { 441 { 0x00, "no T-state use", "" }, 442 { 0x01, "no T-state use", "" }, 443 { 0x02, "use T-states", "" }, 444 { 0xFF, NULL, NULL }, 445 }; 446 447 /* if "exception" used from nm_policy_options */ 448 const struct dcmi_cmd nm_exception[] = { 449 { 0x00, "none", "" }, 450 { 0x01, "alert", "" }, 451 { 0x02, "shutdown", "" }, 452 { 0xFF, NULL, NULL }, 453 }; 454 455 const struct dcmi_cmd nm_reset_mode[] = { 456 { 0x00, "global", "" }, 457 { 0x01, "per_policy", "" }, 458 { 0x1B, "requests", "" }, 459 { 0x1C, "response", "" }, 460 { 0x1D, "throttling", "" }, 461 { 0x1E, "memory", "", }, 462 { 0x1F, "comm", "" }, 463 { 0xFF, NULL, NULL }, 464 }; 465 466 const struct dcmi_cmd nm_power_range[] = { 467 { 0x01, "domain", "domain <platform|CPU|Memory> (default is platform)" }, 468 { 0x02, "min", " min <integer value>" }, 469 { 0x03, "max", "max <integer value>" }, 470 { 0xFF, NULL, NULL }, 471 }; 472 473 const struct dcmi_cmd nm_alert_opts[] = { 474 { 0x01, "set", "nm alert set chan <chan> dest <dest> string <string>" }, 475 { 0x02, "get", "nm alert get" }, 476 { 0x03, "clear", "nm alert clear dest <dest>" }, 477 }; 478 479 const struct dcmi_cmd nm_set_alert_param[] = { 480 { 0x01, "chan", "chan <channel>" }, 481 { 0x02, "dest", "dest <destination>" }, 482 { 0x03, "string", "string <string>" }, 483 }; 484 485 const struct dcmi_cmd nm_thresh_cmds[] = { 486 { 0x01, "set", "nm thresh set [domain <platform|CPU|Memory>] policy_id <policy> thresh_array" }, 487 { 0x02, "get", "nm thresh get [domain <platform|CPU|Memory>] policy_id <policy>" }, 488 }; 489 490 const struct dcmi_cmd nm_thresh_param[] = { 491 { 0x01, "domain", "<platform|CPU|Memory> (default is platform)" }, 492 { 0x02, "policy_id", "<0-7>" }, 493 { 0xFF, NULL, NULL }, 494 }; 495 496 const struct dcmi_cmd nm_suspend_cmds[] = { 497 { 0x01, "set", "nm suspend set [domain <platform|CPU|Memory]> policy_id <policy> <start> <stop> <pattern>" }, 498 { 0x02, "get", "nm suspend get [domain <platform|CPU|Memory]> policy_id <policy>" }, 499 }; 500 501 const struct valstr nm_ccode_vals[] = { 502 { 0x80, "Policy ID Invalid"}, 503 { 0x81, "Domain ID Invalid"}, 504 { 0x82, "Unknown policy trigger type"}, 505 { 0x84, "Power Limit out of range"}, 506 { 0x85, "Correction Time out of range"}, 507 { 0x86, "Policy Trigger value out of range"}, 508 { 0x88, "Invalid Mode"}, 509 { 0x89, "Statistics Reporting Period out of range"}, 510 { 0x8B, "Invalid value for Aggressive CPU correction field"}, 511 { 0xA1, "No policy is currently limiting for the specified domain ID"}, 512 { 0xC4, "No space available"}, 513 { 0xD4, "Insufficient privledge level due wrong responder LUN"}, 514 { 0xD5, "Policy exists and param unchangeable while enabled"}, 515 { 0xD6, "Command subfunction disabled or unavailable"}, 516 { 0xFF, NULL }, 517 }; 518 519 520 /* End strings */ 521 522 /* This was taken from print_valstr() from helper.c. It serves the same 523 * purpose but with out the extra formatting. This function simply prints 524 * the dcmi_cmd struct provided. verthorz specifies to print vertically or 525 * horizontally. If the string is printed horizontally then a | will be 526 * printed between each instance of vs[i].str until it is NULL 527 * 528 * @vs: value string list to print 529 * @title: name of this value string list 530 * @loglevel: what log level to print, -1 for stdout 531 * @verthorz: printed vertically or horizontally, 0 or 1 532 */ 533 void 534 print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel, 535 int verthorz) 536 { 537 int i; 538 539 if (vs == NULL) 540 return; 541 542 if (title != NULL) { 543 if (loglevel < 0) 544 printf("\n%s\n", title); 545 else 546 lprintf(loglevel, "\n%s", title); 547 } 548 for (i = 0; vs[i].str != NULL; i++) { 549 if (loglevel < 0) { 550 if (vs[i].val < 256) 551 if (verthorz == 0) 552 printf(" %s %s\n", vs[i].str, vs[i].desc); 553 else 554 printf("%s", vs[i].str); 555 else if (verthorz == 0) 556 printf(" %s %s\n", vs[i].str, vs[i].desc); 557 else 558 printf("%s", vs[i].str); 559 } else { 560 if (vs[i].val < 256) 561 lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc); 562 else 563 lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc); 564 } 565 /* Check to see if this is NOT the last element in vs.str if true 566 * print the | else don't print anything. 567 */ 568 if ((verthorz == 1) && (vs[i+1].str != NULL)) 569 printf(" | "); 570 } 571 if (verthorz == 0) { 572 if (loglevel < 0) { 573 printf("\n"); 574 } else { 575 lprintf(loglevel, ""); 576 } 577 } 578 } 579 580 /* This was taken from str2val() from helper.c. It serves the same 581 * purpose but with the addition of a desc field from the structure. 582 * This function converts the str from the dcmi_cmd struct provided to the 583 * value associated to the compared string in the struct. 584 * 585 * @str: string to compare against 586 * @vs: dcmi_cmd structure 587 */ 588 uint16_t 589 str2val2(const char *str, const struct dcmi_cmd *vs) 590 { 591 int i; 592 if (vs == NULL || str == NULL) { 593 return 0; 594 } 595 for (i = 0; vs[i].str != NULL; i++) { 596 if (strncasecmp(vs[i].str, str, 597 __maxlen(str, vs[i].str)) == 0) { 598 return vs[i].val; 599 } 600 } 601 return vs[i].val; 602 } 603 604 /* This was taken from val2str() from helper.c. It serves the same 605 * purpose but with the addition of a desc field from the structure. 606 * This function converts the val and returns a string from the dcmi_cmd 607 * struct provided in the struct. 608 * 609 * @val: value to compare against 610 * @vs: dcmi_cmd structure 611 */ 612 const char * 613 val2str2(uint16_t val, const struct dcmi_cmd *vs) 614 { 615 static char un_str[32]; 616 int i; 617 618 if (vs == NULL) 619 return NULL; 620 621 for (i = 0; vs[i].str != NULL; i++) { 622 if (vs[i].val == val) 623 return vs[i].str; 624 } 625 memset(un_str, 0, sizeof (un_str)); 626 snprintf(un_str, 32, "Unknown (0x%x)", val); 627 return un_str; 628 } 629 630 /* check the DCMI response from the BMC 631 * @rsp: Response data structure 632 */ 633 static int 634 chk_rsp(struct ipmi_rs * rsp) 635 { 636 /* if the response from the intf is NULL then the BMC is experiencing 637 * some issue and cannot complete the command 638 */ 639 if (rsp == NULL) { 640 lprintf(LOG_ERR, "\n Unable to get DCMI information"); 641 return 1; 642 } 643 /* if the completion code is greater than zero there was an error. We'll 644 * use val2str from helper.c to print the error from either the DCMI 645 * completion code struct or the generic IPMI completion_code_vals struct 646 */ 647 if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) { 648 lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)", 649 val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode); 650 return 1; 651 } else if (rsp->ccode > 0) { 652 lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)", 653 val2str(rsp->ccode, completion_code_vals), rsp->ccode); 654 return 1; 655 } 656 /* check to make sure this is a DCMI firmware */ 657 if(rsp->data[0] != IPMI_DCMI) { 658 printf("\n A valid DCMI command was not returned! (%x)", rsp->data[0]); 659 return 1; 660 } 661 return 0; 662 } 663 664 /* check the Node Manager response from the BMC 665 * @rsp: Response data structure 666 */ 667 static int 668 chk_nm_rsp(struct ipmi_rs * rsp) 669 { 670 /* if the response from the intf is NULL then the BMC is experiencing 671 * some issue and cannot complete the command 672 */ 673 if (rsp == NULL) { 674 lprintf(LOG_ERR, "\n No reponse to NM request"); 675 return 1; 676 } 677 /* if the completion code is greater than zero there was an error. We'll 678 * use val2str from helper.c to print the error from either the DCMI 679 * completion code struct or the generic IPMI completion_code_vals struct 680 */ 681 if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0xD6)) { 682 lprintf(LOG_ERR, "\n NM request failed because: %s (%x)", 683 val2str(rsp->ccode, nm_ccode_vals), rsp->ccode); 684 return 1; 685 } else if (rsp->ccode > 0) { 686 lprintf(LOG_ERR, "\n NM request failed because: %s (%x)", 687 val2str(rsp->ccode, completion_code_vals), rsp->ccode); 688 return 1; 689 } 690 /* check to make sure this is a DCMI firmware */ 691 if(rsp->data[0] != 0x57) { 692 printf("\n A valid NM command was not returned! (%x)", rsp->data[0]); 693 return 1; 694 } 695 return 0; 696 } 697 698 /* Get capabilities ipmi response 699 * 700 * This function returns the available capabilities of the platform. 701 * The reason it returns in the rsp struct is so that it can be used for other 702 * purposes. 703 * 704 * returns ipmi response structure 705 * 706 * @intf: ipmi interface handler 707 * @selector: Parameter selector 708 */ 709 struct ipmi_rs * 710 ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector) 711 { 712 struct ipmi_rq req; /* request data to send to the BMC */ 713 uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */ 714 715 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 716 msg_data[1] = selector; 717 718 memset(&req, 0, sizeof(req)); 719 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */ 720 req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */ 721 req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */ 722 req.msg.data_len = 2; /* How many times does req.msg.data need to read */ 723 724 return intf->sendrecv(intf, &req); 725 } 726 /* end capabilities struct */ 727 728 /* Displays capabilities from structure 729 * returns void 730 * 731 * @cmd: dcmi_cmd structure 732 * @data_val: holds value of what to display 733 */ 734 void 735 display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val) 736 { 737 uint8_t i; 738 for (i = 0x01; cmd[i-1].val != 0xFF; i++) { 739 if (data_val & (1<<(i-1))) { 740 printf(" %s\n", val2str2(i, cmd)); 741 } 742 } 743 } 744 745 static int 746 ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf) 747 { 748 # ifndef IPMI_INTF_LANPLUS 749 lprintf(LOG_ERR, 750 "DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled."); 751 return (-1); 752 # else 753 struct ipmi_session_params *p; 754 755 if (intf->opened == 0 && intf->open != NULL) { 756 if (intf->open(intf) < 0) 757 return (-1); 758 } 759 if (intf == NULL || intf->session == NULL) 760 return -1; 761 762 p = &intf->ssn_params; 763 764 if (p->port == 0) 765 p->port = IPMI_LAN_PORT; 766 if (p->privlvl == 0) 767 p->privlvl = IPMI_SESSION_PRIV_ADMIN; 768 if (p->timeout == 0) 769 p->timeout = IPMI_LAN_TIMEOUT; 770 if (p->retry == 0) 771 p->retry = IPMI_LAN_RETRY; 772 773 if (p->hostname == NULL || strlen((const char *)p->hostname) == 0) { 774 lprintf(LOG_ERR, "No hostname specified!"); 775 return -1; 776 } 777 778 intf->abort = 1; 779 intf->session->sol_data.sequence_number = 1; 780 781 if (ipmi_intf_socket_connect (intf) == -1) { 782 lprintf(LOG_ERR, "Could not open socket!"); 783 return -1; 784 } 785 786 if (intf->fd < 0) { 787 lperror(LOG_ERR, "Connect to %s failed", 788 p->hostname); 789 intf->close(intf); 790 return -1; 791 } 792 793 intf->opened = 1; 794 795 /* Lets ping/pong */ 796 return ipmiv2_lan_ping(intf); 797 # endif 798 } 799 800 /* This is the get DCMI Capabilities function to see what the BMC supports. 801 * 802 * returns 0 with out error -1 with any errors 803 * 804 * @intf: ipmi interface handler 805 * @selector: selection parameter 806 */ 807 static int 808 ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector) 809 { 810 struct capabilities cape; 811 struct ipmi_rs * rsp; 812 uint8_t reply[16]; 813 rsp = ipmi_dcmi_getcapabilities(intf, selector); 814 int j; 815 816 if(chk_rsp(rsp)) 817 return -1; 818 819 /* if there were no errors, the command worked! */ 820 memcpy(&cape, rsp->data, sizeof (cape)); 821 memcpy(&reply, rsp->data, sizeof (reply)); 822 /* check to make sure that this is a 1.0/1.1/1.5 command */ 823 if ((cape.conformance != IPMI_DCMI_CONFORM) 824 && (cape.conformance != IPMI_DCMI_1_1_CONFORM) 825 && (cape.conformance != IPMI_DCMI_1_5_CONFORM)) { 826 lprintf(LOG_ERR, 827 "ERROR! This command is not available on this platform"); 828 return -1; 829 } 830 /* check to make sure that this is a rev .01 or .02 */ 831 if (cape.revision != 0x01 && cape.revision != 0x02) { 832 lprintf(LOG_ERR, 833 "ERROR! This command is not compatible with this version"); 834 return -1; 835 } 836 /* 0x01 - platform capabilities 837 * 0x02 - Manageability Access Capabilities 838 * 0x03 - SEL Capability 839 * 0x04 - Identification Capability 840 * 0x05 - LAN Out-Of-Band Capability 841 * 0x06 - Serial Out-Of-Band TMODE Capability 842 */ 843 switch (selector) { 844 case 0x01: 845 printf(" Supported DCMI capabilities:\n"); 846 /* loop through each of the entries in the first byte from the 847 * struct 848 */ 849 printf("\n Mandatory platform capabilties\n"); 850 display_capabilities_attributes( 851 dcmi_mandatory_platform_capabilities, cape.data_byte1); 852 /* loop through each of the entries in the second byte from the 853 * struct 854 */ 855 printf("\n Optional platform capabilties\n"); 856 display_capabilities_attributes( 857 dcmi_optional_platform_capabilities, cape.data_byte2); 858 /* loop through each of the entries in the third byte from the 859 * struct 860 */ 861 printf("\n Managebility access capabilties\n"); 862 display_capabilities_attributes( 863 dcmi_management_access_capabilities, cape.data_byte3); 864 break; 865 case 0x02: 866 printf("\n Mandatory platform attributes:\n"); 867 /* byte 1 & 2 data */ 868 printf("\n SEL Attributes: "); 869 printf("\n SEL automatic rollover is "); 870 /* mask the 2nd byte of the data response with 10000000b or 0x80 871 * because of the endian-ness the 15th bit is in the second byte 872 */ 873 if ((cape.data_byte2 & 0x80)) 874 printf("enabled"); 875 else 876 printf("not present"); 877 /* since the number of SEL entries is split across the two data 878 * bytes we will need to bit shift and append them together again 879 */ 880 /* cast cape.data_byte1 as 16 bits */ 881 uint16_t sel_entries = (uint16_t)cape.data_byte1; 882 /* or sel_entries with byte 2 and shift it 8 places */ 883 sel_entries |= (uint16_t)cape.data_byte2 << 8; 884 printf("\n %d SEL entries\n", sel_entries & 0xFFF); 885 /* byte 3 data */ 886 printf("\n Identification Attributes: \n"); 887 display_capabilities_attributes( 888 dcmi_id_capabilities_vals, cape.data_byte3); 889 /* byte 4 data */ 890 printf("\n Temperature Monitoring Attributes: \n"); 891 display_capabilities_attributes(dcmi_temp_monitoring_vals, 892 cape.data_byte4); 893 break; 894 case 0x03: 895 printf("\n Optional Platform Attributes: \n"); 896 /* Power Management */ 897 printf("\n Power Management:\n"); 898 if (cape.data_byte1 == 0x40) { 899 printf(" Slave address of device: 20h (BMC)\n" ); 900 } else { 901 printf(" Slave address of device: %xh (8bits)" 902 "(Satellite/External controller)\n", 903 cape.data_byte1); 904 } 905 /* Controller channel number (4-7) bits */ 906 if ((cape.data_byte2>>4) == 0x00) { 907 printf(" Channel number is 0h (Primary BMC)\n"); 908 } else { 909 printf(" Channel number is %xh \n", 910 (cape.data_byte2>>4)); 911 } 912 /* Device revision (0-3) */ 913 printf(" Device revision is %d \n", 914 cape.data_byte2 &0xf); 915 break; 916 case 0x04: 917 /* LAN */ 918 printf("\n Manageability Access Attributes: \n"); 919 if (cape.data_byte1 == 0xFF) { 920 printf(" Primary LAN channel is not available for OOB\n"); 921 } else { 922 printf(" Primary LAN channel number: %d is available\n", 923 cape.data_byte1); 924 } 925 if (cape.data_byte2 == 0xFF) { 926 printf(" Secondary LAN channel is not available for OOB\n"); 927 } else { 928 printf(" Secondary LAN channel number: %d is available\n", 929 cape.data_byte2); 930 } 931 /* serial */ 932 if (cape.data_byte3 == 0xFF) { 933 printf(" No serial channel is available\n"); 934 } else { 935 printf(" Serial channel number: %d is available\n", 936 cape.data_byte3); 937 } 938 break; 939 case 0x05: 940 /* Node Manager */ 941 printf("\n Node Manager Get DCMI Capability Info: \n"); 942 printf(" DCMI Specification %d.%d\n", reply[1], reply[2]); 943 printf(" Rolling average time period options: %d\n", reply[4]); 944 printf(" Sample time options: "); 945 for (j = 1; dcmi_sampling_vals[j-1].str != NULL; j++) 946 printf(" %s ", val2str2(reply[4+j],dcmi_sampling_vals)); 947 printf("\n"); 948 break; 949 default: 950 return -1; 951 } 952 return 0; 953 /* return intf->sendrecv(intf, &req); */ 954 } 955 956 /* This is the get asset tag command. This checks the length of the asset tag 957 * with the first read, then reads n number of bytes thereafter to get the 958 * complete asset tag. 959 * 960 * @intf: ipmi interface handler 961 * @offset: where to start reading the asset tag 962 * @length: how much to read 963 * 964 * returns ipmi_rs structure 965 */ 966 struct ipmi_rs * 967 ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length) 968 { 969 struct ipmi_rq req; /* request data to send to the BMC */ 970 uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */ 971 972 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 973 msg_data[1] = offset; /* offset 0 */ 974 msg_data[2] = length; /* read one byte */ 975 976 memset(&req, 0, sizeof(req)); 977 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 978 req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */ 979 req.msg.data = msg_data; /* msg_data above */ 980 req.msg.data_len = 3; /* How many times does req.msg.data need to read */ 981 return intf->sendrecv(intf, &req); 982 } 983 984 /* This is the get asset tag command. The function first checks to see if the 985 * platform is capable of getting the asset tag by calling the getcapabilities 986 * function and checking the response. Then it checks the length of the asset 987 * tag with the first read, then x number of reads thereafter to get the asset 988 * complete asset tag then print it. 989 * 990 * @intf: ipmi interface handler 991 * 992 * returns 0 if no failure, -1 with a failure 993 */ 994 static int 995 ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf) 996 { 997 struct ipmi_rs * rsp; /* ipmi response */ 998 uint8_t taglength = 0; 999 uint8_t getlength = 0; 1000 uint8_t offset = 0; 1001 uint8_t i; 1002 /* now let's get the asset tag length */ 1003 rsp = ipmi_dcmi_getassettag(intf, 0, 0); 1004 if (chk_rsp(rsp)) { 1005 return -1; 1006 } 1007 taglength = rsp->data[1]; 1008 printf("\n Asset tag: "); 1009 while (taglength) { 1010 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 1011 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 1012 rsp = ipmi_dcmi_getassettag(intf, offset, getlength); 1013 /* macro has no effect here where can generate sig segv 1014 * if rsp occurs with null 1015 */ 1016 if (rsp != NULL) { 1017 GOOD_ASSET_TAG_CCODE(rsp->ccode); 1018 } 1019 if (chk_rsp(rsp)) { 1020 return -1; 1021 } 1022 for (i=0; i<getlength; i++) { 1023 printf("%c", rsp->data[i+2]); 1024 } 1025 offset += getlength; 1026 taglength -= getlength; 1027 } 1028 printf("\n"); 1029 return 0; 1030 } 1031 1032 /* This is the set asset tag command. This checks the length of the asset tag 1033 * with the first read, then reads n number of bytes thereafter to set the 1034 * complete asset tag. 1035 * 1036 * @intf: ipmi interface handler 1037 * @offset: offset to write 1038 * @length: number of bytes to write (16 bytes maximum) 1039 * @data: data to write 1040 * 1041 * returns ipmi_rs structure 1042 */ 1043 struct ipmi_rs * 1044 ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length, 1045 uint8_t *data) 1046 { 1047 struct ipmi_rq req; /* request data to send to the BMC */ 1048 uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */ 1049 1050 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1051 msg_data[1] = offset; /* offset 0 */ 1052 msg_data[2] = length; /* read one byte */ 1053 1054 memset(&req, 0, sizeof(req)); 1055 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 1056 req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */ 1057 req.msg.data = msg_data; /* msg_data above */ 1058 /* How many times does req.msg.data need to read */ 1059 req.msg.data_len = length + 3; 1060 memcpy(req.msg.data + 3, data, length); 1061 1062 return intf->sendrecv(intf, &req); 1063 } 1064 1065 static int 1066 ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data) 1067 { 1068 struct ipmi_rs * rsp; /* ipmi response */ 1069 uint8_t tmpData[DCMI_MAX_BYTE_SIZE]; 1070 int32_t taglength = 0; 1071 uint8_t getlength = 0; 1072 uint8_t offset = 0; 1073 uint8_t i; 1074 1075 /* now let's get the asset tag length */ 1076 taglength = strlen((char *)data); 1077 if (taglength > 64){ 1078 lprintf(LOG_ERR, "\nValue is too long."); 1079 return -1; 1080 } 1081 printf("\n Set Asset Tag: "); 1082 while (taglength) { 1083 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 1084 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 1085 memcpy(tmpData, data + offset, getlength); 1086 rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData); 1087 if (chk_rsp(rsp)) { 1088 return -1; 1089 } 1090 for (i=0; i<getlength; i++) { 1091 printf("%c", tmpData[i]); 1092 } 1093 offset += getlength; 1094 taglength -= getlength; 1095 } 1096 printf("\n"); 1097 return 0; 1098 } 1099 1100 /* Management Controller Identifier String is provided in order to accommodate 1101 * the requirement for the management controllers to identify themselves. 1102 * 1103 * @intf: ipmi interface handler 1104 * @offset: offset to read 1105 * @length: number of bytes to read (16 bytes maximum) 1106 * 1107 * returns ipmi_rs structure 1108 */ 1109 struct ipmi_rs * 1110 ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length) 1111 { 1112 struct ipmi_rq req; /* request data to send to the BMC */ 1113 uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */ 1114 1115 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1116 msg_data[1] = offset; /* offset 0 */ 1117 msg_data[2] = length; /* read one byte */ 1118 1119 memset(&req, 0, sizeof(req)); 1120 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 1121 req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */ 1122 req.msg.data = msg_data; /* msg_data above */ 1123 /* How many times does req.msg.data need to read */ 1124 req.msg.data_len = 3; 1125 return intf->sendrecv(intf, &req); 1126 } 1127 1128 static int 1129 ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf) 1130 { 1131 struct ipmi_rs * rsp; /* ipmi response */ 1132 uint8_t taglength = 0; 1133 uint8_t getlength = 0; 1134 uint8_t offset = 0; 1135 uint8_t i; 1136 1137 /* now let's get the asset tag length */ 1138 rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1); 1139 1140 if (chk_rsp(rsp)) { 1141 return -1; 1142 } 1143 1144 taglength = rsp->data[1]; 1145 1146 printf("\n Get Management Controller Identifier String: "); 1147 while (taglength) { 1148 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 1149 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 1150 rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength); 1151 1152 if (chk_rsp(rsp)) { 1153 return -1; 1154 } 1155 for (i=0; i<getlength; i++) { 1156 printf("%c", rsp->data[i+2]); 1157 } 1158 offset += getlength; 1159 taglength -= getlength; 1160 } 1161 printf("\n"); 1162 return 0; 1163 } 1164 1165 /* Management Controller Identifier String is provided in order to accommodate 1166 * the requirement for the management controllers to identify themselves. 1167 * 1168 * @intf: ipmi interface handler 1169 * @offset: offset to write 1170 * @length: number of bytes to write (16 bytes maximum) 1171 * @data: data to write 1172 * 1173 * returns ipmi_rs structure 1174 */ 1175 struct ipmi_rs * 1176 ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length, 1177 uint8_t *data) 1178 { 1179 struct ipmi_rq req; /* request data to send to the BMC */ 1180 uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */ 1181 1182 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1183 msg_data[1] = offset; /* offset 0 */ 1184 msg_data[2] = length; /* read one byte */ 1185 1186 memset(&req, 0, sizeof(req)); 1187 req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */ 1188 req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */ 1189 req.msg.data = msg_data; /* msg_data above */ 1190 /* How many times does req.msg.data need to read */ 1191 req.msg.data_len = 3 + length; 1192 memcpy(req.msg.data + 3, data, length); 1193 1194 return intf->sendrecv(intf, &req); 1195 } 1196 1197 /* Set Asset Tag command provides ability for the management console to set the 1198 * asset tag as appropriate. Management controller is not responsible for the 1199 * data format used for the Asset Tag once modified by IPDC. 1200 * 1201 * @intf: ipmi interface handler 1202 * 1203 * returns 0 if no failure, -1 with a failure 1204 */ 1205 static int 1206 ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data) 1207 { 1208 struct ipmi_rs * rsp; /* ipmi response */ 1209 uint8_t tmpData[DCMI_MAX_BYTE_SIZE]; 1210 uint8_t taglength = 0; 1211 uint8_t getlength = 0; 1212 uint8_t offset = 0; 1213 uint8_t i; 1214 1215 data += '\0'; 1216 taglength = strlen((char *)data) +1; 1217 1218 if (taglength > 64) { 1219 lprintf(LOG_ERR, "\nValue is too long."); 1220 return -1; 1221 } 1222 1223 printf("\n Set Management Controller Identifier String Command: "); 1224 while (taglength) { 1225 getlength = taglength / DCMI_MAX_BYTE_SIZE ? 1226 DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE; 1227 memcpy(tmpData, data + offset, getlength); 1228 rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData); 1229 /* because after call "Set mc id string" RMCP+ will go down 1230 * we have no "rsp" 1231 */ 1232 if (strncmp(intf->name, "lanplus", 7)) { 1233 if (chk_rsp(rsp)) { 1234 return -1; 1235 } 1236 } 1237 for (i=0; i<getlength; i++) { 1238 printf("%c", tmpData[i]); 1239 } 1240 offset += getlength; 1241 taglength -= getlength; 1242 } 1243 printf("\n"); 1244 return 0; 1245 } 1246 1247 /* Issues a discovery command to see what sensors are available on the target. 1248 * system. 1249 * 1250 * @intf: ipmi interface handler 1251 * @isnsr: entity ID 1252 * @offset: offset (Entity instace start) 1253 * 1254 * returns ipmi_rs structure 1255 */ 1256 struct ipmi_rs * 1257 ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset) 1258 { 1259 struct ipmi_rq req; /* ipmi request struct */ 1260 uint8_t msg_data[5]; /* number of request data bytes */ 1261 1262 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1263 msg_data[1] = 0x01; /* Senser Type = Temp (01h) */ 1264 msg_data[2] = isnsr; /* Sensor Number */ 1265 msg_data[3] = 0x00; /* Entity Instance, set to read all instances */ 1266 msg_data[4] = offset; /* Entity instace start */ 1267 1268 memset(&req, 0, sizeof(req)); 1269 req.msg.netfn = IPMI_NETFN_DCGRP; 1270 req.msg.cmd = IPMI_DCMI_GETSNSR; 1271 req.msg.data = msg_data; /* Contents above */ 1272 req.msg.data_len = 5; /* how many times does req.msg.data need to read */ 1273 1274 return intf->sendrecv(intf, &req); 1275 } 1276 1277 /* DCMI sensor discovery 1278 * Uses the dcmi_discvry_snsr_vals struct to print its string and 1279 * uses the numeric values to request the sensor sdr record id. 1280 * 1281 * @intf: ipmi interface handler 1282 * @isnsr: entity ID 1283 * @ient: sensor entity id 1284 */ 1285 static int 1286 ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr) 1287 { 1288 int i = 0; 1289 struct ipmi_rs * rsp; /* ipmi response */ 1290 uint8_t records = 0; 1291 int8_t instances = 0; 1292 uint8_t offset = 0; 1293 uint16_t record_id = 0; 1294 uint8_t id_buff[16]; /* enough for 8 record IDs */ 1295 rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0); 1296 if (chk_rsp(rsp)) { 1297 return -1; 1298 } 1299 instances = rsp->data[1]; 1300 printf("\n%s: %d temperature sensor%s found:\n", 1301 val2str2(isnsr, dcmi_discvry_snsr_vals), 1302 instances, 1303 (instances > 1) ? "s" : ""); 1304 while(instances > 0) { 1305 ipmi_dcmi_discvry_snsr(intf, isnsr, offset); 1306 if (chk_rsp(rsp)) { 1307 return -1; 1308 } 1309 records = rsp->data[2]; 1310 /* cache the data since it may be destroyed by subsequent 1311 * ipmi_xxx calls 1312 */ 1313 memcpy(id_buff, &rsp->data[3], sizeof (id_buff)); 1314 for (i=0; i<records; i++) { 1315 /* Record ID is in little endian format */ 1316 record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i]; 1317 printf("Record ID 0x%04x: ", record_id); 1318 ipmi_print_sensor_info(intf, record_id); 1319 } 1320 offset += 8; 1321 instances -= records; 1322 } 1323 return 0; 1324 } 1325 /* end sensor discovery */ 1326 1327 /* Power Management get power reading 1328 * 1329 * @intf: ipmi interface handler 1330 */ 1331 static int 1332 ipmi_dcmi_pwr_rd(struct ipmi_intf * intf, uint8_t sample_time) 1333 { 1334 struct ipmi_rs * rsp; 1335 struct ipmi_rq req; 1336 struct power_reading val; 1337 struct tm tm_t; 1338 time_t t; 1339 uint8_t msg_data[4]; /* number of request data bytes */ 1340 memset(&tm_t, 0, sizeof(tm_t)); 1341 memset(&t, 0, sizeof(t)); 1342 1343 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1344 if (sample_time) { 1345 msg_data[1] = 0x02; /* Enhanced Power Statistics */ 1346 msg_data[2] = sample_time; 1347 } else { 1348 msg_data[1] = 0x01; /* Mode Power Status */ 1349 msg_data[2] = 0x00; /* reserved */ 1350 } 1351 msg_data[3] = 0x00; /* reserved */ 1352 1353 memset(&req, 0, sizeof(req)); 1354 req.msg.netfn = IPMI_NETFN_DCGRP; 1355 req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */ 1356 req.msg.data = msg_data; /* msg_data above */ 1357 req.msg.data_len = 4; /* how many times does req.msg.data need to read */ 1358 1359 rsp = intf->sendrecv(intf, &req); 1360 1361 if (chk_rsp(rsp)) { 1362 return -1; 1363 } 1364 /* rsp->data[0] is equal to response data byte 2 in spec */ 1365 /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */ 1366 memcpy(&val, rsp->data, sizeof (val)); 1367 t = val.time_stamp; 1368 gmtime_r(&t, &tm_t); 1369 printf("\n"); 1370 printf(" Instantaneous power reading: %8d Watts\n", 1371 val.curr_pwr); 1372 printf(" Minimum during sampling period: %8d Watts\n", 1373 val.min_sample); 1374 printf(" Maximum during sampling period: %8d Watts\n", 1375 val.max_sample); 1376 printf(" Average power reading over sample period: %8d Watts\n", 1377 val.avg_pwr); 1378 printf(" IPMI timestamp: %s", 1379 asctime(&tm_t)); 1380 printf(" Sampling period: "); 1381 if (sample_time) 1382 printf("%s \n", val2str2(val.sample,dcmi_sampling_vals)); 1383 else 1384 printf("%08u Seconds.\n", val.sample/1000); 1385 printf(" Power reading state is: "); 1386 /* mask the rsp->data so that we only care about bit 6 */ 1387 if((val.state & 0x40) == 0x40) { 1388 printf("activated"); 1389 } else { 1390 printf("deactivated"); 1391 } 1392 printf("\n\n"); 1393 return 0; 1394 } 1395 /* end Power Management get reading */ 1396 1397 1398 /* This is the get thermalpolicy command. 1399 * 1400 * @intf: ipmi interface handler 1401 */ 1402 int 1403 ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID, 1404 uint8_t entityInstance) 1405 { 1406 struct ipmi_rs * rsp; 1407 struct ipmi_rq req; 1408 struct thermal_limit val; 1409 uint8_t msg_data[3]; /* number of request data bytes */ 1410 1411 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1412 msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/ 1413 msg_data[2] = entityInstance; /* Entity Instance */ 1414 1415 memset(&req, 0, sizeof(req)); 1416 req.msg.netfn = IPMI_NETFN_DCGRP; 1417 req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */ 1418 req.msg.data = msg_data; /* msg_data above */ 1419 req.msg.data_len = 3; /* how many times does req.msg.data need to read */ 1420 1421 rsp = intf->sendrecv(intf, &req); 1422 1423 if (chk_rsp(rsp)) { 1424 return -1; 1425 } 1426 /* rsp->data[0] is equal to response data byte 2 in spec */ 1427 memcpy(&val, rsp->data, sizeof (val)); 1428 printf("\n"); 1429 printf(" Persistance flag is: %s\n", 1430 ((val.exceptionActions & 0x80) ? "set" : "notset")); 1431 printf(" Exception Actions, taken if the Temperature Limit exceeded:\n"); 1432 printf(" Hard Power Off system and log event: %s\n", 1433 ((val.exceptionActions & 0x40) ? "active":"inactive")); 1434 printf(" Log event to SEL only: %s\n", 1435 ((val.exceptionActions & 0x20) ? "active":"inactive")); 1436 printf(" Temperature Limit %d degrees\n", 1437 val.tempLimit); 1438 printf(" Exception Time %d seconds\n", 1439 val.exceptionTime); 1440 printf("\n\n"); 1441 return 0; 1442 } 1443 1444 /* This is the set thermalpolicy command. 1445 * 1446 * @intf: ipmi interface handler 1447 */ 1448 int 1449 ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf, 1450 uint8_t entityID, 1451 uint8_t entityInst, 1452 uint8_t persistanceFlag, 1453 uint8_t actionHardPowerOff, 1454 uint8_t actionLogToSEL, 1455 uint8_t tempLimit, 1456 uint8_t samplingTimeLSB, 1457 uint8_t samplingTimeMSB) 1458 { 1459 struct ipmi_rs * rsp; 1460 struct ipmi_rq req; 1461 uint8_t msg_data[7]; /* number of request data bytes */ 1462 1463 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1464 msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/ 1465 msg_data[2] = entityInst; /* Entity Instance */ 1466 /* persistance and actions or disabled if no actions */ 1467 msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) | 1468 ((actionHardPowerOff? 1 : 0) << 6) | 1469 ((actionLogToSEL ? 1 : 0) << 5)); 1470 msg_data[4] = tempLimit; 1471 msg_data[5] = samplingTimeLSB; 1472 msg_data[6] = samplingTimeMSB; 1473 1474 memset(&req, 0, sizeof(req)); 1475 req.msg.netfn = IPMI_NETFN_DCGRP; 1476 /* Get thermal policy reading */ 1477 req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT; 1478 req.msg.data = msg_data; /* msg_data above */ 1479 /* how many times does req.msg.data need to read */ 1480 req.msg.data_len = 7; 1481 1482 rsp = intf->sendrecv(intf, &req); 1483 if (chk_rsp(rsp)) { 1484 return -1; 1485 } 1486 /* rsp->data[0] is equal to response data byte 2 in spec */ 1487 printf("\nThermal policy %d for %0Xh entity successfully set.\n\n", 1488 entityInst, entityID); 1489 return 0; 1490 } 1491 1492 /* This is Get Temperature Readings Command 1493 * 1494 * returns ipmi response structure 1495 * 1496 * @intf: ipmi interface handler 1497 */ 1498 struct ipmi_rs * 1499 ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf, 1500 uint8_t entityID, 1501 uint8_t entityInst, 1502 uint8_t entityInstStart) 1503 { 1504 struct ipmi_rq req; 1505 uint8_t msg_data[5]; /* number of request data bytes */ 1506 1507 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1508 msg_data[1] = 0x01; /* Sensor type */ 1509 msg_data[2] = entityID; /* Entity Instance */ 1510 msg_data[3] = entityInst; 1511 msg_data[4] = entityInstStart; 1512 1513 memset(&req, 0, sizeof(req)); 1514 req.msg.netfn = IPMI_NETFN_DCGRP; 1515 req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */ 1516 req.msg.data = msg_data; /* msg_data above */ 1517 /* how many times does req.msg.data need to read */ 1518 req.msg.data_len = 5; 1519 return intf->sendrecv(intf, &req); 1520 } 1521 1522 static int 1523 ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf) 1524 { 1525 struct ipmi_rs * rsp; 1526 int i,j, tota_inst, get_inst, offset = 0; 1527 /* Print sensor description */ 1528 printf("\n\tEntity ID\t\t\tEntity Instance\t Temp. Readings"); 1529 for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) { 1530 /* get all of the information about this sensor */ 1531 rsp = ipmi_dcmi_get_temp_readings(intf, 1532 dcmi_temp_read_vals[i].val, 0, 0); 1533 if (chk_rsp(rsp)) { 1534 continue; 1535 } 1536 /* Total number of available instances for the Entity ID */ 1537 offset = 0; 1538 tota_inst = rsp->data[1]; 1539 while (tota_inst > 0) { 1540 get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ? 1541 DCMI_MAX_BYTE_TEMP_READ_SIZE : 1542 (tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE)); 1543 rsp = ipmi_dcmi_get_temp_readings(intf, 1544 dcmi_temp_read_vals[i].val, offset, 0); 1545 if (chk_rsp(rsp)) { 1546 continue; 1547 } 1548 /* Number of sets of Temperature Data in this 1549 * response (Max 8 per response) 1550 */ 1551 for (j=0; j < rsp->data[2]*2; j=j+2) { 1552 /* Print Instance temperature info */ 1553 printf("\n%s",dcmi_temp_read_vals[i].desc); 1554 printf("\t\t%i\t\t%c%i C", rsp->data[j+4], 1555 ((rsp->data[j+3]) >> 7) ? 1556 '-' : '+', (rsp->data[j+3] & 127)); 1557 } 1558 offset += get_inst; 1559 tota_inst -= get_inst; 1560 } 1561 } 1562 return 0; 1563 } 1564 1565 /* This is Get DCMI Config Parameters Command 1566 * 1567 * returns ipmi response structure 1568 * 1569 * @intf: ipmi interface handler 1570 */ 1571 struct ipmi_rs * 1572 ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector) 1573 { 1574 struct ipmi_rq req; 1575 uint8_t msg_data[3]; /* number of request data bytes */ 1576 1577 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1578 msg_data[1] = param_selector; /* Parameter selector */ 1579 /* Set Selector. Selects a given set of parameters under a given Parameter 1580 * selector value. 00h if parameter doesn't use a Set Selector. 1581 */ 1582 msg_data[2] = 0x00; 1583 1584 memset(&req, 0, sizeof(req)); 1585 req.msg.netfn = IPMI_NETFN_DCGRP; 1586 req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */ 1587 req.msg.data = msg_data; /* Contents above */ 1588 /* how many times does req.msg.data need to read */ 1589 req.msg.data_len = 3; 1590 return intf->sendrecv(intf, &req); 1591 } 1592 1593 static int 1594 ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf) 1595 { 1596 struct ipmi_rs * rsp; 1597 const int dcmi_conf_params = 5; 1598 int param_selector; 1599 uint16_t tmp_value = 0; 1600 /* We are not interested in parameter 1 which always will return 0 */ 1601 for (param_selector = 2 ; param_selector <= dcmi_conf_params; 1602 param_selector++) { 1603 rsp = ipmi_dcmi_getconfparam(intf, param_selector); 1604 if (chk_rsp(rsp)) { 1605 return -1; 1606 } 1607 /* Time to print what we have got */ 1608 switch(param_selector) { 1609 case 2: 1610 tmp_value = (rsp->data[4])& 1; 1611 printf("\n\tDHCP Discovery method\t: "); 1612 printf("\n\t\tManagement Controller ID String is %s", 1613 tmp_value ? "enabled" : "disabled"); 1614 printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s", 1615 ((rsp->data[4])& 2) ? "enabled" : "disabled" ); 1616 break; 1617 case 3: 1618 printf("\n\tInitial timeout interval\t: %i seconds", 1619 rsp->data[4]); 1620 break; 1621 case 4: 1622 printf("\n\tServer contact timeout interval\t: %i seconds", 1623 rsp->data[4] + (rsp->data[5]<<8)); 1624 break; 1625 case 5: 1626 printf("\n\tServer contact retry interval\t: %i seconds", 1627 rsp->data[4] + (rsp->data[5] << 8)); 1628 break; 1629 default: 1630 printf("\n\tConfiguration Parameter not supported."); 1631 } 1632 } 1633 return 0; 1634 } 1635 1636 /* This is Set DCMI Config Parameters Command 1637 * 1638 * returns ipmi response structure 1639 * 1640 * @intf: ipmi interface handler 1641 */ 1642 struct ipmi_rs * 1643 ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector, 1644 uint16_t value) 1645 { 1646 struct ipmi_rq req; 1647 uint8_t msg_data[5]; /* number of request data bytes */ 1648 1649 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1650 msg_data[1] = param_selector; /* Parameter selector */ 1651 /* Set Selector (use 00h for parameters that only have one set). */ 1652 msg_data[2] = 0x00; 1653 1654 if (param_selector > 3) { 1655 /* One bite more */ 1656 msg_data[3] = value & 0xFF; 1657 msg_data[4] = value >> 8; 1658 } else { 1659 msg_data[3] = value; 1660 } 1661 1662 memset(&req, 0, sizeof(req)); 1663 req.msg.netfn = IPMI_NETFN_DCGRP; 1664 req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */ 1665 req.msg.data = msg_data; /* Contents above */ 1666 if (param_selector > 3) { 1667 /* One bite more */ 1668 /* how many times does req.msg.data need to read */ 1669 req.msg.data_len = 5; 1670 } else { 1671 /* how many times does req.msg.data need to read */ 1672 req.msg.data_len = 4; 1673 } 1674 return intf->sendrecv(intf, &req); 1675 } 1676 1677 /* Power Management get limit ipmi response 1678 * 1679 * This function returns the currently set power management settings as an 1680 * ipmi response structure. The reason it returns in the rsp struct is so 1681 * that it can be used in the set limit [slimit()] function to populate 1682 * un-changed or un-edited values. 1683 * 1684 * returns ipmi response structure 1685 * 1686 * @intf: ipmi interface handler 1687 */ 1688 struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf) 1689 { 1690 struct ipmi_rq req; 1691 uint8_t msg_data[3]; /* number of request data bytes */ 1692 1693 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1694 msg_data[1] = 0x00; /* reserved */ 1695 msg_data[2] = 0x00; /* reserved */ 1696 1697 memset(&req, 0, sizeof(req)); 1698 req.msg.netfn = IPMI_NETFN_DCGRP; 1699 req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */ 1700 req.msg.data = msg_data; /* Contents above */ 1701 /* how many times does req.msg.data need to read */ 1702 req.msg.data_len = 3; 1703 1704 return intf->sendrecv(intf, &req); 1705 } 1706 /* end Power Management get limit response */ 1707 1708 /* Power Management print the get limit command 1709 * 1710 * This function calls the get limit function that returns an ipmi response. 1711 * 1712 * returns 0 else 1 with error 1713 * @intf: ipmi interface handler 1714 */ 1715 static int 1716 ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf) 1717 { 1718 struct ipmi_rs * rsp; 1719 struct power_limit val; 1720 uint8_t realCc = 0xff; 1721 1722 rsp = ipmi_dcmi_pwr_glimit(intf); 1723 /* rsp can be a null so check response before any operation 1724 * on it to avoid sig segv 1725 */ 1726 if (rsp != NULL) { 1727 realCc = rsp->ccode; 1728 GOOD_PWR_GLIMIT_CCODE(rsp->ccode); 1729 } 1730 if (chk_rsp(rsp)) { 1731 return -1; 1732 } 1733 /* rsp->data[0] is equal to response data byte 2 in spec */ 1734 /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */ 1735 memcpy(&val, rsp->data, sizeof (val)); 1736 printf("\n Current Limit State: %s\n", 1737 (realCc == 0) ? 1738 "Power Limit Active" : "No Active Power Limit"); 1739 printf(" Exception actions: %s\n", 1740 val2str2(val.action, dcmi_pwrmgmt_get_action_vals)); 1741 printf(" Power Limit: %i Watts\n", val.limit); 1742 printf(" Correction time: %i milliseconds\n", val.correction); 1743 printf(" Sampling period: %i seconds\n", val.sample); 1744 printf("\n"); 1745 return 0; 1746 } 1747 /* end print get limit */ 1748 1749 /* Power Management set limit 1750 * 1751 * Undocumented bounds: 1752 * Power limit: 0 - 0xFFFF 1753 * Correction period 5750ms to 28751ms or 0x1676 to 0x704F 1754 * sample period: 3 sec to 65 sec and 69+ 1755 * 1756 * @intf: ipmi interface handler 1757 * @option: Power option to change 1758 * @value: Value of the desired change 1759 */ 1760 static int 1761 ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option, 1762 const char * value) 1763 { 1764 struct ipmi_rs * rsp; /* ipmi response */ 1765 struct ipmi_rq req; /* ipmi request (to send) */ 1766 struct power_limit val; 1767 uint8_t msg_data[15]; /* number of request data bytes */ 1768 uint32_t lvalue = 0; 1769 1770 rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */ 1771 # if 0 1772 { 1773 unsigned char counter = 0; 1774 printf("DATA (%d): ", rsp->data_len); 1775 for(counter = 0; counter < rsp->data_len; counter ++) { 1776 printf("%02X ", rsp->data[counter]); 1777 } 1778 printf("\n"); 1779 } 1780 # endif 1781 /* rsp can be a null so check response before any operation on it to 1782 * avoid sig segv 1783 */ 1784 if (rsp != NULL) { 1785 GOOD_PWR_GLIMIT_CCODE(rsp->ccode); 1786 } 1787 if (chk_rsp(rsp)) { 1788 return -1; 1789 } 1790 memcpy(&val, rsp->data, sizeof (val)); 1791 /* same as above; sets the values of the val struct 1792 * DCMI group ID * 1793 * val.grp_id = rsp->data[0]; 1794 * exception action * 1795 * val.action = rsp->data[3]; * 1796 * 1797 * power limit in Watts * 1798 * store 16 bits of the rsp from the 4th entity * 1799 * val.limit = *(uint16_t*)(&rsp->data[4]); 1800 * correction period in mS * 1801 * store 32 bits of the rsp from the 6th entity * 1802 * val.correction = *(uint32_t*)(&rsp->data[6]); 1803 * store 16 bits of the rsp from the 12th entity * 1804 * sample period in seconds * 1805 * val.sample = *(uint16_t*)(&rsp->data[12]); 1806 */ 1807 lprintf(LOG_INFO, 1808 "DCMI IN Limit=%d Correction=%d Action=%d Sample=%d\n", 1809 val.limit, val.correction, val.action, val.sample); 1810 switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) { 1811 case 0x00: 1812 /* action */ 1813 switch (str2val2(value, dcmi_pwrmgmt_action_vals)) { 1814 case 0x00: 1815 /* no_action */ 1816 val.action = 0; 1817 break; 1818 case 0x01: 1819 /* power_off */ 1820 val.action = 1; 1821 break; 1822 case 0x02: 1823 /* OEM reserved action */ 1824 val.action = 0x02; 1825 break; 1826 case 0x03: 1827 /* OEM reserved action */ 1828 val.action = 0x03; 1829 break; 1830 case 0x04: 1831 /* OEM reserved action */ 1832 val.action = 0x04; 1833 break; 1834 case 0x05: 1835 /* OEM reserved action */ 1836 val.action = 0x05; 1837 break; 1838 case 0x06: 1839 /* OEM reserved action */ 1840 val.action = 0x06; 1841 break; 1842 case 0x07: 1843 /* OEM reserved action */ 1844 val.action = 0x07; 1845 break; 1846 case 0x08: 1847 /* OEM reserved action */ 1848 val.action = 0x08; 1849 break; 1850 case 0x09: 1851 /* OEM reserved action */ 1852 val.action = 0x09; 1853 break; 1854 case 0x0a: 1855 /* OEM reserved action */ 1856 val.action = 0x0a; 1857 break; 1858 case 0x0b: 1859 /* OEM reserved action */ 1860 val.action = 0x0b; 1861 break; 1862 case 0x0c: 1863 /* OEM reserved action */ 1864 val.action = 0x0c; 1865 break; 1866 case 0x0d: 1867 /* OEM reserved action */ 1868 val.action = 0x0d; 1869 break; 1870 case 0x0e: 1871 /* OEM reserved action */ 1872 val.action = 0x0e; 1873 break; 1874 case 0x0f: 1875 /* OEM reserved action */ 1876 val.action = 0x0f; 1877 break; 1878 case 0x10: 1879 /* OEM reserved action */ 1880 val.action = 0x10; 1881 break; 1882 case 0x11: 1883 /* sel_logging*/ 1884 val.action = 0x11; 1885 break; 1886 case 0xFF: 1887 /* error - not a string we knew what to do with */ 1888 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1889 option, value); 1890 return -1; 1891 } 1892 break; 1893 case 0x01: 1894 /* limit */ 1895 if (str2uint(value, &lvalue) != 0) { 1896 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1897 option, value); 1898 return (-1); 1899 } 1900 val.limit = *(uint16_t*)(&lvalue); 1901 break; 1902 case 0x02: 1903 /* correction */ 1904 if (str2uint(value, &lvalue) != 0) { 1905 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1906 option, value); 1907 return (-1); 1908 } 1909 val.correction = *(uint32_t*)(&lvalue); 1910 break; 1911 case 0x03: 1912 /* sample */ 1913 if (str2uint(value, &lvalue) != 0) { 1914 lprintf(LOG_ERR, "Given %s '%s' is invalid.", 1915 option, value); 1916 return (-1); 1917 } 1918 val.sample = *(uint16_t*)(&lvalue); 1919 break; 1920 case 0xff: 1921 /* no valid options */ 1922 return -1; 1923 } 1924 lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample); 1925 1926 msg_data[0] = val.grp_id; /* Group Extension Identification */ 1927 msg_data[1] = 0x00; /* reserved */ 1928 msg_data[2] = 0x00; /* reserved */ 1929 msg_data[3] = 0x00; /* reserved */ 1930 msg_data[4] = val.action; /* exception action; 0x00 disables it */ 1931 1932 /* fill msg_data[5] with the first 16 bits of val.limit */ 1933 *(uint16_t*)(&msg_data[5]) = val.limit; 1934 /* msg_data[5] = 0xFF; 1935 * msg_data[6] = 0xFF; 1936 */ 1937 /* fill msg_data[7] with the first 32 bits of val.correction */ 1938 *(uint32_t*)(&msg_data[7]) = val.correction; 1939 /* msg_data[7] = 0x76; 1940 * msg_data[8] = 0x16; 1941 * msg_data[9] = 0x00; 1942 * msg_data[10] = 0x00; 1943 */ 1944 msg_data[11] = 0x00; /* reserved */ 1945 msg_data[12] = 0x00; /* reserved */ 1946 /* fill msg_data[13] with the first 16 bits of val.sample */ 1947 *(uint16_t*)(&msg_data[13]) = val.sample; 1948 /* msg_data[13] = 0x03; */ 1949 memset(&req, 0, sizeof(req)); 1950 req.msg.netfn = IPMI_NETFN_DCGRP; 1951 req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */ 1952 req.msg.data = msg_data; /* Contents above */ 1953 /* how many times does req.msg.data need to read */ 1954 req.msg.data_len = 15; 1955 1956 rsp = intf->sendrecv(intf, &req); 1957 1958 if (chk_rsp(rsp)) { 1959 return -1; 1960 } 1961 return 0; 1962 } 1963 /* end Power Management set limit */ 1964 1965 /* Power Management activate deactivate 1966 * 1967 * @intf: ipmi interface handler 1968 * @option: uint8_t - 0 to deactivate or 1 to activate 1969 */ 1970 static int 1971 ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option) 1972 { 1973 struct ipmi_rs * rsp; 1974 struct ipmi_rq req; 1975 uint8_t msg_data[4]; /* number of request data bytes */ 1976 1977 msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ 1978 msg_data[1] = option; /* 0 = Deactivate 1 = Activate */ 1979 msg_data[2] = 0x00; /* reserved */ 1980 msg_data[3] = 0x00; /* reserved */ 1981 1982 memset(&req, 0, sizeof(req)); 1983 req.msg.netfn = IPMI_NETFN_DCGRP; 1984 req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */ 1985 req.msg.data = msg_data; /* Contents above */ 1986 req.msg.data_len = 4; /* how mant times does req.msg.data need to read */ 1987 1988 rsp = intf->sendrecv(intf, &req); 1989 if (chk_rsp(rsp)) { 1990 return -1; 1991 } 1992 printf("\n Power limit successfully "); 1993 if (option == 0x00) { 1994 printf("deactivated"); 1995 } else { 1996 printf("activated"); 1997 } 1998 printf("\n"); 1999 return 0; 2000 } 2001 /* end power management activate/deactivate */ 2002 2003 /* Node Manager discover */ 2004 static int 2005 _ipmi_nm_discover(struct ipmi_intf * intf, struct nm_discover *disc) 2006 { 2007 struct ipmi_rq req; /* request data to send to the BMC */ 2008 struct ipmi_rs *rsp; 2009 uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */ 2010 2011 msg_data[0] = 0x57; 2012 msg_data[1] = 1; 2013 msg_data[2] = 0; 2014 memset(&req, 0, sizeof(req)); 2015 req.msg.netfn = IPMI_NETFN_OEM; 2016 req.msg.cmd = IPMI_NM_GET_VERSION; 2017 req.msg.data = msg_data; 2018 req.msg.data_len = 3; 2019 rsp = intf->sendrecv(intf, &req); 2020 if (chk_nm_rsp(rsp)) { 2021 return -1; 2022 } 2023 memcpy(disc, rsp->data, sizeof (struct nm_discover)); 2024 return 0; 2025 } 2026 /* Get NM capabilities 2027 * 2028 * This function returns the available capabilities of the platform. 2029 * 2030 * returns success/failure 2031 * 2032 * @intf: ipmi interface handler 2033 * @caps: fills in capability struct 2034 */ 2035 static int 2036 _ipmi_nm_getcapabilities(struct ipmi_intf * intf, uint8_t domain, uint8_t trigger, struct nm_capability *caps) 2037 { 2038 struct ipmi_rq req; /* request data to send to the BMC */ 2039 struct ipmi_rs *rsp; 2040 uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */ 2041 2042 msg_data[0] = 0x57; 2043 msg_data[1] = 1; 2044 msg_data[2] = 0; 2045 msg_data[3] = domain; 2046 msg_data[4] = trigger; /* power control policy or trigger */ 2047 memset(&req, 0, sizeof(req)); 2048 req.msg.netfn = IPMI_NETFN_OEM; 2049 req.msg.cmd = IPMI_NM_GET_CAP; 2050 req.msg.data = msg_data; 2051 req.msg.data_len = 5; 2052 rsp = intf->sendrecv(intf, &req); 2053 if (chk_nm_rsp(rsp)) { 2054 return -1; 2055 } 2056 memcpy(caps, rsp->data, sizeof (struct nm_capability)); 2057 return 0; 2058 } 2059 2060 static int 2061 _ipmi_nm_get_policy(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, struct nm_get_policy *policy) 2062 { 2063 struct ipmi_rq req; /* request data to send to the BMC */ 2064 struct ipmi_rs *rsp; 2065 uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */ 2066 2067 msg_data[0] = 0x57; 2068 msg_data[1] = 1; 2069 msg_data[2] = 0; 2070 msg_data[3] = domain; 2071 msg_data[4] = policy_id; 2072 memset(&req, 0, sizeof(req)); 2073 req.msg.netfn = IPMI_NETFN_OEM; 2074 req.msg.cmd = IPMI_NM_GET_POLICY; 2075 req.msg.data = msg_data; 2076 req.msg.data_len = 5; 2077 rsp = intf->sendrecv(intf, &req); 2078 if (chk_nm_rsp(rsp)) { 2079 return -1; 2080 } 2081 memcpy(policy, rsp->data, sizeof (struct nm_get_policy)); 2082 return 0; 2083 } 2084 static int 2085 _ipmi_nm_set_policy(struct ipmi_intf * intf, struct nm_policy *policy) 2086 { 2087 struct ipmi_rq req; /* request data to send to the BMC */ 2088 struct ipmi_rs *rsp; 2089 2090 memset(&req, 0, sizeof(req)); 2091 req.msg.netfn = IPMI_NETFN_OEM; 2092 req.msg.cmd = IPMI_NM_SET_POLICY; 2093 req.msg.data = (uint8_t *)policy; 2094 req.msg.data_len = sizeof(struct nm_policy); 2095 policy->intel_id[0] = 0x57; policy->intel_id[1] =1; policy->intel_id[2] =0; 2096 rsp = intf->sendrecv(intf, &req); 2097 if (chk_nm_rsp(rsp)) { 2098 return -1; 2099 } 2100 return 0; 2101 } 2102 2103 static int 2104 _ipmi_nm_policy_limiting(struct ipmi_intf * intf, uint8_t domain) 2105 { 2106 struct ipmi_rq req; /* request data to send to the BMC */ 2107 struct ipmi_rs *rsp; 2108 uint8_t msg_data[4]; /* 'raw' data to be sent to the BMC */ 2109 2110 memset(&req, 0, sizeof(req)); 2111 req.msg.netfn = IPMI_NETFN_OEM; 2112 req.msg.cmd = IPMI_NM_LIMITING; 2113 msg_data[0] = 0x57; 2114 msg_data[1] = 1; 2115 msg_data[2] = 0; 2116 msg_data[3] = domain; 2117 req.msg.data = msg_data; 2118 req.msg.data_len = 4; 2119 rsp = intf->sendrecv(intf, &req); 2120 /* check for special case error of no policy is limiting */ 2121 if (rsp && (rsp->ccode == 0xA1)) 2122 return 0x80; 2123 else if (chk_nm_rsp(rsp)) 2124 return -1; 2125 return rsp->data[0]; 2126 } 2127 2128 static int 2129 _ipmi_nm_control(struct ipmi_intf * intf, uint8_t scope, uint8_t domain, uint8_t policy_id) 2130 { 2131 struct ipmi_rq req; /* request data to send to the BMC */ 2132 struct ipmi_rs *rsp; 2133 uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */ 2134 2135 msg_data[0] = 0x57; 2136 msg_data[1] = 1; 2137 msg_data[2] = 0; 2138 msg_data[3] = scope; 2139 msg_data[4] = domain; 2140 msg_data[5] = policy_id; 2141 memset(&req, 0, sizeof(req)); 2142 req.msg.netfn = IPMI_NETFN_OEM; 2143 req.msg.cmd = IPMI_NM_POLICY_CTL; 2144 req.msg.data = msg_data; 2145 req.msg.data_len = 6; 2146 rsp = intf->sendrecv(intf, &req); 2147 if (chk_nm_rsp(rsp)) { 2148 return -1; 2149 } 2150 return 0; 2151 } 2152 2153 /* Get NM statistics 2154 * 2155 * This function returns the statistics 2156 * 2157 * returns success/failure 2158 * 2159 * @intf: ipmi interface handler 2160 * @selector: Parameter selector 2161 */ 2162 static int 2163 _ipmi_nm_statistics(struct ipmi_intf * intf, uint8_t mode, uint8_t domain, uint8_t policy_id, struct nm_statistics *caps) 2164 { 2165 struct ipmi_rq req; /* request data to send to the BMC */ 2166 struct ipmi_rs *rsp; 2167 uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */ 2168 2169 msg_data[0] = 0x57; 2170 msg_data[1] = 1; 2171 msg_data[2] = 0; 2172 msg_data[3] = mode; 2173 msg_data[4] = domain; 2174 msg_data[5] = policy_id; 2175 memset(&req, 0, sizeof(req)); 2176 req.msg.netfn = IPMI_NETFN_OEM; 2177 req.msg.cmd = IPMI_NM_GET_STATS; 2178 req.msg.data = msg_data; 2179 req.msg.data_len = 6; 2180 rsp = intf->sendrecv(intf, &req); 2181 if (chk_nm_rsp(rsp)) { 2182 return -1; 2183 } 2184 memcpy(caps, rsp->data, sizeof (struct nm_statistics)); 2185 return 0; 2186 } 2187 2188 static int 2189 _ipmi_nm_reset_stats(struct ipmi_intf * intf, uint8_t mode, uint8_t domain, uint8_t policy_id) 2190 { 2191 struct ipmi_rq req; /* request data to send to the BMC */ 2192 struct ipmi_rs *rsp; 2193 uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */ 2194 2195 msg_data[0] = 0x57; 2196 msg_data[1] = 1; 2197 msg_data[2] = 0; 2198 msg_data[3] = mode; 2199 msg_data[4] = domain; 2200 msg_data[5] = policy_id; 2201 memset(&req, 0, sizeof(req)); 2202 req.msg.netfn = IPMI_NETFN_OEM; 2203 req.msg.cmd = IPMI_NM_RESET_STATS; 2204 req.msg.data = msg_data; 2205 req.msg.data_len = 6; 2206 rsp = intf->sendrecv(intf, &req); 2207 if (chk_nm_rsp(rsp)) { 2208 return -1; 2209 } 2210 return 0; 2211 } 2212 2213 static int 2214 _nm_set_range(struct ipmi_intf * intf, uint8_t domain, uint16_t minimum, uint16_t maximum) 2215 { 2216 struct ipmi_rq req; /* request data to send to the BMC */ 2217 struct ipmi_rs *rsp; 2218 uint8_t msg_data[8]; /* 'raw' data to be sent to the BMC */ 2219 2220 msg_data[0] = 0x57; 2221 msg_data[1] = 1; 2222 msg_data[2] = 0; 2223 msg_data[3] = domain; 2224 msg_data[4] = minimum & 0xFF; 2225 msg_data[5] = minimum >> 8; 2226 msg_data[6] = maximum & 0xFF; 2227 msg_data[7] = maximum >> 8; 2228 memset(&req, 0, sizeof(req)); 2229 req.msg.netfn = IPMI_NETFN_OEM; 2230 req.msg.cmd = IPMI_NM_SET_POWER; 2231 req.msg.data = msg_data; 2232 req.msg.data_len = 8; 2233 rsp = intf->sendrecv(intf, &req); 2234 if (chk_nm_rsp(rsp)) { 2235 return -1; 2236 } 2237 return 0; 2238 } 2239 2240 static int 2241 _ipmi_nm_get_alert(struct ipmi_intf * intf, struct nm_set_alert *alert) 2242 { 2243 struct ipmi_rq req; /* request data to send to the BMC */ 2244 struct ipmi_rs *rsp; 2245 uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */ 2246 2247 msg_data[0] = 0x57; 2248 msg_data[1] = 1; 2249 msg_data[2] = 0; 2250 memset(&req, 0, sizeof(req)); 2251 req.msg.netfn = IPMI_NETFN_OEM; 2252 req.msg.cmd = IPMI_NM_GET_ALERT_DS; 2253 req.msg.data = msg_data; 2254 req.msg.data_len = 3; 2255 rsp = intf->sendrecv(intf, &req); 2256 if (chk_nm_rsp(rsp)) { 2257 return -1; 2258 } 2259 memcpy(alert, rsp->data, sizeof (struct nm_set_alert)); 2260 return 0; 2261 } 2262 2263 static int 2264 _ipmi_nm_set_alert(struct ipmi_intf * intf, struct nm_set_alert *alert) 2265 { 2266 struct ipmi_rq req; /* request data to send to the BMC */ 2267 struct ipmi_rs *rsp; 2268 uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */ 2269 2270 msg_data[0] = 0x57; 2271 msg_data[1] = 1; 2272 msg_data[2] = 0; 2273 msg_data[3] = alert->chan; 2274 msg_data[4] = alert->dest; 2275 msg_data[5] = alert->string; 2276 memset(&req, 0, sizeof(req)); 2277 req.msg.netfn = IPMI_NETFN_OEM; 2278 req.msg.cmd = IPMI_NM_SET_ALERT_DS; 2279 req.msg.data = msg_data; 2280 req.msg.data_len = 6; 2281 rsp = intf->sendrecv(intf, &req); 2282 if (chk_nm_rsp(rsp)) { 2283 return -1; 2284 } 2285 return 0; 2286 } 2287 2288 /* 2289 * 2290 * get alert threshold values. 2291 * 2292 * the list pointer is assumed to point to an array of 16 short integers. 2293 * This array is filled in for valid thresholds returned. 2294 */ 2295 static int 2296 _ipmi_nm_get_thresh(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, uint16_t *list) 2297 { 2298 struct ipmi_rq req; /* request data to send to the BMC */ 2299 struct ipmi_rs *rsp; 2300 uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */ 2301 2302 msg_data[0] = 0x57; 2303 msg_data[1] = 1; 2304 msg_data[2] = 0; 2305 msg_data[3] = domain; 2306 msg_data[4] = policy_id; 2307 memset(&req, 0, sizeof(req)); 2308 req.msg.netfn = IPMI_NETFN_OEM; 2309 req.msg.cmd = IPMI_NM_GET_ALERT_TH; 2310 req.msg.data = msg_data; 2311 req.msg.data_len = 5; 2312 rsp = intf->sendrecv(intf, &req); 2313 if (chk_nm_rsp(rsp)) { 2314 return -1; 2315 } 2316 if (rsp->data[3] > 0) 2317 *list++ = (rsp->data[5] << 8) | rsp->data[4]; 2318 if (rsp->data[3] > 1) 2319 *list++ = (rsp->data[7] << 8) | rsp->data[6]; 2320 if (rsp->data[3] > 2) 2321 *list = (rsp->data[9] << 8) | rsp->data[8]; 2322 return 0; 2323 } 2324 2325 static int 2326 _ipmi_nm_set_thresh(struct ipmi_intf * intf, struct nm_thresh * thresh) 2327 { 2328 struct ipmi_rq req; /* request data to send to the BMC */ 2329 struct ipmi_rs *rsp; 2330 uint8_t msg_data[IPMI_NM_SET_THRESH_LEN]; /* 'raw' data to be sent to the BMC */ 2331 2332 memset(&msg_data, 0, sizeof(msg_data)); 2333 msg_data[0] = 0x57; 2334 msg_data[1] = 1; 2335 msg_data[2] = 0; 2336 msg_data[3] = thresh->domain; 2337 msg_data[4] = thresh->policy_id; 2338 msg_data[5] = thresh->count; 2339 if (thresh->count > 0) { 2340 msg_data[7] = thresh->thresholds[0] >> 8; 2341 msg_data[6] = thresh->thresholds[0] & 0xFF; 2342 } 2343 if (thresh->count > 1) { 2344 msg_data[9] = thresh->thresholds[1] >> 8; 2345 msg_data[8] = thresh->thresholds[1] & 0xFF; 2346 } 2347 if (thresh->count > 2) { 2348 msg_data[11] = thresh->thresholds[2] >> 8; 2349 msg_data[10] = thresh->thresholds[2] & 0xFF; 2350 } 2351 memset(&req, 0, sizeof(req)); 2352 req.msg.netfn = IPMI_NETFN_OEM; 2353 req.msg.cmd = IPMI_NM_SET_ALERT_TH; 2354 req.msg.data = msg_data; 2355 req.msg.data_len = 6 + (thresh->count * 2); 2356 rsp = intf->sendrecv(intf, &req); 2357 if (chk_nm_rsp(rsp)) { 2358 return -1; 2359 } 2360 return 0; 2361 } 2362 2363 /* 2364 * 2365 * get suspend periods 2366 * 2367 */ 2368 static int 2369 _ipmi_nm_get_suspend(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, int *count, struct nm_period *periods) 2370 { 2371 struct ipmi_rq req; /* request data to send to the BMC */ 2372 struct ipmi_rs *rsp; 2373 uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */ 2374 int i; 2375 2376 msg_data[0] = 0x57; 2377 msg_data[1] = 1; 2378 msg_data[2] = 0; 2379 msg_data[3] = domain; 2380 msg_data[4] = policy_id; 2381 memset(&req, 0, sizeof(req)); 2382 req.msg.netfn = IPMI_NETFN_OEM; 2383 req.msg.cmd = IPMI_NM_GET_SUSPEND; 2384 req.msg.data = msg_data; 2385 req.msg.data_len = 5; 2386 rsp = intf->sendrecv(intf, &req); 2387 if (chk_nm_rsp(rsp)) { 2388 return -1; 2389 } 2390 *count = rsp->data[3]; 2391 for (i = 0; i < rsp->data[3]; i += 3, periods++) { 2392 periods->start = rsp->data[4+i]; 2393 periods->stop = rsp->data[5+i]; 2394 periods->repeat = rsp->data[6+i]; 2395 } 2396 return 0; 2397 } 2398 2399 static int 2400 _ipmi_nm_set_suspend(struct ipmi_intf * intf, struct nm_suspend *suspend) 2401 { 2402 struct ipmi_rq req; /* request data to send to the BMC */ 2403 struct ipmi_rs *rsp; 2404 uint8_t msg_data[21]; /* 6 control bytes + 5 suspend periods, 3 bytes per period */ 2405 struct nm_period *periods; 2406 int i; 2407 2408 msg_data[0] = 0x57; 2409 msg_data[1] = 1; 2410 msg_data[2] = 0; 2411 msg_data[3] = suspend->domain; 2412 msg_data[4] = suspend->policy_id; 2413 msg_data[5] = suspend->count; 2414 for (i = 0, periods = &suspend->period[0]; i < (suspend->count*3); i += 3, periods++) { 2415 msg_data[6+i] = periods->start; 2416 msg_data[7+i] = periods->stop; 2417 msg_data[8+i] = periods->repeat; 2418 } 2419 memset(&req, 0, sizeof(req)); 2420 req.msg.data_len = 6 + (suspend->count*3); 2421 req.msg.netfn = IPMI_NETFN_OEM; 2422 req.msg.cmd = IPMI_NM_SET_SUSPEND; 2423 req.msg.data = msg_data; 2424 rsp = intf->sendrecv(intf, &req); 2425 if (chk_nm_rsp(rsp)) { 2426 return -1; 2427 } 2428 return 0; 2429 } 2430 2431 static int 2432 ipmi_nm_getcapabilities(struct ipmi_intf * intf, int argc, char **argv) 2433 { 2434 uint8_t option; 2435 uint8_t domain = 0; /* default domain of platform */ 2436 uint8_t trigger = 0; /* default power policy (no trigger) */ 2437 struct nm_capability caps; 2438 2439 while (--argc > 0) { 2440 argv++; 2441 if (argv[0] == NULL) break; 2442 if ((option = str2val2(argv[0], nm_capability_opts)) == 0xFF) { 2443 print_strs(nm_capability_opts, "Capability commands", LOG_ERR, 0); 2444 return -1; 2445 } 2446 switch (option) { 2447 case 0x01: /* get domain scope */ 2448 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 2449 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2450 return -1; 2451 } 2452 break; 2453 case 0x02: /* Inlet */ 2454 trigger = 1; 2455 break; 2456 case 0x03: /* Missing power reading */ 2457 trigger = 2; 2458 break; 2459 case 0x04: /* Time after host reset */ 2460 trigger = 3; 2461 break; 2462 case 0x05: /* Boot time policy */ 2463 trigger = 4; 2464 break; 2465 default: 2466 break; 2467 } 2468 argc--; 2469 argv++; 2470 } 2471 trigger |= 0x10; 2472 memset(&caps, 0, sizeof(caps)); 2473 if (_ipmi_nm_getcapabilities(intf, domain, trigger, &caps)) 2474 return -1; 2475 if (csv_output) { 2476 printf("%d,%u,%u,%u,%u,%u,%u,%s\n", 2477 caps.max_settings, caps.max_value,caps.min_value, 2478 caps.min_corr/1000, caps.max_corr/1000, 2479 caps.min_stats, caps.max_stats, 2480 val2str2(caps.scope&0xF, nm_domain_vals)); 2481 return 0; 2482 } 2483 printf(" power policies:\t\t%d\n", caps.max_settings); 2484 switch (trigger&0xF) { 2485 case 0: /* power */ 2486 printf(" max_power\t\t%7u Watts\n min_power\t\t%7u Watts\n", 2487 caps.max_value, caps.min_value); 2488 break; 2489 case 1: /* Inlet */ 2490 printf(" max_temp\t\t%7u C\n min_temp\t\t%7u C\n", 2491 caps.max_value, caps.min_value); 2492 break; 2493 case 2: /* Missing reading time */ 2494 case 3: /* Time after host reset */ 2495 printf(" max_time\t\t%7u Secs\n min_time\t\t%7u Secs\n", 2496 caps.max_value/10, caps.min_value/10); 2497 break; 2498 case 4: /* boot time policy does not use these values */ 2499 default: 2500 break; 2501 } 2502 printf(" min_corr\t\t%7u secs\n max_corr\t\t%7u secs\n", 2503 caps.min_corr/1000, caps.max_corr/1000); 2504 printf(" min_stats\t\t%7u secs\n max_stats\t\t%7u secs\n", 2505 caps.min_stats, caps.max_stats); 2506 printf(" domain scope:\t%s\n", val2str2(caps.scope&0xF, nm_domain_vals)); 2507 return 0; 2508 } 2509 2510 static int 2511 ipmi_nm_get_policy(struct ipmi_intf * intf, int argc, char **argv) 2512 { 2513 uint8_t option; 2514 uint8_t domain = 0; /* default domain of platform */ 2515 uint8_t policy_id = -1; 2516 struct nm_get_policy policy; 2517 2518 memset(&policy, 0, sizeof(policy)); 2519 2520 while (--argc) { 2521 argv++; 2522 if (argv[0] == NULL) break; 2523 if ((option = str2val2(argv[0], nm_policy_options)) == 0xFF) { 2524 print_strs(nm_policy_options, "Get Policy commands", LOG_ERR, 0); 2525 return -1; 2526 } 2527 switch (option) { 2528 case 0x03: /* get domain scope */ 2529 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 2530 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2531 return -1; 2532 } 2533 policy.domain |= domain & 0xF; 2534 break; 2535 case 0x0B: /* policy id */ 2536 if (str2uchar(argv[1], &policy_id) < 0) { 2537 lprintf(LOG_ERR," Policy ID must be a positive integer 0-7.\n"); 2538 return -1; 2539 } 2540 break; 2541 default: 2542 printf(" Unknown command 0x%x, skipping.\n", option); 2543 break; 2544 } 2545 argc--; 2546 argv++; 2547 } 2548 if (policy_id == 0xFF) { 2549 print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0); 2550 return -1; 2551 } 2552 if (_ipmi_nm_get_policy(intf, policy.domain, policy_id, &policy)) 2553 return -1; 2554 if (csv_output) { 2555 printf("%s,0x%x,%s,%s,%s,%u,%u,%u,%u,%s\n", 2556 val2str2(policy.domain&0xF, nm_domain_vals), 2557 policy.domain, 2558 (policy.policy_type & 0x10) ? "power" : "nopower ", 2559 val2str2(policy.policy_type & 0xF, nm_policy_type_vals), 2560 val2str2(policy.policy_exception, nm_exception), 2561 policy.policy_limits, 2562 policy.corr_time, 2563 policy.trigger_limit, 2564 policy.stats_period, 2565 policy.policy_type & 0x80 ? "volatile" : "non-volatile"); 2566 return 0; 2567 } 2568 printf(" Power domain: %s\n", 2569 val2str2(policy.domain&0xF, nm_domain_vals)); 2570 printf(" Policy is %s %s%s%s\n", 2571 policy.domain&0x10 ? "enabled" : "not enabled", 2572 policy.domain&0x20 ? "per Domain " : "", 2573 policy.domain&0x40 ? "Globally " : "", 2574 policy.domain&0x80 ? "via DCMI api " : ""); 2575 printf(" Policy is %sa power control type.\n", (policy.policy_type & 0x10) ? "" : "not "); 2576 printf(" Policy Trigger Type: %s\n", 2577 val2str2(policy.policy_type & 0xF, nm_policy_type_vals)); 2578 printf(" Correction Aggressiveness: %s\n", 2579 val2str2((policy.policy_type>> 5) & 0x3, nm_correction_vals)); 2580 printf(" Policy Exception Actions: %s\n", 2581 val2str2(policy.policy_exception, nm_exception)); 2582 printf(" Power Limit: %u Watts\n", 2583 policy.policy_limits); 2584 printf(" Correction Time Limit: %u milliseconds\n", 2585 policy.corr_time); 2586 printf(" Trigger Limit: %u units\n", 2587 policy.trigger_limit); 2588 printf(" Statistics Reporting Period: %u seconds\n", 2589 policy.stats_period); 2590 printf(" Policy retention: %s\n", 2591 policy.policy_type & 0x80 ? "volatile" : "non-volatile"); 2592 if ( (policy_id == 0) && ((policy.domain & 0xf) == 0x3) ) 2593 printf(" HW Prot Power domain: %s\n", 2594 policy.policy_type & 0x80 ? "Secondary" : "Primary"); 2595 return 0; 2596 } 2597 2598 static int 2599 ipmi_nm_policy(struct ipmi_intf * intf, int argc, char **argv) 2600 { 2601 uint8_t action; 2602 uint8_t option; 2603 uint8_t correction; 2604 uint8_t domain = 0; /* default domain of platform */ 2605 uint8_t policy_id = -1; 2606 uint16_t power, period, inlet; 2607 uint16_t cores; 2608 uint32_t limit; 2609 struct nm_policy policy; 2610 2611 argv++; 2612 argc--; 2613 if ((argv[0] == NULL) || 2614 ((action = str2val2(argv[0], nm_policy_action)) == 0xFF)) { 2615 print_strs(nm_policy_action, "Policy commands", LOG_ERR, 0); 2616 return -1; 2617 } 2618 if (action == 0) /* get */ 2619 return (ipmi_nm_get_policy(intf, argc, argv)); 2620 memset(&policy, 0, sizeof(policy)); 2621 /* 2622 * nm policy add [domain <param>] enable|disable policy_id <param> correction <opt> power <watts> limit <param> period <param> 2623 * nm policy remove [domain <param>] policy_id <param> 2624 * nm policy limiting {domain <param>] 2625 */ 2626 while (--argc > 0) { 2627 argv++; 2628 if (argv[0] == NULL) break; 2629 if ((option = str2val2(argv[0], nm_policy_options)) == 0xFF) { 2630 print_strs(nm_policy_options, "Policy options", LOG_ERR, 0); 2631 return -1; 2632 } 2633 switch (option) { 2634 case 0x01: /* policy enable */ 2635 policy.domain |= IPMI_NM_POLICY_ENABLE; 2636 break; 2637 case 0x02: /* policy disable */ 2638 break; /* value is initialized to zero already */ 2639 case 0x03: /* get domain scope */ 2640 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 2641 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2642 return -1; 2643 } 2644 policy.domain |= domain & 0xF; 2645 break; 2646 case 0x04: /* inlet */ 2647 if (str2ushort(argv[1], &inlet) < 0) { 2648 printf("Inlet Temp value must be 20-45.\n"); 2649 return -1; 2650 } 2651 policy.policy_type |= 1; 2652 policy.policy_limits = 0; 2653 policy.trigger_limit = inlet; 2654 break; 2655 case 0x06: /* get correction action */ 2656 if (action == 0x5) break; /* skip if this is a remove */ 2657 if ((correction = str2val2(argv[1], nm_correction)) == 0xFF) { 2658 print_strs(nm_correction, "Correction Actions", LOG_ERR, 0); 2659 return -1; 2660 } 2661 policy.policy_type |= (correction << 5); 2662 break; 2663 case 0x07: /* not implemented */ 2664 break; 2665 case 0x08: /* power */ 2666 if (str2ushort(argv[1], &power) < 0) { 2667 printf("Power limit value must be 0-500.\n"); 2668 return -1; 2669 } 2670 policy.policy_limits = power; 2671 break; 2672 case 0x09: /* trigger limit */ 2673 if (str2uint(argv[1], &limit) < 0) { 2674 printf("Trigger Limit value must be positive integer.\n"); 2675 return -1; 2676 } 2677 policy.corr_time = limit; 2678 break; 2679 case 0x0A: /* statistics period */ 2680 if (str2ushort(argv[1], &period) < 0) { 2681 printf("Statistics Reporting Period must be positive integer.\n"); 2682 return -1; 2683 } 2684 policy.stats_period = period; 2685 break; 2686 case 0x0B: /* policy ID */ 2687 if (str2uchar(argv[1], &policy_id) < 0) { 2688 printf("Policy ID must be a positive integer 0-7.\n"); 2689 return -1; 2690 } 2691 policy.policy_id = policy_id; 2692 break; 2693 case 0x0C: /* volatile */ 2694 policy.policy_type |= 0x80; 2695 break; 2696 case 0x0D: /* cores_off, number of cores to disable at boot time */ 2697 policy.policy_type |= 4; 2698 if (str2ushort(argv[1], &cores) < 0) { 2699 printf("number of cores disabled must be 1-127.\n"); 2700 return -1; 2701 } 2702 if ((cores < 1) || (cores > 127)) { 2703 printf("number of cores disabled must be 1-127.\n"); 2704 return -1; 2705 } 2706 policy.policy_type |= 4; 2707 policy.policy_limits = cores << 1; 2708 break; 2709 default: 2710 break; 2711 } 2712 argc--; 2713 argv++; 2714 } 2715 if (action == 0x06) { /* limiting */ 2716 if ((limit = _ipmi_nm_policy_limiting(intf, domain) == -1)) 2717 return -1; 2718 printf("limit %x\n", limit); 2719 return 0; 2720 } 2721 if (policy_id == 0xFF) { 2722 print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0); 2723 return -1; 2724 } 2725 if (action == 0x04) /* add */ 2726 policy.policy_type |= 0x10; 2727 if (_ipmi_nm_set_policy(intf, &policy)) 2728 return -1; 2729 return 0; 2730 } 2731 /* end policy */ 2732 2733 static int 2734 ipmi_nm_control(struct ipmi_intf * intf, int argc, char **argv) 2735 { 2736 uint8_t action; 2737 uint8_t scope = 0; /* default control scope of global */ 2738 uint8_t domain = 0; /* default domain of platform */ 2739 uint8_t policy_id = -1; 2740 2741 argv++; 2742 argc--; 2743 /* nm_ctl_cmds returns 0 for disable, 1 for enable */ 2744 if ((argv[0] == NULL) || 2745 ((action = str2val2(argv[0], nm_ctl_cmds)) == 0xFF)) { 2746 print_strs(nm_ctl_cmds, "Control parameters:", LOG_ERR, 0); 2747 print_strs(nm_ctl_domain, "control Scope (required):", LOG_ERR, 0); 2748 return -1; 2749 } 2750 argv++; 2751 while (--argc) { 2752 /* nm_ctl_domain returns correct bit field except for action */ 2753 if ((argv[0] == NULL) || 2754 ((scope = str2val2(argv[0], nm_ctl_domain)) == 0xFF)) { 2755 print_strs(nm_ctl_domain, "Control Scope (required):", LOG_ERR, 0); 2756 return -1; 2757 } 2758 argv++; 2759 if (argv[0] == NULL) break; 2760 if (scope == 0x02) { /* domain */ 2761 if ((domain = str2val2(argv[0], nm_domain_vals)) == 0xFF) { 2762 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2763 return -1; 2764 } 2765 } else if (scope == 0x04) { /* per_policy */ 2766 2767 if (str2uchar(argv[0], &policy_id) < 0) { 2768 lprintf(LOG_ERR,"Policy ID must be a positive integer.\n"); 2769 return -1; 2770 } 2771 break; 2772 } 2773 argc--; 2774 argv++; 2775 } 2776 if ((scope == 0x04) && (policy_id == 0xFF)) { 2777 print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0); 2778 return -1; 2779 } 2780 if (_ipmi_nm_control(intf, scope|(action&1), domain, policy_id) < 0 ) 2781 return -1; 2782 return 0; 2783 } 2784 2785 static int 2786 ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv) 2787 { 2788 uint8_t mode = 0; 2789 uint8_t option; 2790 uint8_t domain = 0; /* default domain of platform */ 2791 uint8_t policy_id = -1; 2792 int policy_mode = 0; 2793 int cut; 2794 char *units = ""; 2795 char datebuf[27]; 2796 struct nm_statistics stats; 2797 struct tm tm_t; 2798 time_t t; 2799 2800 argv++; 2801 if ((argv[0] == NULL) || 2802 ((mode = str2val2(argv[0], nm_stats_mode)) == 0xFF)) { 2803 print_strs(nm_stats_mode, "Statistics commands", LOG_ERR, 0); 2804 return -1; 2805 } 2806 while (--argc) { 2807 argv++; 2808 if (argv[0] == NULL) break; 2809 if ((option = str2val2(argv[0], nm_stats_opts)) == 0xFF) { 2810 print_strs(nm_stats_opts, "Control Scope options", LOG_ERR, 0); 2811 return -1; 2812 } 2813 switch (option) { 2814 case 0x01: /* get domain scope */ 2815 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 2816 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2817 return -1; 2818 } 2819 break; 2820 case 0x02: /* policy ID */ 2821 if (str2uchar(argv[1], &policy_id) < 0) { 2822 lprintf(LOG_ERR,"Policy ID must be a positive integer.\n"); 2823 return -1; 2824 } 2825 break; 2826 default: 2827 break; 2828 } 2829 argc--; 2830 argv++; 2831 } 2832 2833 switch (mode) { 2834 case 0x01: 2835 units = "Watts"; 2836 break; 2837 case 0x02: 2838 units = "Celsius"; 2839 break; 2840 case 0x03: 2841 units = "%"; 2842 break; 2843 case 0x11: 2844 case 0x12: 2845 case 0x13: 2846 policy_mode = 1; 2847 units = (mode == 0x11) ? "Watts" : (mode == 0x12) ? "Celsius" : " %"; 2848 if (policy_id == 0xFF) { 2849 print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0); 2850 return -1; 2851 } 2852 break; 2853 default: 2854 break; 2855 } 2856 if (_ipmi_nm_statistics(intf, mode, domain, policy_id, &stats)) 2857 return -1; 2858 t = stats.time_stamp; 2859 gmtime_r(&t, &tm_t); 2860 sprintf(datebuf, "%s", asctime(&tm_t)); 2861 cut = strlen(datebuf) -1; 2862 datebuf[cut] = 0; 2863 if (csv_output) { 2864 printf("%s,%s,%s,%s,%s,%d,%d,%d,%d,%s,%d\n", 2865 val2str2(stats.id_state & 0xF, nm_domain_vals), 2866 ((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled" : "Globally Enabled") : "Disabled" , 2867 ((stats.id_state >> 5) & 1) ? "active" : "suspended", 2868 ((stats.id_state >> 6) & 1) ? "in progress" : "suspended", 2869 ((stats.id_state >> 7) & 1) ? "triggered" : "not triggered", 2870 stats.curr_value, 2871 stats.min_value, 2872 stats.max_value, 2873 stats.ave_value, 2874 datebuf, 2875 stats.stat_period); 2876 return 0; 2877 } 2878 printf(" Power domain: %s\n", 2879 val2str2(stats.id_state & 0xF, nm_domain_vals)); 2880 printf(" Policy/Global Admin state %s\n", 2881 ((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled" : "Globally Enabled") : "Disabled" ); 2882 printf(" Policy/Global Operational state %s\n", 2883 ((stats.id_state >> 5) & 1) ? "active" : "suspended"); 2884 printf(" Policy/Global Measurement state %s\n", 2885 ((stats.id_state >> 6) & 1) ? "in progress" : "suspended"); 2886 printf(" Policy Activation state %s\n", 2887 ((stats.id_state >> 7) & 1) ? "triggered" : "not triggered"); 2888 printf(" Instantaneous reading: %8d %s\n", 2889 stats.curr_value, units); 2890 printf(" Minimum during sampling period: %8d %s\n", 2891 stats.min_value, units); 2892 printf(" Maximum during sampling period: %8d %s\n", 2893 stats.max_value, units); 2894 printf(" Average reading over sample period: %8d %s\n", 2895 stats.ave_value, units); 2896 printf(" IPMI timestamp: %s\n", 2897 datebuf); 2898 printf(" Sampling period: %08d Seconds.\n", stats.stat_period); 2899 printf("\n"); 2900 return 0; 2901 } 2902 2903 static int 2904 ipmi_nm_reset_statistics(struct ipmi_intf * intf, int argc, char **argv) 2905 { 2906 uint8_t mode; 2907 uint8_t option; 2908 uint8_t domain = 0; /* default domain of platform */ 2909 uint8_t policy_id = -1; 2910 2911 argv++; 2912 if ((argv[0] == NULL) || 2913 ((mode = str2val2(argv[0], nm_reset_mode)) == 0xFF)) { 2914 print_strs(nm_reset_mode, "Reset Statistics Modes:", LOG_ERR, 0); 2915 return -1; 2916 } 2917 while (--argc) { 2918 argv++; 2919 if (argv[0] == NULL) break; 2920 if ((option = str2val2(argv[0], nm_stats_opts)) == 0xFF) { 2921 print_strs(nm_stats_opts, "Reset Scope options", LOG_ERR, 0); 2922 return -1; 2923 } 2924 switch (option) { 2925 case 0x01: /* get domain scope */ 2926 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 2927 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2928 return -1; 2929 } 2930 break; 2931 case 0x02: /* policy ID */ 2932 if (str2uchar(argv[1], &policy_id) < 0) { 2933 lprintf(LOG_ERR,"Policy ID must be a positive integer.\n"); 2934 return -1; 2935 } 2936 break; 2937 default: 2938 break; 2939 } 2940 argc--; 2941 argv++; 2942 } 2943 if (mode && (policy_id == 0xFF)) { 2944 print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0); 2945 return -1; 2946 } 2947 if (_ipmi_nm_reset_stats(intf, mode, domain, policy_id) < 0) 2948 return -1; 2949 return 0; 2950 } 2951 2952 static int 2953 ipmi_nm_set_range(struct ipmi_intf * intf, int argc, char **argv) 2954 { 2955 uint8_t domain = 0; 2956 uint8_t param; 2957 uint16_t minimum = -1; 2958 uint16_t maximum = -1; 2959 2960 while (--argc) { 2961 argv++; 2962 if (argv[0] == NULL) break; 2963 if ((param = str2val2(argv[0], nm_power_range)) == 0xFF) { 2964 print_strs(nm_power_range, "power range parameters:", LOG_ERR, 0); 2965 return -1; 2966 } 2967 switch (param) { 2968 case 0x01: /* get domain scope */ 2969 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 2970 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 2971 return -1; 2972 } 2973 break; 2974 case 0x02: /* min */ 2975 if (str2ushort(argv[1], &minimum) < 0) { 2976 lprintf(LOG_ERR,"Power minimum must be a positive integer.\n"); 2977 return -1; 2978 } 2979 break; 2980 case 0x03: /* max */ 2981 if (str2ushort(argv[1], &maximum) < 0) { 2982 lprintf(LOG_ERR,"Power maximum must be a positive integer.\n"); 2983 return -1; 2984 } 2985 break; 2986 default: 2987 break; 2988 } 2989 argc--; 2990 argv++; 2991 } 2992 if ((minimum == 0xFFFF) || (maximum == 0xFFFF)) { 2993 lprintf(LOG_ERR,"Missing parameters: nm power range min <minimum> max <maximum>.\n"); 2994 return -1; 2995 } 2996 if (_nm_set_range(intf, domain, minimum, maximum) < 0) 2997 return -1; 2998 return 0; 2999 } 3000 3001 static int 3002 ipmi_nm_get_alert(struct ipmi_intf * intf) 3003 { 3004 struct nm_set_alert alert; 3005 3006 memset(&alert, 0, sizeof(alert)); 3007 if (_ipmi_nm_get_alert(intf, &alert)) 3008 return -1; 3009 if (csv_output) { 3010 printf("%d,%s,0x%x,%s,0x%x\n", 3011 alert.chan&0xF, 3012 (alert.chan >> 7) ? "not registered" : "registered", 3013 alert.dest, 3014 (alert.string >> 7) ? "yes" : "no", 3015 alert.string & 0x7F); 3016 return 0; 3017 } 3018 printf(" Alert Chan: %d\n", 3019 alert.chan&0xF); 3020 printf(" Alert Receiver: %s\n", 3021 (alert.chan >> 7) ? "not registered" : "registered"); 3022 printf(" Alert Lan Destination: 0x%x\n", 3023 alert.dest); 3024 printf(" Use Alert String: %s\n", 3025 (alert.string >> 7) ? "yes" : "no"); 3026 printf(" Alert String Selector: 0x%x\n", 3027 alert.string & 0x7F); 3028 return 0; 3029 } 3030 3031 static int 3032 ipmi_nm_alert(struct ipmi_intf * intf, int argc, char **argv) 3033 { 3034 uint8_t param; 3035 uint8_t action; 3036 uint8_t chan = -1; 3037 uint8_t dest = -1; 3038 uint8_t string = -1; 3039 struct nm_set_alert alert; 3040 3041 argv++; 3042 argc--; 3043 if ((argv[0] == NULL) || 3044 ((action = str2val2(argv[0], nm_alert_opts)) == 0xFF)) { 3045 print_strs(nm_alert_opts, "Alert commands", LOG_ERR, 0); 3046 return -1; 3047 } 3048 if (action == 0x02) /* get */ 3049 return (ipmi_nm_get_alert(intf)); 3050 /* set */ 3051 memset(&alert, 0, sizeof(alert)); 3052 while (--argc) { 3053 argv++; 3054 if (argv[0] == NULL) break; 3055 if ((param = str2val2(argv[0], nm_set_alert_param)) == 0xFF) { 3056 print_strs(nm_set_alert_param, "Set alert Parameters:", LOG_ERR, 0); 3057 return -1; 3058 } 3059 switch (param) { 3060 case 0x01: /* channnel */ 3061 if (str2uchar(argv[1], &chan) < 0) { 3062 lprintf(LOG_ERR,"Alert Lan chan must be a positive integer.\n"); 3063 return -1; 3064 } 3065 if (action == 0x03) /* Clear */ 3066 chan |= 0x80; /* deactivate alert reciever */ 3067 break; 3068 case 0x02: /* dest */ 3069 if (str2uchar(argv[1], &dest) < 0) { 3070 lprintf(LOG_ERR,"Alert Destination must be a positive integer.\n"); 3071 return -1; 3072 } 3073 break; 3074 case 0x03: /* string number */ 3075 if (str2uchar(argv[1], &string) < 0) { 3076 lprintf(LOG_ERR,"Alert String # must be a positive integer.\n"); 3077 return -1; 3078 } 3079 string |= 0x80; /* set string select flag */ 3080 break; 3081 } 3082 argc--; 3083 argv++; 3084 } 3085 if ((chan == 0xFF) || (dest == 0xFF)) { 3086 print_strs(nm_set_alert_param, "Must set alert chan and dest params.", LOG_ERR, 0); 3087 return -1; 3088 } 3089 if (string == 0xFF) string = 0; 3090 alert.chan = chan; 3091 alert.dest = dest; 3092 alert.string = string; 3093 if (_ipmi_nm_set_alert(intf, &alert)) 3094 return -1; 3095 return 0; 3096 } 3097 3098 static int 3099 ipmi_nm_get_thresh(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id) 3100 { 3101 uint16_t list[3]; 3102 3103 memset(list, 0, sizeof(list)); 3104 if (_ipmi_nm_get_thresh(intf, domain, policy_id, &list[0])) 3105 return -1; 3106 3107 printf(" Alert Threshold domain: %s\n", 3108 val2str2(domain, nm_domain_vals)); 3109 printf(" Alert Threshold Policy ID: %d\n", 3110 policy_id); 3111 printf(" Alert Threshold 1: %d\n", 3112 list[0]); 3113 printf(" Alert Threshold 2: %d\n", 3114 list[1]); 3115 printf(" Alert Threshold 3: %d\n", 3116 list[2]); 3117 return 0; 3118 } 3119 3120 static int 3121 ipmi_nm_thresh(struct ipmi_intf * intf, int argc, char **argv) 3122 { 3123 uint8_t option; 3124 uint8_t action; 3125 uint8_t domain = 0; /* default domain of platform */ 3126 uint8_t policy_id = -1; 3127 struct nm_thresh thresh; 3128 int i = 0; 3129 3130 argv++; 3131 argc--; 3132 /* set or get */ 3133 if ((argv[0] == NULL) || (argc < 3) || 3134 ((action = str2val2(argv[0], nm_thresh_cmds)) == 0xFF)) { 3135 print_strs(nm_thresh_cmds, "Theshold commands", LOG_ERR, 0); 3136 return -1; 3137 } 3138 memset(&thresh, 0, sizeof(thresh)); 3139 while (--argc) { 3140 argv++; 3141 if (argv[0] == NULL) break; 3142 option = str2val2(argv[0], nm_thresh_param); 3143 switch (option) { 3144 case 0x01: /* get domain scope */ 3145 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 3146 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 3147 return -1; 3148 } 3149 argc--; 3150 argv++; 3151 break; 3152 case 0x02: /* policy ID */ 3153 if (str2uchar(argv[1], &policy_id) < 0) { 3154 lprintf(LOG_ERR,"Policy ID must be a positive integer.\n"); 3155 return -1; 3156 } 3157 argc--; 3158 argv++; 3159 break; 3160 case 0xFF: 3161 if (i > 2) { 3162 lprintf(LOG_ERR,"Set Threshold requires 1, 2, or 3 threshold integer values.\n"); 3163 return -1; 3164 } 3165 if (str2ushort(argv[0], &thresh.thresholds[i++]) < 0) { 3166 lprintf(LOG_ERR,"threshold value %d count must be a positve integer.\n", i); 3167 return -1; 3168 } 3169 default: 3170 break; 3171 } 3172 } 3173 if (policy_id == 0xFF) { 3174 print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0); 3175 return -1; 3176 } 3177 if (action == 0x02) /* get */ 3178 return (ipmi_nm_get_thresh(intf, domain, policy_id)); 3179 thresh.domain = domain; 3180 thresh.policy_id = policy_id; 3181 thresh.count = i; 3182 if (_ipmi_nm_set_thresh(intf, &thresh) < 0) 3183 return -1; 3184 return 0; 3185 } 3186 3187 static inline int 3188 click2hour(int click) 3189 { 3190 if ((click*6) < 60) return 0; 3191 return ((click*6)/60); 3192 } 3193 3194 static inline int 3195 click2min(int click) 3196 { 3197 if (!click) return 0; 3198 if ((click*6) < 60) return click*6; 3199 return (click*6)%60; 3200 } 3201 3202 static int 3203 ipmi_nm_get_suspend(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id) 3204 { 3205 struct nm_period periods[5]; 3206 int i; 3207 int j; 3208 int count = 0; 3209 const char *days[7] = {"M", "Tu", "W", "Th", "F", "Sa", "Su"}; 3210 3211 memset(periods, 0, sizeof(periods)); 3212 if (_ipmi_nm_get_suspend(intf, domain, policy_id, &count, &periods[0])) 3213 return -1; 3214 3215 printf(" Suspend Policy domain: %s\n", 3216 val2str2(domain, nm_domain_vals)); 3217 printf(" Suspend Policy Policy ID: %d\n", 3218 policy_id); 3219 if (!count) { 3220 printf(" No suspend Periods.\n"); 3221 return 0; 3222 } 3223 for (i = 0; i < count; i++) { 3224 printf(" Suspend Period %d: %02d:%02d to %02d:%02d", 3225 i, click2hour(periods[i].start), click2min(periods[i].start), 3226 click2hour(periods[i].stop), click2min(periods[i].stop)); 3227 if (periods[i].repeat) printf(", "); 3228 for (j = 0; j < 7; j++) 3229 printf("%s", (periods[i].repeat >> j)&1 ? days[j] : ""); 3230 printf("\n"); 3231 } 3232 return 0; 3233 } 3234 3235 static int 3236 ipmi_nm_suspend(struct ipmi_intf * intf, int argc, char **argv) 3237 { 3238 uint8_t option; 3239 uint8_t action; 3240 uint8_t domain = 0; /* default domain of platform */ 3241 uint8_t policy_id = -1; 3242 uint8_t count = 0; 3243 struct nm_suspend suspend; 3244 int i; 3245 3246 argv++; 3247 argc--; 3248 /* set or get */ 3249 if ((argv[0] == NULL) || (argc < 3) || 3250 ((action = str2val2(argv[0], nm_suspend_cmds)) == 0xFF)) { 3251 print_strs(nm_suspend_cmds, "Suspend commands", LOG_ERR, 0); 3252 return -1; 3253 } 3254 memset(&suspend, 0, sizeof(suspend)); 3255 while (--argc > 0) { 3256 argv++; 3257 if (argv[0] == NULL) break; 3258 option = str2val2(argv[0], nm_thresh_param); 3259 switch (option) { 3260 case 0x01: /* get domain scope */ 3261 if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) { 3262 print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0); 3263 return -1; 3264 } 3265 argc--; 3266 argv++; 3267 break; 3268 case 0x02: /* policy ID */ 3269 if (str2uchar(argv[1], &policy_id) < 0) { 3270 lprintf(LOG_ERR,"Policy ID must be a positive integer.\n"); 3271 return -1; 3272 } 3273 argc--; 3274 argv++; 3275 break; 3276 case 0xFF: /* process periods */ 3277 for (i = 0; count < IPMI_NM_SUSPEND_PERIOD_MAX; i += 3, count++) { 3278 if (argc < 3) { 3279 lprintf(LOG_ERR,"Error: suspend period requires a start, stop, and repeat values.\n"); 3280 return -1; 3281 } 3282 if (str2uchar(argv[i+0], &suspend.period[count].start) < 0) { 3283 lprintf(LOG_ERR,"suspend start value %d must be 0-239.\n", count); 3284 return -1; 3285 } 3286 if (str2uchar(argv[i+1], &suspend.period[count].stop) < 0) { 3287 lprintf(LOG_ERR,"suspend stop value %d must be 0-239.\n", count); 3288 return -1; 3289 } 3290 if (str2uchar(argv[i+2], &suspend.period[count].repeat) < 0) { 3291 lprintf(LOG_ERR,"suspend repeat value %d unable to convert.\n", count); 3292 return -1; 3293 } 3294 argc -= 3; 3295 if (argc <= 0) 3296 break; 3297 } 3298 if (argc <= 0) 3299 break; 3300 break; 3301 default: 3302 break; 3303 } 3304 } 3305 if (action == 0x02) /* get */ 3306 return (ipmi_nm_get_suspend(intf, domain, policy_id)); 3307 3308 suspend.domain = domain; 3309 suspend.policy_id = policy_id; 3310 if (_ipmi_nm_set_suspend(intf, &suspend) < 0) 3311 return -1; 3312 return 0; 3313 } 3314 /* end nm */ 3315 3316 static int 3317 ipmi_dcmi_set_limit(struct ipmi_intf * intf, int argc, char **argv) 3318 { 3319 int rc = 0; 3320 3321 if ( argc == 10) { 3322 /* Let`s initialize dcmi power parameters */ 3323 struct ipmi_rq req; 3324 uint8_t data[256]; 3325 uint16_t sample = 0; 3326 uint16_t limit = 0; 3327 uint32_t correction = 0; 3328 struct ipmi_rs *rsp; 3329 3330 memset(data, 0, sizeof(data)); 3331 memset(&req, 0, sizeof(req)); 3332 3333 req.msg.netfn = IPMI_NETFN_DCGRP; 3334 req.msg.lun = 0x00; 3335 req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */ 3336 req.msg.data = data; /* Contents above */ 3337 req.msg.data_len = 15; 3338 3339 data[0] = IPMI_DCMI; /* Group Extension Identification */ 3340 data[1] = 0x0; /* reserved */ 3341 data[2] = 0x0; /* reserved */ 3342 data[3] = 0x0; /* reserved */ 3343 3344 /* action */ 3345 switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) { 3346 case 0x00: 3347 /* no_action */ 3348 data[4] = 0x00; 3349 break; 3350 case 0x01: 3351 /* power_off */ 3352 data[4] = 0x01; 3353 break; 3354 case 0x11: 3355 /* sel_logging*/ 3356 data[4] = 0x11; 3357 break; 3358 case 0xFF: 3359 /* error - not a string we knew what to do with */ 3360 lprintf(LOG_ERR, "Given Action '%s' is invalid.", 3361 argv[2]); 3362 return -1; 3363 } 3364 /* limit */ 3365 if (str2ushort(argv[4], &limit) != 0) { 3366 lprintf(LOG_ERR, 3367 "Given Limit '%s' is invalid.", 3368 argv[4]); 3369 return (-1); 3370 } 3371 data[5] = limit >> 0; 3372 data[6] = limit >> 8; 3373 /* correction */ 3374 if (str2uint(argv[6], &correction) != 0) { 3375 lprintf(LOG_ERR, 3376 "Given Correction '%s' is invalid.", 3377 argv[6]); 3378 return (-1); 3379 } 3380 data[7] = correction >> 0; 3381 data[8] = correction >> 8; 3382 data[9] = correction >> 16; 3383 data[10] = correction >> 24; 3384 data[11] = 0x00; /* reserved */ 3385 data[12] = 0x00; /* reserved */ 3386 /* sample */ 3387 if (str2ushort(argv[8], &sample) != 0) { 3388 lprintf(LOG_ERR, 3389 "Given Sample '%s' is invalid.", 3390 argv[8]); 3391 return (-1); 3392 } 3393 data[13] = sample >> 0; 3394 data[14] = sample >> 8; 3395 3396 rsp = intf->sendrecv(intf, &req); 3397 if (chk_rsp(rsp)) { 3398 return -1; 3399 } 3400 } else { 3401 /* loop through each parameter and value until we have neither */ 3402 while ((argv[1] != NULL) && (argv[2] != NULL)) { 3403 rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]); 3404 /* catch any error that the set limit function returned */ 3405 if (rc > 0) { 3406 print_strs(dcmi_pwrmgmt_set_usage_vals, 3407 "set_limit <parameter> <value>", LOG_ERR, 0); 3408 return -1; 3409 } 3410 /* the first argument is the command and the second is the 3411 * value. Move argv two places; what is now 3 will be 1 3412 */ 3413 argv+=2; 3414 } 3415 } 3416 return rc; 3417 } 3418 3419 static int 3420 ipmi_dcmi_parse_power(struct ipmi_intf * intf, int argc, char **argv) 3421 { 3422 int rc = 0; 3423 uint8_t sample_time = 0; 3424 /* power management */ 3425 switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) { 3426 case 0x00: 3427 /* get reading */ 3428 if (argv[1] != NULL) { 3429 if (!(sample_time = str2val2(argv[1], dcmi_sampling_vals))) { 3430 print_strs(dcmi_sampling_vals, 3431 "Invalid sample time. Valid times are: ", 3432 LOG_ERR, 1); 3433 printf("\n"); 3434 return -1; 3435 } 3436 } 3437 rc = ipmi_dcmi_pwr_rd(intf, sample_time); 3438 break; 3439 case 0x01: 3440 /* get limit */ 3441 /* because the get limit function is also used to 3442 * populate unchanged values for the set limit 3443 * command it returns an ipmi response structure 3444 */ 3445 rc = ipmi_dcmi_pwr_prnt_glimit(intf); 3446 break; 3447 case 0x02: 3448 /* set limit */ 3449 if (argc < 4) { 3450 print_strs(dcmi_pwrmgmt_set_usage_vals, 3451 "set_limit <parameter> <value>", 3452 LOG_ERR, 0); 3453 return -1; 3454 } 3455 if (ipmi_dcmi_set_limit(intf, argc, argv) < 0) 3456 return -1; 3457 rc = ipmi_dcmi_pwr_prnt_glimit(intf); 3458 break; 3459 case 0x03: 3460 /* activate */ 3461 rc = ipmi_dcmi_pwr_actdeact(intf, 1); 3462 break; 3463 case 0x04: 3464 /* deactivate */ 3465 rc = ipmi_dcmi_pwr_actdeact(intf, 0); 3466 break; 3467 default: 3468 /* no valid options */ 3469 print_strs(dcmi_pwrmgmt_vals, 3470 "power <command>", LOG_ERR, 0); 3471 break; 3472 } 3473 return rc; 3474 } 3475 /* end dcmi power command */ 3476 3477 static int 3478 ipmi_dcmi_thermalpolicy(struct ipmi_intf * intf, int argc, char **argv) 3479 { 3480 int rc = 0; 3481 uint8_t entityID = 0; 3482 uint8_t entityInst = 0; 3483 uint8_t persistanceFlag; 3484 uint8_t actionHardPowerOff; 3485 uint8_t actionLogToSEL; 3486 uint8_t tempLimit = 0; 3487 uint8_t samplingTimeLSB; 3488 uint8_t samplingTimeMSB; 3489 uint16_t samplingTime = 0; 3490 /* Thermal policy get/set */ 3491 /* dcmitool dcmi thermalpolicy get */ 3492 switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) { 3493 case 0x00: 3494 if (argc < 4) { 3495 lprintf(LOG_NOTICE, "Get <entityID> <instanceID>"); 3496 return -1; 3497 } 3498 if (str2uchar(argv[2], &entityID) != 0) { 3499 lprintf(LOG_ERR, 3500 "Given Entity ID '%s' is invalid.", 3501 argv[2]); 3502 return (-1); 3503 } 3504 if (str2uchar(argv[3], &entityInst) != 0) { 3505 lprintf(LOG_ERR, 3506 "Given Instance ID '%s' is invalid.", 3507 argv[3]); 3508 return (-1); 3509 } 3510 rc = ipmi_dcmi_getthermalpolicy(intf, entityID, entityInst); 3511 break; 3512 case 0x01: 3513 if (argc < 4) { 3514 lprintf(LOG_NOTICE, "Set <entityID> <instanceID>"); 3515 return -1; 3516 } else if (argc < 9) { 3517 print_strs(dcmi_thermalpolicy_set_parameters_vals, 3518 "Set thermalpolicy instance parameters: " 3519 "<volatile/nonvolatile/disabled> " 3520 "<poweroff/nopoweroff/disabled> " 3521 "<sel/nosel/disabled> <templimitByte> <exceptionTime>", 3522 LOG_ERR, 0); 3523 return -1; 3524 } 3525 if (str2uchar(argv[2], &entityID) != 0) { 3526 lprintf(LOG_ERR, 3527 "Given Entity ID '%s' is invalid.", 3528 argv[2]); 3529 return (-1); 3530 } 3531 if (str2uchar(argv[3], &entityInst) != 0) { 3532 lprintf(LOG_ERR, 3533 "Given Instance ID '%s' is invalid.", 3534 argv[3]); 3535 return (-1); 3536 } 3537 persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals); 3538 actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals); 3539 actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals); 3540 if (str2uchar(argv[7], &tempLimit) != 0) { 3541 lprintf(LOG_ERR, 3542 "Given Temp Limit '%s' is invalid.", 3543 argv[7]); 3544 return (-1); 3545 } 3546 if (str2ushort(argv[8], &samplingTime) != 0) { 3547 lprintf(LOG_ERR, 3548 "Given Sampling Time '%s' is invalid.", 3549 argv[8]); 3550 return (-1); 3551 } 3552 samplingTimeLSB = (samplingTime & 0xFF); 3553 samplingTimeMSB = ((samplingTime & 0xFF00) >> 8); 3554 3555 rc = ipmi_dcmi_setthermalpolicy(intf, 3556 entityID, 3557 entityInst, 3558 persistanceFlag, 3559 actionHardPowerOff, 3560 actionLogToSEL, 3561 tempLimit, 3562 samplingTimeLSB, 3563 samplingTimeMSB); 3564 3565 break; 3566 default: 3567 print_strs(dcmi_thermalpolicy_vals, 3568 "thermalpolicy <command>", 3569 LOG_ERR, 0); 3570 return -1; 3571 } 3572 return rc; 3573 } 3574 3575 /* main 3576 * 3577 * @intf: dcmi interface handler 3578 * @argc: argument count 3579 * @argv: argument vector 3580 */ 3581 int 3582 ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv) 3583 { 3584 int rc = 0; 3585 int i; 3586 struct ipmi_rs *rsp; 3587 3588 if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) { 3589 print_strs(dcmi_cmd_vals, 3590 "Data Center Management Interface commands", 3591 LOG_ERR, 0); 3592 return -1; 3593 } 3594 /* start the cmd requested */ 3595 switch (str2val2(argv[0], dcmi_cmd_vals)) { 3596 case 0x00: 3597 /* discover capabilities*/ 3598 for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) { 3599 if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) { 3600 lprintf(LOG_ERR,"Error discovering %s capabilities!\n", 3601 val2str2(i, dcmi_capable_vals)); 3602 return -1; 3603 } 3604 } 3605 break; 3606 case 0x01: 3607 /* power */ 3608 argv++; 3609 if (argv[0] == NULL) { 3610 print_strs(dcmi_pwrmgmt_vals, "power <command>", 3611 LOG_ERR, 0); 3612 return -1; 3613 } 3614 rc = ipmi_dcmi_parse_power(intf, argc, argv); 3615 break; 3616 /* end power command */ 3617 case 0x02: 3618 /* sensor print */ 3619 /* Look for each item in the dcmi_discvry_snsr_vals struct 3620 * and if it exists, print the sdr record id(s) for it. 3621 * Use the val from each one as the sensor number. 3622 */ 3623 for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) { 3624 /* get all of the information about this sensor */ 3625 rc = ipmi_dcmi_prnt_discvry_snsr(intf, 3626 dcmi_discvry_snsr_vals[i].val); 3627 } 3628 break; 3629 /* end sensor print */ 3630 case 0x03: 3631 /* asset tag */ 3632 if(ipmi_dcmi_prnt_getassettag(intf) < 0) { 3633 lprintf(LOG_ERR, "Error getting asset tag!"); 3634 return -1; 3635 } 3636 break; 3637 /* end asset tag */ 3638 case 0x04: 3639 { 3640 /* set asset tag */ 3641 if (argc == 1 ) { 3642 print_strs(dcmi_cmd_vals, 3643 "Data Center Management Interface commands", 3644 LOG_ERR, 0); 3645 return -1; 3646 } 3647 if (ipmi_dcmi_prnt_setassettag(intf, (uint8_t *)argv[1]) < 0) { 3648 lprintf(LOG_ERR, "\nError setting asset tag!"); 3649 return -1; 3650 } 3651 break; 3652 } 3653 /* end set asset tag */ 3654 case 0x05: 3655 /* get management controller identifier string */ 3656 if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) { 3657 lprintf(LOG_ERR, 3658 "Error getting management controller identifier string!"); 3659 return -1; 3660 } 3661 break; 3662 /* end get management controller identifier string */ 3663 case 0x06: 3664 { 3665 /* set management controller identifier string */ 3666 if (argc == 1 ) { 3667 print_strs(dcmi_cmd_vals, 3668 "Data Center Management Interface commands", 3669 LOG_ERR, 0); 3670 return -1; 3671 } 3672 if (ipmi_dcmi_prnt_setmngctrlids(intf, (uint8_t *)argv[1]) < 0) { 3673 lprintf(LOG_ERR, 3674 "Error setting management controller identifier string!"); 3675 return -1; 3676 } 3677 break; 3678 } 3679 /* end set management controller identifier string */ 3680 case 0x07: 3681 /* get/set thermal policy */ 3682 rc = ipmi_dcmi_thermalpolicy(intf, argc, argv); 3683 break; 3684 case 0x08: 3685 if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) { 3686 lprintf(LOG_ERR, 3687 "Error get temperature readings!"); 3688 return -1; 3689 } 3690 break; 3691 case 0x09: 3692 if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) { 3693 lprintf(LOG_ERR, 3694 "Error Get DCMI Configuration Parameters!"); 3695 return -1; 3696 }; 3697 break; 3698 case 0x0A: 3699 { 3700 switch (argc) { 3701 case 2: 3702 if (strncmp(argv[1], "activate_dhcp", 13) != 0) { 3703 print_strs( dcmi_conf_param_vals, 3704 "DCMI Configuration Parameters", 3705 LOG_ERR, 0); 3706 return -1; 3707 } 3708 break; 3709 default: 3710 if (argc != 3 || strncmp(argv[1], "help", 4) == 0) { 3711 print_strs(dcmi_conf_param_vals, 3712 "DCMI Configuration Parameters", 3713 LOG_ERR, 0); 3714 return -1; 3715 } 3716 } 3717 if (strncmp(argv[1], "activate_dhcp", 13) == 0) { 3718 rsp = ipmi_dcmi_setconfparam(intf, 1, 1); 3719 } else { 3720 uint16_t tmp_val = 0; 3721 if (str2ushort(argv[2], &tmp_val) != 0) { 3722 lprintf(LOG_ERR, 3723 "Given %s '%s' is invalid.", 3724 argv[1], argv[2]); 3725 return (-1); 3726 } 3727 rsp = ipmi_dcmi_setconfparam(intf, 3728 str2val2(argv[1], dcmi_conf_param_vals), 3729 tmp_val); 3730 } 3731 if (chk_rsp(rsp)) { 3732 lprintf(LOG_ERR, 3733 "Error Set DCMI Configuration Parameters!"); 3734 } 3735 break; 3736 } 3737 case 0x0B: 3738 { 3739 if (intf->session == NULL) { 3740 lprintf(LOG_ERR, 3741 "\nOOB discovery is available only via RMCP interface."); 3742 return -1; 3743 } 3744 if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) { 3745 lprintf(LOG_ERR, "\nOOB discovering capabilities failed."); 3746 return -1; 3747 } 3748 break; 3749 } 3750 default: 3751 /* couldn't detect what the user entered */ 3752 print_strs(dcmi_cmd_vals, 3753 "Data Center Management Interface commands", 3754 LOG_ERR, 0); 3755 return -1; 3756 break; 3757 } 3758 printf("\n"); 3759 return rc; 3760 } 3761 3762 /* Node Manager main 3763 * 3764 * @intf: nm interface handler 3765 * @argc: argument count 3766 * @argv: argument vector 3767 */ 3768 int 3769 ipmi_nm_main(struct ipmi_intf * intf, int argc, char **argv) 3770 { 3771 struct nm_discover disc; 3772 3773 if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) { 3774 print_strs(nm_cmd_vals, 3775 "Node Manager Interface commands", 3776 LOG_ERR, 0); 3777 return -1; 3778 } 3779 3780 switch (str2val2(argv[0], nm_cmd_vals)) { 3781 /* discover */ 3782 case 0x00: 3783 if (_ipmi_nm_discover(intf, &disc)) 3784 return -1; 3785 printf(" Node Manager Version %s\n", val2str2(disc.nm_version, nm_version_vals)); 3786 printf(" revision %d.%d%d patch version %d\n", disc.major_rev, 3787 disc.minor_rev>>4, disc.minor_rev&0xf, disc.patch_version); 3788 break; 3789 /* capability */ 3790 case 0x01: 3791 if (ipmi_nm_getcapabilities(intf, argc, argv)) 3792 return -1; 3793 break; 3794 /* policy control enable-disable */ 3795 case 0x02: 3796 if (ipmi_nm_control(intf, argc, argv)) 3797 return -1; 3798 break; 3799 /* policy */ 3800 case 0x03: 3801 if (ipmi_nm_policy(intf, argc, argv)) 3802 return -1; 3803 break; 3804 /* Get statistics */ 3805 case 0x04: 3806 if (ipmi_nm_get_statistics(intf, argc, argv)) 3807 return -1; 3808 break; 3809 /* set power draw range */ 3810 case 0x05: 3811 if (ipmi_nm_set_range(intf, argc, argv)) 3812 return -1; 3813 break; 3814 /* set/get suspend periods */ 3815 case 0x06: 3816 if (ipmi_nm_suspend(intf, argc, argv)) 3817 return -1; 3818 break; 3819 /* reset statistics */ 3820 case 0x07: 3821 if (ipmi_nm_reset_statistics(intf, argc, argv)) 3822 return -1; 3823 break; 3824 /* set/get alert destination */ 3825 case 0x08: 3826 if (ipmi_nm_alert(intf, argc, argv)) 3827 return -1; 3828 break; 3829 /* set/get alert thresholds */ 3830 case 0x09: 3831 if (ipmi_nm_thresh(intf, argc, argv)) 3832 return -1; 3833 break; 3834 default: 3835 print_strs(nm_cmd_vals, "Node Manager Interface commands", LOG_ERR, 0); 3836 break; 3837 } 3838 return 0; 3839 } 3840 3841 /* Display DCMI sensor information 3842 * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the 3843 * target Record ID. Then either ipmi_sensor_print_full or 3844 * ipmi_sensor_print_compact is called to print the data 3845 * 3846 * @intf: ipmi interface handler 3847 * @rec_id: target Record ID 3848 */ 3849 static int 3850 ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id) 3851 { 3852 struct sdr_get_rs *header; 3853 struct ipmi_sdr_iterator *itr; 3854 int rc = 0; 3855 uint8_t *rec = NULL; 3856 3857 itr = ipmi_sdr_start(intf, 0); 3858 if (itr == NULL) { 3859 lprintf(LOG_ERR, "Unable to open SDR for reading"); 3860 return (-1); 3861 } 3862 3863 while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) { 3864 if (header->id == rec_id) { 3865 break; 3866 } 3867 } 3868 if (header == NULL) { 3869 lprintf(LOG_DEBUG, "header == NULL"); 3870 ipmi_sdr_end(intf, itr); 3871 return (-1); 3872 } 3873 /* yes, we found the SDR for this record ID, now get full record */ 3874 rec = ipmi_sdr_get_record(intf, header, itr); 3875 if (rec == NULL) { 3876 lprintf(LOG_DEBUG, "rec == NULL"); 3877 ipmi_sdr_end(intf, itr); 3878 return (-1); 3879 } 3880 if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) || 3881 (header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) { 3882 rc = ipmi_sdr_print_rawentry(intf, header->type, 3883 rec, header->length); 3884 } else { 3885 rc = (-1); 3886 } 3887 free(rec); 3888 rec = NULL; 3889 ipmi_sdr_end(intf, itr); 3890 return rc; 3891 } 3892