1 /*****************************************************************************\ 2 * $Id: ipmi-dcmi.c,v 1.15 2010-07-27 18:01:43 chu11 Exp $ 3 ***************************************************************************** 4 * Copyright (C) 2009-2015 Lawrence Livermore National Security, LLC. 5 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 6 * Written by Albert Chu <chu11@llnl.gov> 7 * LLNL-CODE-413270 8 * 9 * This file is part of Ipmi-Dcmi, tools and libraries to support the 10 * data center manageability interface (DCMI). For details, see 11 * http://www.llnl.gov/linux/. 12 * 13 * Ipmi-Dcmi is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 3 of the License, or (at your 16 * option) any later version. 17 * 18 * Ipmi-Dcmi is distributed in the hope that it will be useful, but 19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21 * for more details. 22 * 23 * You should have received a copy of the GNU General Public License along 24 * with Ipmi-Dcmi. If not, see <http://www.gnu.org/licenses/>. 25 \*****************************************************************************/ 26 27 #if HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #if STDC_HEADERS 34 #include <string.h> 35 #endif /* STDC_HEADERS */ 36 #if TIME_WITH_SYS_TIME 37 #include <sys/time.h> 38 #include <time.h> 39 #else /* !TIME_WITH_SYS_TIME */ 40 #if HAVE_SYS_TIME_H 41 #include <sys/time.h> 42 #else /* !HAVE_SYS_TIME_H */ 43 #include <time.h> 44 #endif /* !HAVE_SYS_TIME_H */ 45 #endif /* !TIME_WITH_SYS_TIME */ 46 #include <assert.h> 47 #include <errno.h> 48 49 #include <freeipmi/freeipmi.h> 50 51 #include "ipmi-dcmi.h" 52 #include "ipmi-dcmi-argp.h" 53 54 #include "freeipmi-portability.h" 55 #include "pstdout.h" 56 #include "tool-common.h" 57 #include "tool-cmdline-common.h" 58 #include "tool-hostrange-common.h" 59 #include "tool-util-common.h" 60 61 #define IPMI_DCMI_ROLLING_AVERAGE_TIME_PERIOD_BUFLEN 4096 62 63 #define IPMI_DCMI_MAX_RECORD_IDS_BUFLEN 1024 64 65 #define IPMI_DCMI_ERROR_BUFLEN 1024 66 67 #define IPMI_DCMI_TIME_BUFLEN 512 68 69 /* return 1 on output success, 0 on no output, -1 on error */ 70 static int 71 _dcmi_specification_conformance (ipmi_dcmi_state_data_t *state_data, uint8_t *parameter_revision) 72 { 73 fiid_obj_t obj_cmd_rs = NULL; 74 uint8_t major, minor; 75 uint64_t val; 76 int rv = -1; 77 78 assert (state_data); 79 assert (parameter_revision); 80 81 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_capability_info_supported_dcmi_capabilities_rs))) 82 { 83 pstdout_fprintf (state_data->pstate, 84 stderr, 85 "fiid_obj_create: %s\n", 86 strerror (errno)); 87 goto cleanup; 88 } 89 90 if (ipmi_cmd_dcmi_get_dcmi_capability_info_supported_dcmi_capabilities (state_data->ipmi_ctx, 91 obj_cmd_rs) < 0) 92 { 93 pstdout_fprintf (state_data->pstate, 94 stderr, 95 "ipmi_cmd_dcmi_get_dcmi_capability_info_supported_dcmi_capabilities: %s\n", 96 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 97 goto cleanup; 98 } 99 100 if (FIID_OBJ_GET (obj_cmd_rs, 101 "dcmi_specification_conformance.major_version", 102 &val) < 0) 103 { 104 pstdout_fprintf (state_data->pstate, 105 stderr, 106 "fiid_obj_get: 'dcmi_specification_conformance.major_version': %s\n", 107 fiid_obj_errormsg (obj_cmd_rs)); 108 goto cleanup; 109 } 110 major = val; 111 112 if (FIID_OBJ_GET (obj_cmd_rs, 113 "dcmi_specification_conformance.minor_version", 114 &val) < 0) 115 { 116 pstdout_fprintf (state_data->pstate, 117 stderr, 118 "fiid_obj_get: 'dcmi_specification_conformance.minor_version': %s\n", 119 fiid_obj_errormsg (obj_cmd_rs)); 120 goto cleanup; 121 } 122 minor = val; 123 124 /* XXX: achu: The spec does not say how these version numbers are 125 * formmatted. decimal? BCD? On the one hand, I think to be cmdline_parse(int key,char * arg,struct argp_state * state)126 * consistent to the "IPMI Version" of a Get Device ID call, it 127 * should be BCD. But, these are 8 bit fields instead of 4 bit 128 * fields (e.g. would I output "01.00" instead of "1.0"?). So I'm 129 * going to assume decimal for now. 130 */ 131 pstdout_printf (state_data->pstate, 132 "DCMI Specification Conformance : %u.%u\n", 133 major, 134 minor); 135 136 if (FIID_OBJ_GET (obj_cmd_rs, 137 "parameter_revision", 138 &val) < 0) 139 { 140 pstdout_fprintf (state_data->pstate, 141 stderr, 142 "fiid_obj_get: 'parameter_revision': %s\n", 143 fiid_obj_errormsg (obj_cmd_rs)); 144 goto cleanup; 145 } 146 (*parameter_revision) = val; 147 148 rv = 1; 149 cleanup: 150 fiid_obj_destroy (obj_cmd_rs); 151 return (rv); 152 } 153 154 /* return 1 on output success, 0 on no output, -1 on error */ 155 static int 156 _supported_dcmi_capabilities (ipmi_dcmi_state_data_t *state_data) 157 { 158 fiid_obj_t obj_cmd_rs = NULL; 159 uint8_t parameter_revision; 160 uint64_t val; 161 int rv = -1; 162 163 assert (state_data); 164 165 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_capability_info_supported_dcmi_capabilities_rs))) 166 { 167 pstdout_fprintf (state_data->pstate, 168 stderr, 169 "fiid_obj_create: %s\n", 170 strerror (errno)); 171 goto cleanup; 172 } 173 174 if (ipmi_cmd_dcmi_get_dcmi_capability_info_supported_dcmi_capabilities (state_data->ipmi_ctx, 175 obj_cmd_rs) < 0) 176 { 177 pstdout_fprintf (state_data->pstate, 178 stderr, 179 "ipmi_cmd_dcmi_get_dcmi_capability_info_supported_dcmi_capabilities: %s\n", 180 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 181 goto cleanup; 182 } 183 184 if (FIID_OBJ_GET (obj_cmd_rs, 185 "parameter_revision", 186 &val) < 0) 187 { 188 pstdout_fprintf (state_data->pstate, 189 stderr, 190 "fiid_obj_get: 'mandatory_platform_capabilities.identification_support': %s\n", 191 fiid_obj_errormsg (obj_cmd_rs)); 192 goto cleanup; 193 } 194 parameter_revision = val; 195 196 /* See errata 1.0 */ 197 if (!(parameter_revision >= 0x02)) 198 { 199 if (FIID_OBJ_GET (obj_cmd_rs, 200 "mandatory_platform_capabilities.identification_support", 201 &val) < 0) 202 { 203 pstdout_fprintf (state_data->pstate, 204 stderr, 205 "fiid_obj_get: 'mandatory_platform_capabilities.identification_support': %s\n", 206 fiid_obj_errormsg (obj_cmd_rs)); 207 goto cleanup; 208 } 209 210 pstdout_printf (state_data->pstate, 211 "Identification Support : %s\n", 212 val ? "Compliant with DCMI Specification" : "Not Compliant with DCMI Specification"); 213 214 if (FIID_OBJ_GET (obj_cmd_rs, 215 "mandatory_platform_capabilities.sel_logging", 216 &val) < 0) 217 { 218 pstdout_fprintf (state_data->pstate, 219 stderr, 220 "fiid_obj_get: 'mandatory_platform_capabilities.sel_logging': %s\n", 221 fiid_obj_errormsg (obj_cmd_rs)); 222 goto cleanup; 223 } 224 225 pstdout_printf (state_data->pstate, 226 "SEL logging : %s\n", 227 val ? "Compliant with DCMI Specification" : "Not Compliant with DCMI Specification"); 228 229 if (FIID_OBJ_GET (obj_cmd_rs, 230 "mandatory_platform_capabilities.chassis_power", 231 &val) < 0) 232 { 233 pstdout_fprintf (state_data->pstate, 234 stderr, 235 "fiid_obj_get: 'mandatory_platform_capabilities.chassis_power': %s\n", 236 fiid_obj_errormsg (obj_cmd_rs)); 237 goto cleanup; 238 } 239 240 pstdout_printf (state_data->pstate, 241 "Chassis Power : %s\n", 242 val ? "Compliant with DCMI Specification" : "Not Compliant with DCMI Specification"); 243 244 if (FIID_OBJ_GET (obj_cmd_rs, 245 "mandatory_platform_capabilities.temperature_monitor", 246 &val) < 0) 247 { 248 pstdout_fprintf (state_data->pstate, 249 stderr, 250 "fiid_obj_get: 'mandatory_platform_capabilities.temperature_monitor': %s\n", 251 fiid_obj_errormsg (obj_cmd_rs)); 252 goto cleanup; 253 } 254 255 pstdout_printf (state_data->pstate, 256 "Temperature Monitor : %s\n", 257 val ? "Compliant with DCMI Specification" : "Not Compliant with DCMI Specification"); 258 } 259 260 if (FIID_OBJ_GET (obj_cmd_rs, 261 "optional_platform_capabilities.power_management_monitoring_support", 262 &val) < 0) 263 { 264 pstdout_fprintf (state_data->pstate, 265 stderr, 266 "fiid_obj_get: 'optional_platform_capabilities.power_management_monitoring_support': %s\n", 267 fiid_obj_errormsg (obj_cmd_rs)); 268 goto cleanup; 269 } 270 271 pstdout_printf (state_data->pstate, 272 "Power Management / Monitoring Support : %s\n", 273 val ? "Available" : "Not present"); 274 275 if (FIID_OBJ_GET (obj_cmd_rs, 276 "manageability_access_capabilities.in_band_system_interface_channel_available", 277 &val) < 0) 278 { 279 pstdout_fprintf (state_data->pstate, 280 stderr, 281 "fiid_obj_get: 'manageability_access_capabilities.in_band_system_interface_channel_available': %s\n", 282 fiid_obj_errormsg (obj_cmd_rs)); 283 goto cleanup; 284 } 285 286 pstdout_printf (state_data->pstate, 287 "In-band System Interface Channel : %s\n", 288 val ? "Available" : "Not present"); 289 290 if (FIID_OBJ_GET (obj_cmd_rs, 291 "manageability_access_capabilities.serial_tmode_available", 292 &val) < 0) 293 { 294 pstdout_fprintf (state_data->pstate, 295 stderr, 296 "fiid_obj_get: 'manageability_access_capabilities.serial_tmode_available': %s\n", 297 fiid_obj_errormsg (obj_cmd_rs)); 298 goto cleanup; 299 } 300 301 pstdout_printf (state_data->pstate, 302 "Serial TMODE : %s\n", 303 val ? "Available" : "Not present"); 304 305 if (FIID_OBJ_GET (obj_cmd_rs, 306 "manageability_access_capabilities.out_of_band_secondary_lan_channel_available", 307 &val) < 0) 308 { _ipmi_dcmi_config_file_parse(struct ipmi_dcmi_arguments * cmd_args)309 pstdout_fprintf (state_data->pstate, 310 stderr, 311 "fiid_obj_get: 'manageability_access_capabilities.out_of_band_secondary_lan_channel_available': %s\n", 312 fiid_obj_errormsg (obj_cmd_rs)); 313 goto cleanup; 314 } 315 316 pstdout_printf (state_data->pstate, 317 "Out-Of-Band Secondary LAN Channel : %s\n", 318 val ? "Available" : "Not present"); 319 320 /* See errata 1.0 */ 321 if (!(parameter_revision >= 0x02)) 322 { 323 if (FIID_OBJ_GET (obj_cmd_rs, 324 "manageability_access_capabilities.out_of_band_primary_lan_channel_available", 325 &val) < 0) 326 { 327 pstdout_fprintf (state_data->pstate, 328 stderr, 329 "fiid_obj_get: 'manageability_access_capabilities.out_of_band_primary_lan_channel_available': %s\n", 330 fiid_obj_errormsg (obj_cmd_rs)); 331 goto cleanup; 332 } 333 334 pstdout_printf (state_data->pstate, _ipmi_dcmi_args_validate(struct ipmi_dcmi_arguments * cmd_args)335 "Out-Of-Band Primary LAN Channel : %s\n", 336 val ? "Available" : "Not present"); 337 338 if (FIID_OBJ_GET (obj_cmd_rs, 339 "manageability_access_capabilities.sol_supported", 340 &val) < 0) 341 { 342 pstdout_fprintf (state_data->pstate, 343 stderr, 344 "fiid_obj_get: 'manageability_access_capabilities.sol_supported': %s\n", 345 fiid_obj_errormsg (obj_cmd_rs)); 346 goto cleanup; 347 } 348 349 /* SOL Supported - removed "supported" */ 350 pstdout_printf (state_data->pstate, 351 "SOL : %s\n", 352 val ? "Available" : "Not present"); 353 354 if (FIID_OBJ_GET (obj_cmd_rs, 355 "manageability_access_capabilities.vlan_capable", 356 &val) < 0) 357 { 358 pstdout_fprintf (state_data->pstate, 359 stderr, 360 "fiid_obj_get: 'manageability_access_capabilities.vlan_capable': %s\n", 361 fiid_obj_errormsg (obj_cmd_rs)); 362 goto cleanup; 363 } 364 365 /* VLAN Capable - removed "capable" */ 366 pstdout_printf (state_data->pstate, 367 "VLAN : %s\n", 368 val ? "Available" : "Not present"); 369 } 370 371 rv = 1; 372 cleanup: 373 fiid_obj_destroy (obj_cmd_rs); 374 return (rv); 375 } 376 377 /* return 1 on output success, 0 on no output, -1 on error */ 378 static int 379 _mandatory_platform_attributes (ipmi_dcmi_state_data_t *state_data) 380 { 381 fiid_obj_t obj_cmd_rs = NULL; 382 uint8_t parameter_revision; 383 uint16_t number_of_sel_entries; 384 uint64_t val; 385 int rv = -1; ipmi_dcmi_argp_parse(int argc,char ** argv,struct ipmi_dcmi_arguments * cmd_args)386 387 assert (state_data); 388 389 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_capability_info_mandatory_platform_attributes_rs))) 390 { 391 pstdout_fprintf (state_data->pstate, 392 stderr, 393 "fiid_obj_create: %s\n", 394 strerror (errno)); 395 goto cleanup; 396 } 397 398 if (ipmi_cmd_dcmi_get_dcmi_capability_info_mandatory_platform_attributes (state_data->ipmi_ctx, 399 obj_cmd_rs) < 0) 400 { 401 pstdout_fprintf (state_data->pstate, 402 stderr, 403 "ipmi_cmd_dcmi_get_dcmi_capability_info_mandatory_platform_attributes: %s\n", 404 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 405 goto cleanup; 406 } 407 408 if (FIID_OBJ_GET (obj_cmd_rs, 409 "parameter_revision", 410 &val) < 0) 411 { 412 pstdout_fprintf (state_data->pstate, 413 stderr, 414 "fiid_obj_get: 'mandatory_platform_capabilities.identification_support': %s\n", 415 fiid_obj_errormsg (obj_cmd_rs)); 416 goto cleanup; 417 } 418 parameter_revision = val; 419 420 if (FIID_OBJ_GET (obj_cmd_rs, 421 "sel_attributes.number_of_sel_entries", 422 &val) < 0) 423 { 424 pstdout_fprintf (state_data->pstate, 425 stderr, 426 "fiid_obj_get: 'sel_attributes.number_of_sel_entries': %s\n", 427 fiid_obj_errormsg (obj_cmd_rs)); 428 goto cleanup; 429 } 430 number_of_sel_entries = val; 431 432 pstdout_printf (state_data->pstate, 433 "Number of SEL entries : %u\n", 434 number_of_sel_entries); 435 436 /* In DCMI v1.1 */ 437 if (parameter_revision >= 0x02) 438 { 439 if (FIID_OBJ_GET (obj_cmd_rs, 440 "sel_attributes.record_level_sel_flush_upon_rollover", 441 &val) < 0) 442 { 443 pstdout_fprintf (state_data->pstate, 444 stderr, 445 "fiid_obj_get: 'sel_attributes.record_level_sel_flush_upon_rollover': %s\n", 446 fiid_obj_errormsg (obj_cmd_rs)); 447 goto cleanup; 448 } 449 450 pstdout_printf (state_data->pstate, 451 "Record Level SEL Flush upon Rollover : %s\n", 452 val ? "Available" : "Not present"); 453 454 if (FIID_OBJ_GET (obj_cmd_rs, 455 "sel_attributes.entire_sel_flush_upon_rollover", 456 &val) < 0) 457 { 458 pstdout_fprintf (state_data->pstate, 459 stderr, 460 "fiid_obj_get: 'sel_attributes.entire_sel_flush_upon_rollover': %s\n", 461 fiid_obj_errormsg (obj_cmd_rs)); 462 goto cleanup; 463 } 464 465 pstdout_printf (state_data->pstate, 466 "Entire SEL Flush upon Rollover : %s\n", 467 val ? "Available" : "Not present"); 468 } 469 470 if (FIID_OBJ_GET (obj_cmd_rs, 471 "sel_attributes.sel_automatic_rollover_enabled", 472 &val) < 0) 473 { 474 pstdout_fprintf (state_data->pstate, 475 stderr, 476 "fiid_obj_get: 'sel_attributes.sel_automatic_rollover_enabled': %s\n", 477 fiid_obj_errormsg (obj_cmd_rs)); 478 goto cleanup; 479 } 480 481 pstdout_printf (state_data->pstate, 482 "SEL automatic rollover : %s\n", 483 val ? "Available" : "Not present"); 484 485 /* See errata 1.0 */ 486 if (!(parameter_revision >= 0x02)) 487 { 488 if (FIID_OBJ_GET (obj_cmd_rs, 489 "identification_attributes.guid_support", 490 &val) < 0) 491 { 492 pstdout_fprintf (state_data->pstate, 493 stderr, 494 "fiid_obj_get: 'identification_attributes.guid_support': %s\n", 495 fiid_obj_errormsg (obj_cmd_rs)); 496 goto cleanup; 497 } 498 499 pstdout_printf (state_data->pstate, 500 "GUID : %s\n", 501 val ? "Available" : "Not present"); 502 } 503 504 if (FIID_OBJ_GET (obj_cmd_rs, 505 "identification_attributes.dhcp_host_name_support", 506 &val) < 0) 507 { 508 pstdout_fprintf (state_data->pstate, 509 stderr, 510 "fiid_obj_get: 'identification_attributes.dhcp_host_name_support': %s\n", 511 fiid_obj_errormsg (obj_cmd_rs)); 512 goto cleanup; 513 } 514 515 pstdout_printf (state_data->pstate, 516 "DHCP Host Name : %s\n", 517 val ? "Available" : "Not present"); 518 519 if (FIID_OBJ_GET (obj_cmd_rs, 520 "identification_attributes.asset_tag_support", 521 &val) < 0) 522 { 523 pstdout_fprintf (state_data->pstate, 524 stderr, 525 "fiid_obj_get: 'identification_attributes.asset_tag_support': %s\n", 526 fiid_obj_errormsg (obj_cmd_rs)); 527 goto cleanup; 528 } 529 530 pstdout_printf (state_data->pstate, 531 "Asset Tag : %s\n", 532 val ? "Available" : "Not present"); 533 534 /* See errata 1.0 */ 535 if (!(parameter_revision >= 0x02)) 536 { 537 if (FIID_OBJ_GET (obj_cmd_rs, 538 "temperature_monitoring.inlet_temperature", 539 &val) < 0) 540 { 541 pstdout_fprintf (state_data->pstate, 542 stderr, 543 "fiid_obj_get: 'temperature_monitoring.inlet_temperature': %s\n", 544 fiid_obj_errormsg (obj_cmd_rs)); 545 goto cleanup; 546 } 547 548 pstdout_printf (state_data->pstate, 549 "Inlet temperature : %s\n", 550 val ? "At least 1 present" : "Not present"); 551 552 if (FIID_OBJ_GET (obj_cmd_rs, 553 "temperature_monitoring.processors_temperature", 554 &val) < 0) 555 { 556 pstdout_fprintf (state_data->pstate, 557 stderr, 558 "fiid_obj_get: 'temperature_monitoring.processors_temperature': %s\n", 559 fiid_obj_errormsg (obj_cmd_rs)); 560 goto cleanup; 561 } 562 563 pstdout_printf (state_data->pstate, 564 "Processors temperature : %s\n", 565 val ? "At least 1 present" : "Not present"); 566 567 if (FIID_OBJ_GET (obj_cmd_rs, 568 "temperature_monitoring.baseboard_temperature", 569 &val) < 0) 570 { 571 pstdout_fprintf (state_data->pstate, 572 stderr, 573 "fiid_obj_get: 'temperature_monitoring.baseboard_temperature': %s\n", 574 fiid_obj_errormsg (obj_cmd_rs)); 575 goto cleanup; 576 } 577 578 pstdout_printf (state_data->pstate, 579 "Baseboard temperature : %s\n", 580 val ? "At least 1 present" : "Not present"); 581 } 582 583 /* In DCMI v1.1 */ 584 if (parameter_revision >= 0x02) 585 { 586 int flag; 587 588 if ((flag = fiid_obj_get (obj_cmd_rs, 589 "temperature_monitoring.sampling_period", 590 &val)) < 0) 591 { 592 pstdout_fprintf (state_data->pstate, 593 stderr, 594 "fiid_obj_get: 'temperature_monitoring.sampling_period': %s\n", 595 fiid_obj_errormsg (obj_cmd_rs)); 596 goto cleanup; 597 } 598 599 if (flag) 600 { 601 pstdout_printf (state_data->pstate, 602 "Sampling frequency for Temperature Monitoring : Every %u Second(s)\n", 603 val); 604 } 605 } 606 607 rv = 1; 608 cleanup: 609 fiid_obj_destroy (obj_cmd_rs); 610 return (rv); 611 } 612 613 /* return 1 on output success, 0 on no output, -1 on error */ 614 static int 615 _optional_platform_attributes (ipmi_dcmi_state_data_t *state_data) 616 { 617 fiid_obj_t obj_cmd_rs = NULL; 618 uint8_t slave_address; 619 uint8_t device_revision; 620 uint8_t channel_number; 621 uint64_t val; 622 int rv = -1; 623 624 assert (state_data); 625 626 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_capability_info_optional_platform_attributes_rs))) 627 { 628 pstdout_fprintf (state_data->pstate, 629 stderr, 630 "fiid_obj_create: %s\n", 631 strerror (errno)); 632 goto cleanup; 633 } 634 635 if (ipmi_cmd_dcmi_get_dcmi_capability_info_optional_platform_attributes (state_data->ipmi_ctx, 636 obj_cmd_rs) < 0) 637 { 638 /* IPMI Workaround? 639 * 640 * Technically, I believe this should be mandatory, as this is 641 * not listed as optional in the DCMI spec (enhanced system 642 * power statistics attributes is the only one that is 643 * optional). However, this parameter specifically lists 644 * attributes for optional parts of DCMI. 645 * 646 * This has been seen as non-implemented on atleast two 647 * motherboards (one undocumented motherboard and also the Intel 648 * S2600JF/Appro 512X). 649 */ 650 if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 651 && ((ipmi_check_completion_code (obj_cmd_rs, 652 IPMI_COMP_CODE_REQUEST_PARAMETER_NOT_SUPPORTED) == 1) 653 || (ipmi_check_completion_code (obj_cmd_rs, 654 IPMI_COMP_CODE_REQUESTED_SENSOR_DATA_OR_RECORD_NOT_PRESENT) == 1))) 655 { 656 rv = 0; 657 goto cleanup; 658 } 659 660 pstdout_fprintf (state_data->pstate, 661 stderr, 662 "ipmi_cmd_dcmi_get_dcmi_capability_info_optional_platform_attributes: %s\n", 663 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 664 goto cleanup; 665 } 666 667 if (FIID_OBJ_GET (obj_cmd_rs, 668 "power_management_device_slave_address.slave_address", 669 &val) < 0) 670 { 671 pstdout_fprintf (state_data->pstate, 672 stderr, 673 "fiid_obj_get: 'power_management_device_slave_address.slave_address': %s\n", 674 fiid_obj_errormsg (obj_cmd_rs)); 675 goto cleanup; 676 } 677 slave_address = val; 678 679 pstdout_printf (state_data->pstate, 680 "Power Management Device Slave Address : %02Xh\n", 681 slave_address); 682 683 if (FIID_OBJ_GET (obj_cmd_rs, 684 "power_management_controller_channel_number.device_revision", 685 &val) < 0) 686 { 687 pstdout_fprintf (state_data->pstate, 688 stderr, 689 "fiid_obj_get: 'power_management_controller_channel_number.device_revision': %s\n", 690 fiid_obj_errormsg (obj_cmd_rs)); 691 goto cleanup; 692 } 693 device_revision = val; 694 695 /* revision is decimal? Lets assume so */ 696 pstdout_printf (state_data->pstate, 697 "Power Management Controller Device Revision : %u\n", 698 device_revision); 699 700 if (FIID_OBJ_GET (obj_cmd_rs, 701 "power_management_controller_channel_number.channel_number", 702 &val) < 0) 703 { 704 pstdout_fprintf (state_data->pstate, 705 stderr, 706 "fiid_obj_get: 'power_management_controller_channel_number.channel_number': %s\n", 707 fiid_obj_errormsg (obj_cmd_rs)); 708 goto cleanup; 709 } 710 channel_number = val; 711 712 pstdout_printf (state_data->pstate, 713 "Power Management Controller Channel Number : %u\n", 714 channel_number); 715 716 rv = 1; 717 cleanup: 718 fiid_obj_destroy (obj_cmd_rs); 719 return (rv); 720 } 721 722 /* return 1 on output success, 0 on no output, -1 on error */ 723 static int 724 _manageability_access_attributes (ipmi_dcmi_state_data_t *state_data) 725 { 726 fiid_obj_t obj_cmd_rs = NULL; 727 uint8_t channel_number; 728 uint64_t val; 729 int rv = -1; 730 731 assert (state_data); 732 733 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_capability_info_manageability_access_attributes_rs))) 734 { 735 pstdout_fprintf (state_data->pstate, 736 stderr, 737 "fiid_obj_create: %s\n", 738 strerror (errno)); 739 goto cleanup; 740 } 741 742 if (ipmi_cmd_dcmi_get_dcmi_capability_info_manageability_access_attributes (state_data->ipmi_ctx, 743 obj_cmd_rs) < 0) 744 { 745 pstdout_fprintf (state_data->pstate, 746 stderr, 747 "ipmi_cmd_dcmi_get_dcmi_capability_info_manageability_access_attributes: %s\n", 748 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 749 goto cleanup; 750 } 751 752 if (FIID_OBJ_GET (obj_cmd_rs, 753 "mandatory_primary_lan_out_of_band_support_channel_number", 754 &val) < 0) 755 { 756 pstdout_fprintf (state_data->pstate, 757 stderr, 758 "fiid_obj_get: 'mandatory_primary_lan_out_of_band_support_channel_number': %s\n", 759 fiid_obj_errormsg (obj_cmd_rs)); 760 goto cleanup; 761 } 762 channel_number = val; 763 764 if (channel_number == IPMI_DCMI_CHANNEL_NOT_SUPPORTED) 765 pstdout_printf (state_data->pstate, 766 "Primary LAN Out-of-band Channel Number : Not supported\n"); 767 else 768 pstdout_printf (state_data->pstate, 769 "Primary LAN Out-of-band Channel Number : %u\n", 770 channel_number); 771 772 if (FIID_OBJ_GET (obj_cmd_rs, 773 "optional_secondary_lan_out_of_band_support_channel_number", 774 &val) < 0) 775 { 776 pstdout_fprintf (state_data->pstate, 777 stderr, 778 "fiid_obj_get: 'optional_secondary_lan_out_of_band_support_channel_number': %s\n", 779 fiid_obj_errormsg (obj_cmd_rs)); 780 goto cleanup; 781 } 782 channel_number = val; 783 784 if (channel_number == IPMI_DCMI_CHANNEL_NOT_SUPPORTED) 785 pstdout_printf (state_data->pstate, 786 "Secondary LAN Out-of-band Channel Number : Not supported\n"); 787 else 788 pstdout_printf (state_data->pstate, 789 "Secondary LAN Out-of-band Channel Number : %u\n", 790 channel_number); 791 792 if (FIID_OBJ_GET (obj_cmd_rs, 793 "optional_serial_out_of_band_tmode_capability_channel_number", 794 &val) < 0) 795 { 796 pstdout_fprintf (state_data->pstate, 797 stderr, 798 "fiid_obj_get: 'optional_serial_out_of_band_tmode_capability_channel_number': %s\n", 799 fiid_obj_errormsg (obj_cmd_rs)); 800 goto cleanup; 801 } 802 channel_number = val; 803 804 if (channel_number == IPMI_DCMI_CHANNEL_NOT_SUPPORTED) 805 pstdout_printf (state_data->pstate, 806 "Serial Out-of-band TMODE Capability Channel Number : Not supported\n"); 807 else 808 pstdout_printf (state_data->pstate, 809 "Serial Out-of-band TMODE Capability Channel Number : %u\n", 810 channel_number); 811 812 rv = 1; 813 cleanup: 814 fiid_obj_destroy (obj_cmd_rs); 815 return (rv); 816 } 817 818 /* return 1 on output success, 0 on no output, -1 on error */ 819 static int 820 _get_enhanced_system_power_statistics_attributes (ipmi_dcmi_state_data_t *state_data, 821 uint8_t *number_of_supported_rolling_average_time_periods, 822 uint8_t *rolling_average_time_periods, 823 unsigned int rolling_average_time_periods_buflen) 824 { 825 fiid_obj_t obj_cmd_rs = NULL; 826 uint64_t val; 827 int len; 828 int rv = -1; 829 830 assert (state_data); 831 assert (number_of_supported_rolling_average_time_periods); 832 assert (rolling_average_time_periods); 833 assert (rolling_average_time_periods_buflen); 834 835 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_capability_info_enhanced_system_power_statistics_attributes_rs))) 836 { 837 pstdout_fprintf (state_data->pstate, 838 stderr, 839 "fiid_obj_create: %s\n", 840 strerror (errno)); 841 goto cleanup; 842 } 843 844 if (ipmi_cmd_dcmi_get_dcmi_capability_info_enhanced_system_power_statistics_attributes (state_data->ipmi_ctx, 845 obj_cmd_rs) < 0) 846 { 847 /* this optional parameter is not supported */ 848 if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 849 && ((ipmi_check_completion_code (obj_cmd_rs, 850 IPMI_COMP_CODE_REQUEST_PARAMETER_NOT_SUPPORTED) == 1) 851 || (ipmi_check_completion_code (obj_cmd_rs, 852 IPMI_COMP_CODE_REQUESTED_SENSOR_DATA_OR_RECORD_NOT_PRESENT) == 1))) 853 { 854 rv = 0; 855 goto cleanup; 856 } 857 858 pstdout_fprintf (state_data->pstate, 859 stderr, 860 "ipmi_cmd_dcmi_get_dcmi_capability_info_enhanced_system_power_statistics_attributes: %s\n", 861 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 862 goto cleanup; 863 } 864 865 if (FIID_OBJ_GET (obj_cmd_rs, 866 "number_of_supported_rolling_average_time_periods", 867 &val) < 0) 868 { 869 pstdout_fprintf (state_data->pstate, 870 stderr, 871 "fiid_obj_get: 'number_of_supported_rolling_average_time_periods': %s\n", 872 fiid_obj_errormsg (obj_cmd_rs)); 873 goto cleanup; 874 } 875 (*number_of_supported_rolling_average_time_periods) = val; 876 877 if ((len = fiid_obj_get_data (obj_cmd_rs, 878 "rolling_average_time_periods", 879 rolling_average_time_periods, 880 rolling_average_time_periods_buflen)) < 0) 881 { 882 pstdout_fprintf (state_data->pstate, 883 stderr, 884 "fiid_obj_get_data: 'rolling_average_time_periods': %s\n", 885 fiid_obj_errormsg (obj_cmd_rs)); 886 goto cleanup; 887 } 888 889 if ((*number_of_supported_rolling_average_time_periods) != len) 890 { 891 pstdout_fprintf (state_data->pstate, 892 stderr, 893 "invalid number of supported rolling average time periods reported: %u vs. %u\n", 894 (*number_of_supported_rolling_average_time_periods), 895 len); 896 goto cleanup; 897 } 898 899 if ((len = fiid_template_len_bytes (tmpl_dcmi_rolling_average_time_period)) < 0) 900 { 901 pstdout_fprintf (state_data->pstate, 902 stderr, 903 "fiid_template_len_bytes: %s\n", 904 strerror (errno)); 905 goto cleanup; 906 } 907 908 /* an "assertion" */ 909 if (len != 1) 910 { 911 pstdout_fprintf (state_data->pstate, 912 stderr, 913 "rolling average time period length invalid: %u\n", 914 len); 915 goto cleanup; 916 } 917 918 rv = 1; 919 cleanup: 920 fiid_obj_destroy (obj_cmd_rs); 921 return (rv); 922 } 923 924 static int 925 _get_time_duration_info (ipmi_dcmi_state_data_t *state_data, 926 uint8_t rolling_average_time_period, 927 uint8_t *time_duration, 928 char **time_duration_units_str) 929 { 930 fiid_obj_t obj_rolling_average_time_period = NULL; 931 uint8_t time_duration_units; 932 uint64_t val; 933 int rv = -1; 934 935 assert (state_data); 936 assert (time_duration); 937 assert (time_duration_units_str); 938 939 if (!(obj_rolling_average_time_period = fiid_obj_create (tmpl_dcmi_rolling_average_time_period))) 940 { 941 pstdout_fprintf (state_data->pstate, 942 stderr, 943 "fiid_obj_create: %s\n", 944 strerror (errno)); 945 goto cleanup; 946 } 947 948 if (fiid_obj_set_all (obj_rolling_average_time_period, 949 &rolling_average_time_period, 950 1) < 0) 951 { 952 pstdout_fprintf (state_data->pstate, 953 stderr, 954 "fiid_obj_set_all: %s\n", 955 fiid_obj_errormsg (obj_rolling_average_time_period)); 956 goto cleanup; 957 } 958 959 if (FIID_OBJ_GET (obj_rolling_average_time_period, 960 "time_duration", 961 &val) < 0) 962 { 963 pstdout_fprintf (state_data->pstate, 964 stderr, 965 "fiid_obj_get: 'time_duration': %s\n", 966 fiid_obj_errormsg (obj_rolling_average_time_period)); 967 goto cleanup; 968 } 969 (*time_duration) = val; 970 971 if (FIID_OBJ_GET (obj_rolling_average_time_period, 972 "time_duration_units", 973 &val) < 0) 974 { 975 pstdout_fprintf (state_data->pstate, 976 stderr, 977 "fiid_obj_get: 'time_duration_units': %s\n", 978 fiid_obj_errormsg (obj_rolling_average_time_period)); 979 goto cleanup; 980 } 981 time_duration_units = val; 982 983 if (time_duration_units == IPMI_DCMI_TIME_DURATION_UNITS_SECONDS) 984 (*time_duration_units_str) = "Seconds"; 985 else if (time_duration_units == IPMI_DCMI_TIME_DURATION_UNITS_MINUTES) 986 (*time_duration_units_str) = "Minutes"; 987 else if (time_duration_units == IPMI_DCMI_TIME_DURATION_UNITS_HOURS) 988 (*time_duration_units_str) = "Hours"; 989 else 990 (*time_duration_units_str) = "Days"; 991 992 rv = 0; 993 cleanup: 994 fiid_obj_destroy (obj_rolling_average_time_period); 995 return (rv); 996 } 997 998 /* return 1 on output success, 0 on no output, -1 on error */ 999 static int 1000 _enhanced_system_power_statistics_attributes (ipmi_dcmi_state_data_t *state_data) 1001 { 1002 uint8_t rolling_average_time_periods[IPMI_DCMI_ROLLING_AVERAGE_TIME_PERIOD_BUFLEN]; 1003 uint8_t number_of_supported_rolling_average_time_periods; 1004 int i; 1005 1006 assert (state_data); 1007 1008 if (_get_enhanced_system_power_statistics_attributes (state_data, 1009 &number_of_supported_rolling_average_time_periods, 1010 rolling_average_time_periods, 1011 IPMI_DCMI_ROLLING_AVERAGE_TIME_PERIOD_BUFLEN) < 0) 1012 return (-1); 1013 1014 for (i = 0; i < number_of_supported_rolling_average_time_periods; i++) 1015 { 1016 uint8_t time_duration; 1017 char *time_duration_units_str = NULL; 1018 1019 if (_get_time_duration_info (state_data, 1020 rolling_average_time_periods[i], 1021 &time_duration, 1022 &time_duration_units_str) < 0) 1023 return (-1); 1024 1025 pstdout_printf (state_data->pstate, 1026 "Available Rolling Average Time Period : %u %s\n", 1027 time_duration, 1028 time_duration_units_str); 1029 } 1030 1031 return (1); 1032 } 1033 1034 static int 1035 get_dcmi_capability_info (ipmi_dcmi_state_data_t *state_data) 1036 { 1037 uint8_t parameter_revision; 1038 int ret; 1039 1040 assert (state_data); 1041 1042 if ((ret = _dcmi_specification_conformance (state_data, ¶meter_revision)) < 0) 1043 return (-1); 1044 1045 if (ret) 1046 pstdout_printf (state_data->pstate, "\n"); 1047 1048 if ((ret = _supported_dcmi_capabilities (state_data)) < 0) 1049 return (-1); 1050 1051 if (ret) 1052 pstdout_printf (state_data->pstate, "\n"); 1053 1054 if ((ret = _mandatory_platform_attributes (state_data)) < 0) 1055 return (-1); 1056 1057 if (ret) 1058 pstdout_printf (state_data->pstate, "\n"); 1059 1060 if ((ret = _optional_platform_attributes (state_data)) < 0) 1061 return (-1); 1062 1063 if (ret) 1064 pstdout_printf (state_data->pstate, "\n"); 1065 1066 if ((ret = _manageability_access_attributes (state_data)) < 0) 1067 return (-1); 1068 1069 if (parameter_revision >= 0x02) 1070 { 1071 if (ret) 1072 pstdout_printf (state_data->pstate, "\n"); 1073 1074 if ((ret = _enhanced_system_power_statistics_attributes (state_data)) < 0) 1075 return (-1); 1076 } 1077 1078 return (0); 1079 } 1080 1081 static int 1082 get_asset_tag (ipmi_dcmi_state_data_t *state_data) 1083 { 1084 fiid_obj_t obj_cmd_rs = NULL; 1085 uint8_t asset_tag_data[IPMI_DCMI_MAX_ASSET_TAG_LENGTH + 1]; 1086 int data_len; 1087 unsigned int offset = 0; 1088 uint8_t total_asset_tag_length = 0; 1089 uint8_t bytes_to_read = IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_READ_MAX; 1090 int rv = -1; 1091 1092 assert (state_data); 1093 1094 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_asset_tag_rs))) 1095 { 1096 pstdout_fprintf (state_data->pstate, 1097 stderr, 1098 "fiid_obj_create: %s\n", 1099 strerror (errno)); 1100 goto cleanup; 1101 } 1102 1103 memset (asset_tag_data, '\0', IPMI_DCMI_MAX_ASSET_TAG_LENGTH + 1); 1104 1105 while (1) 1106 { 1107 uint64_t val; 1108 1109 if (!offset 1110 || ((total_asset_tag_length - offset) >= IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_READ_MAX)) 1111 bytes_to_read = IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_READ_MAX; 1112 else 1113 bytes_to_read = total_asset_tag_length - offset; 1114 1115 if (ipmi_cmd_dcmi_get_asset_tag (state_data->ipmi_ctx, 1116 offset, 1117 bytes_to_read, 1118 obj_cmd_rs) < 0) 1119 { 1120 pstdout_fprintf (state_data->pstate, 1121 stderr, 1122 "ipmi_cmd_dcmi_get_asset_tag: %s\n", 1123 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1124 goto cleanup; 1125 } 1126 1127 if (FIID_OBJ_GET (obj_cmd_rs, 1128 "total_asset_tag_length", 1129 &val) < 0) 1130 { 1131 pstdout_fprintf (state_data->pstate, 1132 stderr, 1133 "fiid_obj_get: 'total_asset_tag_length': %s\n", 1134 fiid_obj_errormsg (obj_cmd_rs)); 1135 goto cleanup; 1136 } 1137 total_asset_tag_length = val; 1138 1139 if (!total_asset_tag_length) 1140 break; 1141 1142 if ((data_len = fiid_obj_get_data (obj_cmd_rs, 1143 "data", 1144 asset_tag_data + offset, 1145 IPMI_DCMI_MAX_ASSET_TAG_LENGTH - offset)) < 0) 1146 { 1147 pstdout_fprintf (state_data->pstate, 1148 stderr, 1149 "fiid_obj_get_data: 'data': %s\n", 1150 fiid_obj_errormsg (obj_cmd_rs)); 1151 goto cleanup; 1152 } 1153 offset += data_len; 1154 1155 if (offset >= total_asset_tag_length) 1156 break; 1157 } 1158 1159 if (total_asset_tag_length) 1160 { 1161 /* Handle special case UTF-8 encoding w/ BOM prefix */ 1162 if (asset_tag_data[0] == IPMI_DCMI_ASSET_TAG_UTF8_BOM_BYTE0 1163 && asset_tag_data[1] == IPMI_DCMI_ASSET_TAG_UTF8_BOM_BYTE1 1164 && asset_tag_data[2] == IPMI_DCMI_ASSET_TAG_UTF8_BOM_BYTE2) 1165 /* achu: I think this is right for UTF-8 in libc and is 1166 * portable, but I would bet some systems won't like this. 1167 */ 1168 pstdout_printf (state_data->pstate, 1169 "%ls\n", 1170 &asset_tag_data[3]); 1171 else 1172 pstdout_printf (state_data->pstate, 1173 "%s\n", 1174 asset_tag_data); 1175 } 1176 1177 rv = 0; 1178 cleanup: 1179 fiid_obj_destroy (obj_cmd_rs); 1180 return (rv); 1181 } 1182 1183 static int 1184 set_asset_tag (ipmi_dcmi_state_data_t *state_data) 1185 { 1186 fiid_obj_t obj_cmd_rs = NULL; 1187 unsigned int offset = 0; 1188 char data_buf[IPMI_DCMI_MAX_ASSET_TAG_LENGTH + 1]; 1189 unsigned int data_len; 1190 uint8_t bytes_to_write = IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_WRITE_MAX; 1191 int rv = -1; 1192 1193 assert (state_data); 1194 1195 /* achu: 1196 * 1197 * DCMI v1.1 spec is unclear if the entire buffer needs to be 1198 * written or just the amount you desire. 1199 * 1200 * DCMI v1.5 spec strongly suggests you don't write the entire 1201 * buffer due to the results of the "total_asset_tag_length_written" 1202 * field. 1203 * 1204 * "Total Asset Tag Length. This is the length in bytes of the stored 1205 * Asset Tag after the Set operation has completed. The Asset Tag 1206 * length shall be set to the sum of the offset to write plus bytes 1207 * to write. For example, if offset to write is 32 and bytes to 1208 * write is 4, the Total Asset Tag Length returned will be 36." 1209 */ 1210 1211 data_len = strlen (state_data->prog_data->args->set_asset_tag_arg); 1212 1213 memset (data_buf, '\0', IPMI_DCMI_MAX_ASSET_TAG_LENGTH + 1); 1214 1215 memcpy (data_buf, 1216 state_data->prog_data->args->set_asset_tag_arg, 1217 strlen (state_data->prog_data->args->set_asset_tag_arg)); 1218 1219 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_set_asset_tag_rs))) 1220 { 1221 pstdout_fprintf (state_data->pstate, 1222 stderr, 1223 "fiid_obj_create: %s\n", 1224 strerror (errno)); 1225 goto cleanup; 1226 } 1227 1228 while (1) 1229 { 1230 uint64_t val; 1231 1232 if ((data_len - offset) >= IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_WRITE_MAX) 1233 bytes_to_write = IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_WRITE_MAX; 1234 else 1235 bytes_to_write = data_len - offset; 1236 1237 if (ipmi_cmd_dcmi_set_asset_tag (state_data->ipmi_ctx, 1238 offset, 1239 bytes_to_write, 1240 data_buf + offset, 1241 data_len, 1242 obj_cmd_rs) < 0) 1243 { 1244 pstdout_fprintf (state_data->pstate, 1245 stderr, 1246 "ipmi_cmd_dcmi_set_asset_tag: %s\n", 1247 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1248 goto cleanup; 1249 } 1250 1251 if (FIID_OBJ_GET (obj_cmd_rs, 1252 "total_asset_tag_length_written", 1253 &val) < 0) 1254 { 1255 pstdout_fprintf (state_data->pstate, 1256 stderr, 1257 "fiid_obj_get: 'total_asset_tag_length': %s\n", 1258 fiid_obj_errormsg (obj_cmd_rs)); 1259 goto cleanup; 1260 } 1261 1262 /* DCMI 1.1 spec is unclear on "total_length_written", is it the 1263 * number of bytes just written or total bytes written so far? 1264 * 1265 * DCMI 1.5 spec makes it clear that this is the number of bytes 1266 * written in total. To defend against vendor mistakes, we 1267 * handle both situations. 1268 */ 1269 if (val > bytes_to_write) 1270 offset += bytes_to_write; 1271 else 1272 offset += val; 1273 1274 if (offset >= data_len) 1275 break; 1276 } 1277 1278 rv = 0; 1279 cleanup: 1280 fiid_obj_destroy (obj_cmd_rs); 1281 return (rv); 1282 } 1283 1284 static int 1285 get_management_controller_identifier_string (ipmi_dcmi_state_data_t *state_data) 1286 { 1287 fiid_obj_t obj_cmd_rs = NULL; 1288 char management_controller_identifier_string_data[IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH + 1]; 1289 int data_len; 1290 unsigned int offset = 0; 1291 uint8_t total_length = 0; 1292 uint8_t bytes_to_read = IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_READ_MAX; 1293 int rv = -1; 1294 1295 assert (state_data); 1296 1297 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_management_controller_identifier_string_rs))) 1298 { 1299 pstdout_fprintf (state_data->pstate, 1300 stderr, 1301 "fiid_obj_create: %s\n", 1302 strerror (errno)); 1303 goto cleanup; 1304 } 1305 1306 memset (management_controller_identifier_string_data, '\0', IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH + 1); 1307 1308 while (1) 1309 { 1310 uint64_t val; 1311 1312 if (!offset 1313 || ((total_length - offset) >= IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_READ_MAX)) 1314 bytes_to_read = IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_READ_MAX; 1315 else 1316 bytes_to_read = total_length - offset; 1317 1318 if (ipmi_cmd_dcmi_get_management_controller_identifier_string (state_data->ipmi_ctx, 1319 offset, 1320 bytes_to_read, 1321 obj_cmd_rs) < 0) 1322 { 1323 pstdout_fprintf (state_data->pstate, 1324 stderr, 1325 "ipmi_cmd_dcmi_get_management_controller_identifier_string: %s\n", 1326 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1327 goto cleanup; 1328 } 1329 1330 if (FIID_OBJ_GET (obj_cmd_rs, 1331 "total_length", 1332 &val) < 0) 1333 { 1334 pstdout_fprintf (state_data->pstate, 1335 stderr, 1336 "fiid_obj_get: 'total_length': %s\n", 1337 fiid_obj_errormsg (obj_cmd_rs)); 1338 goto cleanup; 1339 } 1340 total_length = val; 1341 1342 if (!total_length) 1343 break; 1344 1345 if ((data_len = fiid_obj_get_data (obj_cmd_rs, 1346 "data", 1347 management_controller_identifier_string_data + offset, 1348 IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH - offset)) < 0) 1349 { 1350 pstdout_fprintf (state_data->pstate, 1351 stderr, 1352 "fiid_obj_get_data: 'data': %s\n", 1353 fiid_obj_errormsg (obj_cmd_rs)); 1354 goto cleanup; 1355 } 1356 offset += data_len; 1357 1358 if (offset >= total_length) 1359 break; 1360 } 1361 1362 if (total_length) 1363 pstdout_printf (state_data->pstate, 1364 "%s\n", 1365 management_controller_identifier_string_data); 1366 1367 rv = 0; 1368 cleanup: 1369 fiid_obj_destroy (obj_cmd_rs); 1370 return (rv); 1371 } 1372 1373 static int 1374 set_management_controller_identifier_string (ipmi_dcmi_state_data_t *state_data) 1375 { 1376 fiid_obj_t obj_cmd_rs = NULL; 1377 unsigned int offset = 0; 1378 char data_buf[IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH + 1]; 1379 unsigned int data_len; 1380 uint8_t bytes_to_write = IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_WRITE_MAX; 1381 int rv = -1; 1382 1383 assert (state_data); 1384 1385 /* achu: 1386 * 1387 * According to DCMI v1.5 draft 1388 * 1389 * "The presence of the null terminator among bytes to shall be 1390 * considered as indicating the last transfer of the Management 1391 * Controller Identifier string" 1392 * 1393 * So I am assuming we don't need to write the entire buffer. But 1394 * we must include the NUL byte at the end. 1395 */ 1396 1397 /* +1 for NUL char */ 1398 data_len = strlen (state_data->prog_data->args->set_management_controller_identifier_string_arg) + 1; 1399 1400 memset (data_buf, '\0', IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH + 1); 1401 1402 memcpy (data_buf, 1403 state_data->prog_data->args->set_management_controller_identifier_string_arg, 1404 strlen (state_data->prog_data->args->set_management_controller_identifier_string_arg)); 1405 1406 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_set_management_controller_identifier_string_rs))) 1407 { 1408 pstdout_fprintf (state_data->pstate, 1409 stderr, 1410 "fiid_obj_create: %s\n", 1411 strerror (errno)); 1412 goto cleanup; 1413 } 1414 1415 while (1) 1416 { 1417 uint64_t val; 1418 1419 if ((data_len - offset) >= IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_WRITE_MAX) 1420 bytes_to_write = IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_WRITE_MAX; 1421 else 1422 bytes_to_write = data_len - offset; 1423 1424 if (ipmi_cmd_dcmi_set_management_controller_identifier_string (state_data->ipmi_ctx, 1425 offset, 1426 bytes_to_write, 1427 data_buf + offset, 1428 data_len, 1429 obj_cmd_rs) < 0) 1430 { 1431 pstdout_fprintf (state_data->pstate, 1432 stderr, 1433 "ipmi_cmd_dcmi_set_management_controller_identifier_string: %s\n", 1434 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1435 goto cleanup; 1436 } 1437 1438 if (FIID_OBJ_GET (obj_cmd_rs, 1439 "total_length_written", 1440 &val) < 0) 1441 { 1442 pstdout_fprintf (state_data->pstate, 1443 stderr, 1444 "fiid_obj_get: 'total_management_controller_identifier_string_length': %s\n", 1445 fiid_obj_errormsg (obj_cmd_rs)); 1446 goto cleanup; 1447 } 1448 1449 1450 /* DCMI 1.1 spec is unclear on "total_length_written", is it the 1451 * number of bytes just written or total bytes written so far? 1452 * 1453 * DCMI 1.5 spec makes it clear that this is the number of bytes 1454 * written in total. To defend against vendor mistakes, we 1455 * handle both situations. 1456 */ 1457 if (val > bytes_to_write) 1458 offset += bytes_to_write; 1459 else 1460 offset += val; 1461 1462 if (offset >= data_len) 1463 break; 1464 } 1465 1466 rv = 0; 1467 cleanup: 1468 fiid_obj_destroy (obj_cmd_rs); 1469 return (rv); 1470 } 1471 1472 static char * 1473 _entity_string (uint8_t entity_id) 1474 { 1475 assert (IPMI_DCMI_ENTITY_ID_VALID (entity_id)); 1476 1477 if (entity_id == IPMI_DCMI_ENTITY_ID_INLET_TEMPERATURE) 1478 return IPMI_DCMI_ENTITY_ID_INLET_TEMPERATURE_STR; 1479 else if (entity_id == IPMI_DCMI_ENTITY_ID_CPU_TEMPERATURE) 1480 return IPMI_DCMI_ENTITY_ID_CPU_TEMPERATURE_STR; 1481 else 1482 return IPMI_DCMI_ENTITY_ID_BASEBOARD_TEMPERATURE_STR; 1483 } 1484 1485 static int 1486 _sensor_info_output (ipmi_dcmi_state_data_t *state_data, 1487 uint8_t sensor_type, 1488 uint8_t entity_id) 1489 { 1490 fiid_obj_t obj_cmd_rs = NULL; 1491 uint8_t entity_instance_start = 0x01; /* starts at 1, not 0 */ 1492 unsigned int total_entity_instances_parsed = 0; 1493 int rv = -1; 1494 1495 assert (state_data); 1496 assert (IPMI_SENSOR_TYPE_VALID (sensor_type)); 1497 assert (IPMI_DCMI_ENTITY_ID_VALID (entity_id)); 1498 1499 pstdout_printf (state_data->pstate, 1500 "%s SDR Record IDs\n", 1501 _entity_string (entity_id)); 1502 1503 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_dcmi_sensor_info_rs))) 1504 { 1505 pstdout_fprintf (state_data->pstate, 1506 stderr, 1507 "fiid_obj_create: %s\n", 1508 strerror (errno)); 1509 goto cleanup; 1510 } 1511 1512 while (1) 1513 { 1514 uint64_t val; 1515 uint8_t total_number_of_available_instances; 1516 uint8_t number_of_record_ids_in_this_response; 1517 uint8_t sdr_record_ids[IPMI_DCMI_MAX_RECORD_IDS_BUFLEN]; 1518 int sdr_record_ids_len; 1519 int i; 1520 1521 if (ipmi_cmd_dcmi_get_dcmi_sensor_info (state_data->ipmi_ctx, 1522 sensor_type, 1523 entity_id, 1524 IPMI_DCMI_ENTITY_INSTANCE_ALL, 1525 entity_instance_start, 1526 obj_cmd_rs) < 0) 1527 { 1528 pstdout_fprintf (state_data->pstate, 1529 stderr, 1530 "ipmi_cmd_dcmi_get_dcmi_sensor_info: %s\n", 1531 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1532 goto cleanup; 1533 } 1534 1535 if (FIID_OBJ_GET (obj_cmd_rs, 1536 "total_number_of_available_instances", 1537 &val) < 0) 1538 { 1539 pstdout_fprintf (state_data->pstate, 1540 stderr, 1541 "fiid_obj_get: 'total_number_of_available_instances': %s\n", 1542 fiid_obj_errormsg (obj_cmd_rs)); 1543 goto cleanup; 1544 } 1545 total_number_of_available_instances = val; 1546 1547 if (!total_number_of_available_instances) 1548 break; 1549 1550 if (FIID_OBJ_GET (obj_cmd_rs, 1551 "number_of_record_ids_in_this_response", 1552 &val) < 0) 1553 { 1554 pstdout_fprintf (state_data->pstate, 1555 stderr, 1556 "fiid_obj_get: 'number_of_record_ids_in_this_response': %s\n", 1557 fiid_obj_errormsg (obj_cmd_rs)); 1558 goto cleanup; 1559 } 1560 number_of_record_ids_in_this_response = val; 1561 1562 if (!number_of_record_ids_in_this_response) 1563 break; 1564 1565 if ((sdr_record_ids_len = fiid_obj_get_data (obj_cmd_rs, 1566 "sdr_record_ids", 1567 sdr_record_ids, 1568 IPMI_DCMI_MAX_RECORD_IDS_BUFLEN)) < 0) 1569 { 1570 pstdout_fprintf (state_data->pstate, 1571 stderr, 1572 "fiid_obj_get_data: 'sdr_record_ids': %s\n", 1573 fiid_obj_errormsg (obj_cmd_rs)); 1574 goto cleanup; 1575 } 1576 1577 if (sdr_record_ids_len % 2) 1578 { 1579 pstdout_fprintf (state_data->pstate, 1580 stderr, 1581 "invalid sdr_record_ids length returned: %u\n", 1582 sdr_record_ids_len); 1583 goto cleanup; 1584 } 1585 1586 if (number_of_record_ids_in_this_response > (sdr_record_ids_len / 2)) 1587 { 1588 pstdout_fprintf (state_data->pstate, 1589 stderr, 1590 "invalid sdr_record_ids returned: %u > %u\n", 1591 number_of_record_ids_in_this_response, 1592 (sdr_record_ids_len / 2)); 1593 goto cleanup; 1594 } 1595 1596 for (i = 0; i < (number_of_record_ids_in_this_response * 2); i += 2) 1597 { 1598 uint16_t record_id = 0; 1599 1600 record_id |= sdr_record_ids[i]; 1601 record_id |= (sdr_record_ids[i+1] << 8); 1602 1603 pstdout_printf (state_data->pstate, 1604 "%u\n", 1605 record_id); 1606 total_entity_instances_parsed++; 1607 } 1608 1609 /* achu: entity IDs are returned sequentially? If not, I'm not 1610 * sure how this API can even work, you wouldn't know where to 1611 * start the next time around. Hopefully this is a correct 1612 * assumption 1613 */ 1614 /* HLiebig: Note: Intel simply increments the offset by 8 (max number of 1615 * SDR Id's per response. 1616 * See dcmitool from www.intel.com/go/DCMI (a modified ipmitool) 1617 */ 1618 1619 entity_instance_start += number_of_record_ids_in_this_response; 1620 1621 if (total_entity_instances_parsed >= total_number_of_available_instances) 1622 break; 1623 } 1624 1625 rv = 0; 1626 cleanup: 1627 fiid_obj_destroy (obj_cmd_rs); 1628 return (rv); 1629 } 1630 1631 static int 1632 get_dcmi_sensor_info (ipmi_dcmi_state_data_t *state_data) 1633 { 1634 int rv = -1; 1635 1636 assert (state_data); 1637 1638 if (_sensor_info_output (state_data, 1639 IPMI_SENSOR_TYPE_TEMPERATURE, 1640 IPMI_DCMI_ENTITY_ID_INLET_TEMPERATURE) < 0) 1641 goto cleanup; 1642 1643 pstdout_printf (state_data->pstate, "\n"); 1644 1645 if (_sensor_info_output (state_data, 1646 IPMI_SENSOR_TYPE_TEMPERATURE, 1647 IPMI_DCMI_ENTITY_ID_CPU_TEMPERATURE) < 0) 1648 goto cleanup; 1649 1650 pstdout_printf (state_data->pstate, "\n"); 1651 1652 if (_sensor_info_output (state_data, 1653 IPMI_SENSOR_TYPE_TEMPERATURE, 1654 IPMI_DCMI_ENTITY_ID_BASEBOARD_TEMPERATURE) < 0) 1655 goto cleanup; 1656 1657 rv = 0; 1658 cleanup: 1659 return (rv); 1660 } 1661 1662 static int 1663 _output_power_statistics (ipmi_dcmi_state_data_t *state_data, 1664 uint8_t mode, 1665 uint8_t mode_attributes) 1666 { 1667 fiid_obj_t obj_cmd_rs = NULL; 1668 uint16_t current_power; 1669 uint16_t minimum_power_over_sampling_duration; 1670 uint16_t maximum_power_over_sampling_duration; 1671 uint16_t average_power_over_sampling_duration; 1672 uint32_t time_stamp; 1673 uint32_t statistics_reporting_time_period; 1674 uint8_t power_measurement; 1675 uint64_t val; 1676 char timestr[IPMI_DCMI_TIME_BUFLEN + 1]; 1677 int rv = -1; 1678 1679 assert (state_data); 1680 1681 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_power_reading_rs))) 1682 { 1683 pstdout_fprintf (state_data->pstate, 1684 stderr, 1685 "fiid_obj_create: %s\n", 1686 strerror (errno)); 1687 goto cleanup; 1688 } 1689 1690 if (ipmi_cmd_dcmi_get_power_reading (state_data->ipmi_ctx, 1691 mode, 1692 mode_attributes, 1693 obj_cmd_rs) < 0) 1694 { 1695 pstdout_fprintf (state_data->pstate, 1696 stderr, 1697 "ipmi_cmd_dcmi_get_power_reading: %s\n", 1698 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1699 goto cleanup; 1700 } 1701 1702 if (FIID_OBJ_GET (obj_cmd_rs, 1703 "current_power", 1704 &val) < 0) 1705 { 1706 pstdout_fprintf (state_data->pstate, 1707 stderr, 1708 "fiid_obj_get: 'current_power': %s\n", 1709 fiid_obj_errormsg (obj_cmd_rs)); 1710 goto cleanup; 1711 } 1712 current_power = val; 1713 1714 if (FIID_OBJ_GET (obj_cmd_rs, 1715 "minimum_power_over_sampling_duration", 1716 &val) < 0) 1717 { 1718 pstdout_fprintf (state_data->pstate, 1719 stderr, 1720 "fiid_obj_get: 'minimum_power_over_sampling_duration': %s\n", 1721 fiid_obj_errormsg (obj_cmd_rs)); 1722 goto cleanup; 1723 } 1724 minimum_power_over_sampling_duration = val; 1725 1726 if (FIID_OBJ_GET (obj_cmd_rs, 1727 "maximum_power_over_sampling_duration", 1728 &val) < 0) 1729 { 1730 pstdout_fprintf (state_data->pstate, 1731 stderr, 1732 "fiid_obj_get: 'maximum_power_over_sampling_duration': %s\n", 1733 fiid_obj_errormsg (obj_cmd_rs)); 1734 goto cleanup; 1735 } 1736 maximum_power_over_sampling_duration = val; 1737 1738 if (FIID_OBJ_GET (obj_cmd_rs, 1739 "average_power_over_sampling_duration", 1740 &val) < 0) 1741 { 1742 pstdout_fprintf (state_data->pstate, 1743 stderr, 1744 "fiid_obj_get: 'average_power_over_sampling_duration': %s\n", 1745 fiid_obj_errormsg (obj_cmd_rs)); 1746 goto cleanup; 1747 } 1748 average_power_over_sampling_duration = val; 1749 1750 if (FIID_OBJ_GET (obj_cmd_rs, 1751 "time_stamp", 1752 &val) < 0) 1753 { 1754 pstdout_fprintf (state_data->pstate, 1755 stderr, 1756 "fiid_obj_get: 'time_stamp': %s\n", 1757 fiid_obj_errormsg (obj_cmd_rs)); 1758 goto cleanup; 1759 } 1760 time_stamp = val; 1761 1762 if (FIID_OBJ_GET (obj_cmd_rs, 1763 "statistics_reporting_time_period", 1764 &val) < 0) 1765 { 1766 pstdout_fprintf (state_data->pstate, 1767 stderr, 1768 "fiid_obj_get: 'statistics_reporting_time_period': %s\n", 1769 fiid_obj_errormsg (obj_cmd_rs)); 1770 goto cleanup; 1771 } 1772 statistics_reporting_time_period = val; 1773 1774 if (FIID_OBJ_GET (obj_cmd_rs, 1775 "power_reading_state.power_measurement", 1776 &val) < 0) 1777 { 1778 pstdout_fprintf (state_data->pstate, 1779 stderr, 1780 "fiid_obj_get: 'power_measurement': %s\n", 1781 fiid_obj_errormsg (obj_cmd_rs)); 1782 goto cleanup; 1783 } 1784 power_measurement = val; 1785 1786 pstdout_printf (state_data->pstate, 1787 "Current Power : %u Watts\n", 1788 current_power); 1789 1790 pstdout_printf (state_data->pstate, 1791 "Minimum Power over sampling duration : %u watts\n", 1792 minimum_power_over_sampling_duration); 1793 1794 pstdout_printf (state_data->pstate, 1795 "Maximum Power over sampling duration : %u watts\n", 1796 maximum_power_over_sampling_duration); 1797 1798 pstdout_printf (state_data->pstate, 1799 "Average Power over sampling duration : %u watts\n", 1800 average_power_over_sampling_duration); 1801 1802 memset (timestr, '\0', IPMI_DCMI_TIME_BUFLEN + 1); 1803 1804 if (ipmi_timestamp_string (time_stamp, 1805 state_data->prog_data->args->common_args.utc_offset, 1806 get_timestamp_flags (&(state_data->prog_data->args->common_args), 1807 IPMI_TIMESTAMP_FLAG_DEFAULT), 1808 "%m/%d/%Y - %H:%M:%S", 1809 timestr, 1810 IPMI_DCMI_TIME_BUFLEN) < 0) 1811 { 1812 pstdout_fprintf (state_data->pstate, 1813 stderr, 1814 "ipmi_timestamp_string: %s\n", 1815 strerror (errno)); 1816 goto cleanup; 1817 } 1818 1819 pstdout_printf (state_data->pstate, 1820 "Time Stamp : %s\n", 1821 timestr); 1822 1823 pstdout_printf (state_data->pstate, 1824 "Statistics reporting time period : %u milliseconds\n", 1825 statistics_reporting_time_period); 1826 1827 pstdout_printf (state_data->pstate, 1828 "Power Measurement : %s\n", 1829 (power_measurement) ? "Active" : "Not Available"); 1830 1831 rv = 0; 1832 cleanup: 1833 fiid_obj_destroy (obj_cmd_rs); 1834 return (rv); 1835 } 1836 1837 static int 1838 get_system_power_statistics (ipmi_dcmi_state_data_t *state_data) 1839 { 1840 assert (state_data); 1841 1842 if (_output_power_statistics (state_data, 1843 IPMI_DCMI_POWER_READING_MODE_SYSTEM_POWER_STATISTICS, 1844 0) < 0) 1845 return (-1); 1846 1847 return (0); 1848 } 1849 1850 static int 1851 get_enhanced_system_power_statistics (ipmi_dcmi_state_data_t *state_data) 1852 { 1853 uint8_t rolling_average_time_periods[IPMI_DCMI_ROLLING_AVERAGE_TIME_PERIOD_BUFLEN]; 1854 uint8_t number_of_supported_rolling_average_time_periods = 0; 1855 int i; 1856 1857 assert (state_data); 1858 1859 if (_get_enhanced_system_power_statistics_attributes (state_data, 1860 &number_of_supported_rolling_average_time_periods, 1861 rolling_average_time_periods, 1862 IPMI_DCMI_ROLLING_AVERAGE_TIME_PERIOD_BUFLEN) < 0) 1863 return (-1); 1864 1865 1866 for (i = 0; i < number_of_supported_rolling_average_time_periods; i++) 1867 { 1868 uint8_t time_duration; 1869 char *time_duration_units_str = NULL; 1870 1871 if (_get_time_duration_info (state_data, 1872 rolling_average_time_periods[i], 1873 &time_duration, 1874 &time_duration_units_str) < 0) 1875 return (-1); 1876 1877 pstdout_printf (state_data->pstate, 1878 "Power Statistics for Rolling Average Time Period %u %s\n", 1879 time_duration, 1880 time_duration_units_str); 1881 1882 pstdout_printf (state_data->pstate, "\n"); 1883 1884 if (_output_power_statistics (state_data, 1885 IPMI_DCMI_POWER_READING_MODE_ENHANCED_SYSTEM_POWER_STATISTICS, 1886 rolling_average_time_periods[i]) < 0) 1887 return (-1); 1888 } 1889 1890 return (0); 1891 } 1892 1893 static int 1894 _get_power_limit (ipmi_dcmi_state_data_t *state_data, 1895 uint8_t *exception_actions, 1896 uint16_t *power_limit_requested, 1897 uint32_t *correction_time_limit, 1898 uint16_t *management_application_statistics_sampling_period, 1899 uint8_t *comp_code, 1900 char *errorbuf, 1901 unsigned int errorbuflen) 1902 1903 { 1904 fiid_obj_t obj_cmd_rs = NULL; 1905 uint64_t val; 1906 int no_set_power_limit_error_flag = 0; 1907 int rv = -1; 1908 1909 assert (state_data); 1910 assert (exception_actions); 1911 assert (power_limit_requested); 1912 assert (correction_time_limit); 1913 assert (management_application_statistics_sampling_period); 1914 assert (errorbuf); 1915 assert (errorbuflen); 1916 1917 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_power_limit_rs))) 1918 { 1919 snprintf (errorbuf, 1920 errorbuflen, 1921 "fiid_obj_create: %s", 1922 strerror (errno)); 1923 goto cleanup; 1924 } 1925 1926 /* IPMI Workaround/Interpretation 1927 * 1928 * The DCMI spec indicates a potential completion code for the "Get 1929 * Power Limit" command as "No Set Power Limit" (0x80). FreeIPMI 1930 * originally interpreted this to mean the "Set Power Limit" command 1931 * was not available. Atleast one vendor interpreted this to mean 1932 * "No Power Limit Set". One can consider this an English 1933 * interpretation issue of 'No set POWER LIMIT' vs. 'No SET POWER 1934 * LIMIT' (i.e. is "set" a verb or part of a proper noun referencing 1935 * the DCMI command). Confounding this issue is the fact that the 1936 * example implementation in Intel's DCMItool implements the former, 1937 * while the DCMI Conformance test suite implements the latter. In 1938 * addition to this, with the latter interpretation, it need not be 1939 * an indication of an error, but rather a flag. So the rest of the 1940 * packet can be completely full of legitimate data. 1941 * 1942 * So how do we handle this? 1943 * 1944 * If we hit "No Set Power Limit", try to read data. If we can't 1945 * read data (b/c it's not set), fail out, but preserve the "No Set 1946 * Power Limit" error message. 1947 */ 1948 1949 if (ipmi_cmd_dcmi_get_power_limit (state_data->ipmi_ctx, 1950 obj_cmd_rs) < 0) 1951 { 1952 if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 1953 && comp_code) 1954 { 1955 (*comp_code) = 0; 1956 if (FIID_OBJ_GET (obj_cmd_rs, "comp_code", &val) < 0) 1957 { 1958 snprintf (errorbuf, 1959 errorbuflen, 1960 "fiid_obj_get: 'comp_code': %s", 1961 fiid_obj_errormsg (obj_cmd_rs)); 1962 goto cleanup; 1963 } 1964 (*comp_code) = val; 1965 } 1966 1967 if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 1968 && ipmi_check_completion_code (obj_cmd_rs, 1969 IPMI_COMP_CODE_DCMI_NO_SET_POWER_LIMIT) == 1) 1970 { 1971 snprintf (errorbuf, 1972 errorbuflen, 1973 "ipmi_cmd_dcmi_get_power_limit: %s", 1974 IPMI_COMP_CODE_DCMI_NO_SET_POWER_LIMIT_STR); 1975 no_set_power_limit_error_flag++; 1976 goto read_data; 1977 } 1978 else 1979 snprintf (errorbuf, 1980 errorbuflen, 1981 "ipmi_cmd_dcmi_get_power_limit: %s", 1982 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 1983 1984 goto cleanup; 1985 } 1986 1987 read_data: 1988 1989 if (FIID_OBJ_GET (obj_cmd_rs, 1990 "exception_actions", 1991 &val) < 0) 1992 { 1993 if (!no_set_power_limit_error_flag 1994 || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE) 1995 snprintf (errorbuf, 1996 errorbuflen, 1997 "fiid_obj_get: 'exception_actions': %s", 1998 fiid_obj_errormsg (obj_cmd_rs)); 1999 goto cleanup; 2000 } 2001 (*exception_actions) = val; 2002 2003 if (FIID_OBJ_GET (obj_cmd_rs, 2004 "power_limit_requested", 2005 &val) < 0) 2006 { 2007 if (!no_set_power_limit_error_flag 2008 || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE) 2009 snprintf (errorbuf, 2010 errorbuflen, 2011 "fiid_obj_get: 'power_limit_requested': %s", 2012 fiid_obj_errormsg (obj_cmd_rs)); 2013 goto cleanup; 2014 } 2015 (*power_limit_requested) = val; 2016 2017 if (FIID_OBJ_GET (obj_cmd_rs, 2018 "correction_time_limit", 2019 &val) < 0) 2020 { 2021 if (!no_set_power_limit_error_flag 2022 || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE) 2023 snprintf (errorbuf, 2024 errorbuflen, 2025 "fiid_obj_get: 'correction_time_limit': %s", 2026 fiid_obj_errormsg (obj_cmd_rs)); 2027 goto cleanup; 2028 } 2029 (*correction_time_limit) = val; 2030 2031 if (FIID_OBJ_GET (obj_cmd_rs, 2032 "management_application_statistics_sampling_period", 2033 &val) < 0) 2034 { 2035 if (!no_set_power_limit_error_flag 2036 || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE) 2037 snprintf (errorbuf, 2038 errorbuflen, 2039 "fiid_obj_get: 'management_application_statistics_sampling_period': %s", 2040 fiid_obj_errormsg (obj_cmd_rs)); 2041 goto cleanup; 2042 } 2043 (*management_application_statistics_sampling_period) = val; 2044 2045 rv = 0; 2046 cleanup: 2047 fiid_obj_destroy (obj_cmd_rs); 2048 return (rv); 2049 } 2050 2051 2052 static int 2053 get_power_limit (ipmi_dcmi_state_data_t *state_data) 2054 { 2055 uint8_t exception_actions; 2056 uint16_t power_limit_requested; 2057 uint32_t correction_time_limit; 2058 uint16_t management_application_statistics_sampling_period; 2059 char errorbuf[IPMI_DCMI_ERROR_BUFLEN + 1]; 2060 2061 assert (state_data); 2062 2063 memset (errorbuf, '\0', IPMI_DCMI_ERROR_BUFLEN + 1); 2064 2065 if (_get_power_limit (state_data, 2066 &exception_actions, 2067 &power_limit_requested, 2068 &correction_time_limit, 2069 &management_application_statistics_sampling_period, 2070 NULL, /* comp_code */ 2071 errorbuf, 2072 IPMI_DCMI_ERROR_BUFLEN) < 0) 2073 { 2074 pstdout_fprintf (state_data->pstate, 2075 stderr, 2076 "%s\n", 2077 errorbuf); 2078 return (-1); 2079 } 2080 2081 /* XXX: figure out OEM specifics, and list details given manufacturer ID/product ID */ 2082 /* 2083 2084 From Holger Liebig at Fujitsu 2085 2086 "Regarding OEM exception action we currently do support 'continue' 2087 (0x02) and 'shutdown' (0x03) in addition to the 'hard power off'." 2088 2089 But I don't know what the manufacturer ID and product ID are, so we leave it out for now. 2090 2091 */ 2092 2093 if (exception_actions == IPMI_DCMI_EXCEPTION_ACTION_NO_ACTION) 2094 pstdout_printf (state_data->pstate, 2095 "Exception Actions : No Action (%Xh)\n", 2096 exception_actions); 2097 else if (exception_actions == IPMI_DCMI_EXCEPTION_ACTION_HARD_POWER_OFF_SYSTEM) 2098 pstdout_printf (state_data->pstate, 2099 "Exception Actions : Hard Power Off system (%Xh)\n", 2100 exception_actions); 2101 else if (exception_actions == IPMI_DCMI_EXCEPTION_ACTION_LOG_EVENT_TO_SEL_ONLY) 2102 pstdout_printf (state_data->pstate, 2103 "Exception Actions : Log event to SEL only (%Xh)\n", 2104 exception_actions); 2105 else if ((exception_actions >= IPMI_DCMI_EXCEPTION_ACTION_OEM_MIN) 2106 && (exception_actions <= IPMI_DCMI_EXCEPTION_ACTION_OEM_MAX)) 2107 pstdout_printf (state_data->pstate, 2108 "Exception Actions : OEM action (%Xh)\n", 2109 exception_actions); 2110 else 2111 pstdout_printf (state_data->pstate, 2112 "Exception Actions : Unknown action (%Xh)\n", 2113 exception_actions); 2114 2115 pstdout_printf (state_data->pstate, 2116 "Power Limit Requested : %u watts\n", 2117 power_limit_requested); 2118 2119 pstdout_printf (state_data->pstate, 2120 "Correction time limit : %u milliseconds\n", 2121 correction_time_limit); 2122 2123 pstdout_printf (state_data->pstate, 2124 "Management application Statistics Sampling period : %u seconds\n", 2125 management_application_statistics_sampling_period); 2126 2127 return (0); 2128 } 2129 2130 static int 2131 set_power_limit (ipmi_dcmi_state_data_t *state_data) 2132 { 2133 struct ipmi_dcmi_arguments *args; 2134 fiid_obj_t obj_cmd_rs = NULL; 2135 uint8_t comp_code = 0; 2136 uint8_t exception_actions; 2137 uint16_t power_limit_requested; 2138 uint32_t correction_time_limit; 2139 uint16_t management_application_statistics_sampling_period; 2140 char errorbuf[IPMI_DCMI_ERROR_BUFLEN + 1]; 2141 int rv = -1; 2142 2143 assert (state_data); 2144 assert (state_data->prog_data->args->exception_actions 2145 || state_data->prog_data->args->power_limit_requested 2146 || state_data->prog_data->args->correction_time_limit 2147 || state_data->prog_data->args->statistics_sampling_period); 2148 2149 args = state_data->prog_data->args; 2150 2151 memset (errorbuf, '\0', IPMI_DCMI_ERROR_BUFLEN + 1); 2152 2153 if (_get_power_limit (state_data, 2154 &exception_actions, 2155 &power_limit_requested, 2156 &correction_time_limit, 2157 &management_application_statistics_sampling_period, 2158 &comp_code, 2159 errorbuf, 2160 IPMI_DCMI_ERROR_BUFLEN) < 0) 2161 { 2162 /* IPMI Workaround/Interpretation 2163 * 2164 * The DCMI spec indicates a potential completion code for the 2165 * "Get Power Limit" command as "No Set Power Limit" (0x80). 2166 * FreeIPMI originally interpreted this to mean the "Set Power 2167 * Limit" command was not available. Atleast one vendor 2168 * interpreted this to mean "No Power Limit Set". One can 2169 * consider this an English interpretation issue of 'No set 2170 * POWER LIMIT' vs. 'No SET POWER LIMIT' (i.e. is "set" a verb 2171 * or part of a proper noun referencing the DCMI command). 2172 * Confounding this issue is the fact that the example 2173 * implementation in Intel's DCMItool implements the former, 2174 * while the DCMI Conformance test suite implements the latter. 2175 * In addition to this, with the latter interpretation, it need 2176 * not be an indication of an error, but rather a flag. So the 2177 * rest of the packet can be completely full of legitimate data. 2178 * 2179 * So we will do the following. 2180 * 2181 * If the "No Set Power Limit" completion code is returned and 2182 * we were able to read all of the fields, _get_power_limit() will 2183 * return normally and this error fallthrough won't occur. 2184 * 2185 * If the "No Set Power Limit", completion code is returned and 2186 * we were *not* able to read all of the fields, we won't have 2187 * values from "Get Power Limit" and won't know how to do the 2188 * configuration properly in "Set Power Limit". So we will 2189 * require that the user input all fields for "Set Power Limit". 2190 */ 2191 if (comp_code == IPMI_COMP_CODE_DCMI_NO_SET_POWER_LIMIT) 2192 { 2193 if (!args->exception_actions 2194 || !args->power_limit_requested 2195 || !args->correction_time_limit 2196 || !args->statistics_sampling_period) 2197 { 2198 pstdout_fprintf (state_data->pstate, 2199 stderr, 2200 "Must specify --exception-actions, --power-limit-requested, " 2201 "--correction-time-limit, and --statistics-sampling-period\n"); 2202 goto cleanup; 2203 } 2204 } 2205 else 2206 { 2207 pstdout_fprintf (state_data->pstate, 2208 stderr, 2209 "%s\n", 2210 errorbuf); 2211 goto cleanup; 2212 } 2213 } 2214 2215 if (!args->exception_actions) 2216 args->exception_actions_arg = exception_actions; 2217 2218 if (!args->power_limit_requested) 2219 args->power_limit_requested_arg = power_limit_requested; 2220 2221 if (!args->correction_time_limit) 2222 args->correction_time_limit_arg = correction_time_limit; 2223 2224 if (!args->statistics_sampling_period) 2225 args->statistics_sampling_period_arg = management_application_statistics_sampling_period; 2226 2227 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_set_power_limit_rs))) 2228 { 2229 pstdout_fprintf (state_data->pstate, 2230 stderr, 2231 "fiid_obj_create: %s\n", 2232 strerror (errno)); 2233 goto cleanup; 2234 } 2235 2236 if (ipmi_cmd_dcmi_set_power_limit (state_data->ipmi_ctx, 2237 args->exception_actions_arg, 2238 args->power_limit_requested_arg, 2239 args->correction_time_limit_arg, 2240 args->statistics_sampling_period_arg, 2241 obj_cmd_rs) < 0) 2242 { 2243 if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 2244 && ipmi_check_completion_code (obj_cmd_rs, 2245 IPMI_COMP_CODE_DCMI_POWER_LIMIT_OUT_OF_RANGE) == 1) 2246 pstdout_fprintf (state_data->pstate, 2247 stderr, 2248 "ipmi_cmd_dcmi_set_power_limit: %s\n", 2249 IPMI_COMP_CODE_DCMI_POWER_LIMIT_OUT_OF_RANGE_STR); 2250 else if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 2251 && ipmi_check_completion_code (obj_cmd_rs, 2252 IPMI_COMP_CODE_DCMI_CORRECTION_TIME_OUT_OF_RANGE) == 1) 2253 pstdout_fprintf (state_data->pstate, 2254 stderr, 2255 "ipmi_cmd_dcmi_set_power_limit: %s\n", 2256 IPMI_COMP_CODE_DCMI_CORRECTION_TIME_OUT_OF_RANGE_STR); 2257 else if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE 2258 && ipmi_check_completion_code (obj_cmd_rs, 2259 IPMI_COMP_CODE_DCMI_STATISTICS_REPORTING_PERIOD_OUT_OF_RANGE) == 1) 2260 pstdout_fprintf (state_data->pstate, 2261 stderr, 2262 "ipmi_cmd_dcmi_set_power_limit: %s\n", 2263 IPMI_COMP_CODE_DCMI_STATISTICS_REPORTING_PERIOD_OUT_OF_RANGE_STR); 2264 else 2265 pstdout_fprintf (state_data->pstate, 2266 stderr, 2267 "ipmi_cmd_dcmi_set_power_limit: %s\n", 2268 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 2269 goto cleanup; 2270 } 2271 2272 rv = 0; 2273 cleanup: 2274 fiid_obj_destroy (obj_cmd_rs); 2275 return (rv); 2276 } 2277 2278 static int 2279 activate_deactivate_power_limit (ipmi_dcmi_state_data_t *state_data) 2280 { 2281 struct ipmi_dcmi_arguments *args; 2282 fiid_obj_t obj_cmd_rs = NULL; 2283 int rv = -1; 2284 2285 assert (state_data); 2286 2287 args = state_data->prog_data->args; 2288 2289 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_activate_deactivate_power_limit_rs))) 2290 { 2291 pstdout_fprintf (state_data->pstate, 2292 stderr, 2293 "fiid_obj_create: %s\n", 2294 strerror (errno)); 2295 goto cleanup; 2296 } 2297 2298 if (ipmi_cmd_dcmi_activate_deactivate_power_limit (state_data->ipmi_ctx, 2299 args->activate_deactivate_power_limit_arg, 2300 obj_cmd_rs) < 0) 2301 { 2302 pstdout_fprintf (state_data->pstate, 2303 stderr, 2304 "ipmi_cmd_dcmi_activate_deactivate_power_limit: %s\n", 2305 ipmi_ctx_errormsg (state_data->ipmi_ctx)); 2306 goto cleanup; 2307 } 2308 2309 rv = 0; 2310 cleanup: 2311 fiid_obj_destroy (obj_cmd_rs); 2312 return (rv); 2313 } 2314 2315 static int 2316 run_cmd_args (ipmi_dcmi_state_data_t *state_data) 2317 { 2318 struct ipmi_dcmi_arguments *args; 2319 int rv = -1; 2320 2321 assert (state_data); 2322 2323 args = state_data->prog_data->args; 2324 2325 if (args->get_dcmi_capability_info) 2326 return (get_dcmi_capability_info (state_data)); 2327 2328 if (args->get_system_power_statistics) 2329 return (get_system_power_statistics (state_data)); 2330 2331 if (args->get_enhanced_system_power_statistics) 2332 return (get_enhanced_system_power_statistics (state_data)); 2333 2334 if (args->get_asset_tag) 2335 return (get_asset_tag (state_data)); 2336 2337 if (args->set_asset_tag) 2338 return (set_asset_tag (state_data)); 2339 2340 if (args->get_management_controller_identifier_string) 2341 return (get_management_controller_identifier_string (state_data)); 2342 2343 if (args->set_management_controller_identifier_string) 2344 return (set_management_controller_identifier_string (state_data)); 2345 2346 if (args->get_dcmi_sensor_info) 2347 return (get_dcmi_sensor_info (state_data)); 2348 2349 if (args->get_power_limit) 2350 return (get_power_limit (state_data)); 2351 2352 if (args->set_power_limit) 2353 return (set_power_limit (state_data)); 2354 2355 if (args->activate_deactivate_power_limit) 2356 return (activate_deactivate_power_limit (state_data)); 2357 2358 rv = 0; 2359 return (rv); 2360 } 2361 2362 static int 2363 _ipmi_dcmi (pstdout_state_t pstate, 2364 const char *hostname, 2365 void *arg) 2366 { 2367 ipmi_dcmi_state_data_t state_data; 2368 ipmi_dcmi_prog_data_t *prog_data; 2369 int exit_code = EXIT_FAILURE; 2370 2371 assert (pstate); 2372 assert (arg); 2373 2374 prog_data = (ipmi_dcmi_prog_data_t *)arg; 2375 memset (&state_data, '\0', sizeof (ipmi_dcmi_state_data_t)); 2376 2377 state_data.prog_data = prog_data; 2378 state_data.pstate = pstate; 2379 2380 if (!(state_data.ipmi_ctx = ipmi_open (prog_data->progname, 2381 hostname, 2382 &(prog_data->args->common_args), 2383 state_data.pstate, 2384 0))) 2385 goto cleanup; 2386 2387 if (run_cmd_args (&state_data) < 0) 2388 goto cleanup; 2389 2390 exit_code = EXIT_SUCCESS; 2391 cleanup: 2392 ipmi_ctx_close (state_data.ipmi_ctx); 2393 ipmi_ctx_destroy (state_data.ipmi_ctx); 2394 return (exit_code); 2395 } 2396 2397 int 2398 main (int argc, char **argv) 2399 { 2400 ipmi_dcmi_prog_data_t prog_data; 2401 struct ipmi_dcmi_arguments cmd_args; 2402 int hosts_count; 2403 int rv; 2404 2405 ipmi_disable_coredump (); 2406 2407 prog_data.progname = argv[0]; 2408 ipmi_dcmi_argp_parse (argc, argv, &cmd_args); 2409 prog_data.args = &cmd_args; 2410 2411 if ((hosts_count = pstdout_setup (&(prog_data.args->common_args.hostname), 2412 &(prog_data.args->common_args))) < 0) 2413 return (EXIT_FAILURE); 2414 2415 if (!hosts_count) 2416 return (EXIT_SUCCESS); 2417 2418 if ((rv = pstdout_launch (prog_data.args->common_args.hostname, 2419 _ipmi_dcmi, 2420 &prog_data)) < 0) 2421 { 2422 fprintf (stderr, 2423 "pstdout_launch: %s\n", 2424 pstdout_strerror (pstdout_errnum)); 2425 return (EXIT_FAILURE); 2426 } 2427 2428 return (rv); 2429 } 2430