1
/* nut-libfreeipmi.c - NUT IPMI backend, using FreeIPMI
4
* 2011 - 2012 Arnaud Quette <arnaud.quette@free.fr>
5
* 2011 - Albert Chu <chu11@llnl.gov>
7
* Based on the sample codes 'ipmi-fru-example.c', 'frulib.c' and
8
* 'ipmimonitoring-sensors.c', from FreeIPMI
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
* add power control support (ipmipower): seems OOB only!
26
-n, --on Power on the target hosts.
27
-f, --off Power off the target hosts.
28
-c, --cycle Power cycle the target hosts.
29
-r, --reset Reset the target hosts.
30
-s, --stat Get power status of the target hosts.
31
--pulse Send power diagnostic interrupt to target hosts.
32
--soft Initiate a soft-shutdown of the OS via ACPI.
33
--on-if-off Issue a power on command instead of a power cycle
34
or hard reset command if the remote machine's
35
power is currently off.
36
--wait-until-off Regularly query the remote BMC and return only
37
after the machine has powered off.
38
--wait-until-on Regularly query the remote BMC and return only
46
#include <freeipmi/freeipmi.h>
47
#include <ipmi_monitoring.h>
48
#if HAVE_FREEIPMI_MONITORING
49
#include <ipmi_monitoring_bitmasks.h>
54
/* FreeIPMI defines */
55
#define IPMI_FRU_STR_BUFLEN 1024
56
/* haven't seen a motherboard with more than 2-3 so far,
57
* 64 should be more than enough */
58
#define IPMI_FRU_CUSTOM_FIELDS 64
60
/* FreeIPMI contexts and configuration*/
61
ipmi_ctx_t ipmi_ctx = NULL;
62
ipmi_monitoring_ctx_t mon_ctx = NULL;
63
struct ipmi_monitoring_ipmi_config ipmi_config;
65
/* SDR management API has changed with 1.1.X and later */
66
#ifdef HAVE_FREEIPMI_11X_12X
67
ipmi_sdr_ctx_t sdr_ctx = NULL;
68
ipmi_fru_ctx_t fru_ctx = NULL;
69
#define SDR_PARSE_CTX sdr_ctx
71
ipmi_sdr_cache_ctx_t sdr_ctx = NULL;
72
ipmi_sdr_parse_ctx_t sdr_parse_ctx = NULL;
73
#define SDR_PARSE_CTX sdr_parse_ctx
74
ipmi_fru_parse_ctx_t fru_ctx = NULL;
75
/* Functions remapping */
76
#define ipmi_sdr_ctx_create ipmi_sdr_cache_ctx_create
77
#define ipmi_sdr_ctx_destroy ipmi_sdr_cache_ctx_destroy
78
#define ipmi_sdr_ctx_errnum ipmi_sdr_cache_ctx_errnum
79
#define ipmi_sdr_ctx_errormsg ipmi_sdr_cache_ctx_errormsg
80
#define ipmi_fru_ctx_create ipmi_fru_parse_ctx_create
81
#define ipmi_fru_ctx_destroy ipmi_fru_parse_ctx_destroy
82
#define ipmi_fru_ctx_set_flags ipmi_fru_parse_ctx_set_flags
83
#define ipmi_fru_ctx_strerror ipmi_fru_parse_ctx_strerror
84
#define ipmi_fru_ctx_errnum ipmi_fru_parse_ctx_errnum
85
#define ipmi_fru_open_device_id ipmi_fru_parse_open_device_id
86
#define ipmi_fru_close_device_id ipmi_fru_parse_close_device_id
87
#define ipmi_fru_ctx_errormsg ipmi_fru_parse_ctx_errormsg
88
#define ipmi_fru_read_data_area ipmi_fru_parse_read_data_area
89
#define ipmi_fru_next ipmi_fru_parse_next
90
#define ipmi_fru_type_length_field_to_string ipmi_fru_parse_type_length_field_to_string
91
#define ipmi_fru_multirecord_power_supply_information ipmi_fru_parse_multirecord_power_supply_information
92
#define ipmi_fru_board_info_area ipmi_fru_parse_board_info_area
93
#define ipmi_fru_field_t ipmi_fru_parse_field_t
95
#define IPMI_SDR_MAX_RECORD_LENGTH IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH
96
#define IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST
97
#define IPMI_FRU_AREA_SIZE_MAX IPMI_FRU_PARSE_AREA_SIZE_MAX
98
#define IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS
99
#define IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA
100
#define IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION
101
#define IPMI_FRU_AREA_STRING_MAX IPMI_FRU_PARSE_AREA_STRING_MAX
102
#endif /* HAVE_FREEIPMI_11X_12X */
104
/* FIXME: freeipmi auto selects a cache based on the hostname you are
105
* connecting too, but this is probably fine for you
107
#define CACHE_LOCATION "/tmp/sdrcache"
109
/* Support functions */
110
static const char* libfreeipmi_getfield (uint8_t language_code,
111
ipmi_fru_field_t *field);
113
static void libfreeipmi_cleanup();
115
static int libfreeipmi_get_psu_info (const void *areabuf,
116
uint8_t area_length, IPMIDevice_t *ipmi_dev);
118
static int libfreeipmi_get_board_info (const void *areabuf,
119
uint8_t area_length, IPMIDevice_t *ipmi_dev);
121
static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev);
124
/*******************************************************************************
126
******************************************************************************/
127
int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev)
130
uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1];
131
unsigned int area_type = 0;
132
unsigned int area_length = 0;
134
upsdebugx(1, "nut-libfreeipmi: nutipmi_open()...");
136
/* Initialize the FreeIPMI library. */
137
if (!(ipmi_ctx = ipmi_ctx_create ()))
139
/* we have to force cleanup, since exit handler is not yet installed */
140
libfreeipmi_cleanup();
141
fatal_with_errno(EXIT_FAILURE, "ipmi_ctx_create");
144
if ((ret = ipmi_ctx_find_inband (ipmi_ctx,
146
0, /* don't disable auto-probe */
150
0, /* workaround flags, none by default */
154
libfreeipmi_cleanup();
155
fatalx(EXIT_FAILURE, "ipmi_ctx_find_inband: %s",
156
ipmi_ctx_errormsg (ipmi_ctx));
160
libfreeipmi_cleanup();
161
fatalx(EXIT_FAILURE, "could not find inband device");
164
upsdebugx(1, "FreeIPMI initialized...");
166
/* Parse FRU information */
167
if (!(fru_ctx = ipmi_fru_ctx_create (ipmi_ctx)))
169
libfreeipmi_cleanup();
170
fatal_with_errno(EXIT_FAILURE, "ipmi_fru_ctx_create()");
173
/* lots of motherboards calculate checksums incorrectly */
174
if (ipmi_fru_ctx_set_flags (fru_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0)
176
libfreeipmi_cleanup();
177
fatalx(EXIT_FAILURE, "ipmi_fru_ctx_set_flags: %s\n",
178
ipmi_fru_ctx_strerror (ipmi_fru_ctx_errnum (fru_ctx)));
181
/* Now open the requested (local) PSU */
182
if (ipmi_fru_open_device_id (fru_ctx, ipmi_id) < 0)
184
libfreeipmi_cleanup();
185
fatalx(EXIT_FAILURE, "ipmi_fru_open_device_id: %s\n",
186
ipmi_fru_ctx_errormsg (fru_ctx));
189
/* Set IPMI identifier */
190
ipmi_dev->ipmi_id = ipmi_id;
197
memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1);
199
/* parse FRU buffer */
200
if (ipmi_fru_read_data_area (fru_ctx,
204
IPMI_FRU_AREA_SIZE_MAX) < 0)
206
libfreeipmi_cleanup();
207
fatal_with_errno(EXIT_FAILURE,
208
"ipmi_fru_read_data_area: %s\n",
209
ipmi_fru_ctx_errormsg (fru_ctx));
216
/* get generic board information */
217
case IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA:
219
if(libfreeipmi_get_board_info (areabuf, area_length,
222
upsdebugx(1, "Can't retrieve board information");
225
/* get specific PSU information */
226
case IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION:
228
if(libfreeipmi_get_psu_info (areabuf, area_length, ipmi_dev) < 0)
230
upsdebugx(1, "Can't retrieve PSU information");
234
upsdebugx (5, "FRU: discarding FRU Area Type Read: %02Xh", area_type);
238
} while ((ret = ipmi_fru_next (fru_ctx)) == 1);
240
/* check for errors */
242
libfreeipmi_cleanup();
243
fatal_with_errno(EXIT_FAILURE, "ipmi_fru_next: %s",
244
ipmi_fru_ctx_errormsg (fru_ctx));
247
/* Get all related sensors information */
248
libfreeipmi_get_sensors_info (ipmi_dev);
251
/* cleanup context */
252
libfreeipmi_cleanup();
257
void nut_ipmi_close(void)
259
upsdebugx(1, "nutipmi_close...");
261
libfreeipmi_cleanup();
264
static const char* libfreeipmi_getfield (uint8_t language_code,
265
ipmi_fru_field_t *field)
267
static char strbuf[IPMI_FRU_AREA_STRING_MAX + 1];
268
unsigned int strbuflen = IPMI_FRU_AREA_STRING_MAX;
270
if (!field->type_length_field_length)
273
memset (strbuf, '\0', IPMI_FRU_AREA_STRING_MAX + 1);
275
if (ipmi_fru_type_length_field_to_string (fru_ctx,
276
field->type_length_field,
277
field->type_length_field_length,
282
upsdebugx (2, "ipmi_fru_type_length_field_to_string: %s",
283
ipmi_fru_ctx_errormsg (fru_ctx));
293
/* Get voltage value from the IPMI voltage code */
294
static float libfreeipmi_get_voltage (uint8_t voltage_code)
296
if (voltage_code == IPMI_FRU_VOLTAGE_12V)
298
else if (voltage_code == IPMI_FRU_VOLTAGE_MINUS12V)
300
else if (voltage_code == IPMI_FRU_VOLTAGE_5V)
302
else if (voltage_code == IPMI_FRU_VOLTAGE_3_3V)
308
/* Cleanup IPMI contexts */
309
static void libfreeipmi_cleanup()
313
ipmi_fru_close_device_id (fru_ctx);
314
ipmi_fru_ctx_destroy (fru_ctx);
318
ipmi_sdr_ctx_destroy (sdr_ctx);
321
#ifndef HAVE_FREEIPMI_11X_12X
323
ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx);
328
ipmi_ctx_close (ipmi_ctx);
329
ipmi_ctx_destroy (ipmi_ctx);
333
ipmi_monitoring_ctx_destroy (mon_ctx);
337
/* Get generic board information (manufacturer and model names, serial, ...)
339
static int libfreeipmi_get_psu_info (const void *areabuf,
341
IPMIDevice_t *ipmi_dev)
343
/* FIXME: directly use ipmi_dev fields */
344
unsigned int overall_capacity;
345
unsigned int low_end_input_voltage_range_1;
346
unsigned int high_end_input_voltage_range_1;
347
unsigned int low_end_input_frequency_range;
348
unsigned int high_end_input_frequency_range;
349
unsigned int voltage_1;
351
/* FIXME: check for the interest and capability to use these data */
352
unsigned int peak_va;
353
unsigned int inrush_current;
354
unsigned int inrush_interval;
355
unsigned int low_end_input_voltage_range_2;
356
unsigned int high_end_input_voltage_range_2;
357
unsigned int ac_dropout_tolerance;
358
unsigned int predictive_fail_support;
359
unsigned int power_factor_correction;
360
unsigned int autoswitch;
361
unsigned int hot_swap_support;
362
unsigned int tachometer_pulses_per_rotation_predictive_fail_polarity;
363
unsigned int peak_capacity;
364
unsigned int hold_up_time;
365
unsigned int voltage_2;
366
unsigned int total_combined_wattage;
367
unsigned int predictive_fail_tachometer_lower_threshold;
369
upsdebugx(1, "entering libfreeipmi_get_psu_info()");
371
if (ipmi_fru_multirecord_power_supply_information (fru_ctx,
378
&low_end_input_voltage_range_1,
379
&high_end_input_voltage_range_1,
380
&low_end_input_voltage_range_2,
381
&high_end_input_voltage_range_2,
382
&low_end_input_frequency_range,
383
&high_end_input_frequency_range,
384
&ac_dropout_tolerance,
385
&predictive_fail_support,
386
&power_factor_correction,
389
&tachometer_pulses_per_rotation_predictive_fail_polarity,
394
&total_combined_wattage,
395
&predictive_fail_tachometer_lower_threshold) < 0)
397
fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: %s",
398
ipmi_fru_ctx_errormsg (fru_ctx));
401
ipmi_dev->overall_capacity = overall_capacity;
403
/* Voltages are in mV! */
404
ipmi_dev->input_minvoltage = low_end_input_voltage_range_1 / 1000;
405
ipmi_dev->input_maxvoltage = high_end_input_voltage_range_1 / 1000;
407
ipmi_dev->input_minfreq = low_end_input_frequency_range;
408
ipmi_dev->input_maxfreq = high_end_input_frequency_range;
410
ipmi_dev->voltage = libfreeipmi_get_voltage(voltage_1);
412
upsdebugx(1, "libfreeipmi_get_psu_info() retrieved successfully");
417
/* Get specific PSU information from IPMI FRU */
418
static int libfreeipmi_get_board_info (const void *areabuf,
419
uint8_t area_length, IPMIDevice_t *ipmi_dev)
421
uint8_t language_code;
422
uint32_t mfg_date_time;
423
ipmi_fru_field_t board_manufacturer;
424
ipmi_fru_field_t board_product_name;
425
ipmi_fru_field_t board_serial_number;
426
ipmi_fru_field_t board_part_number;
427
ipmi_fru_field_t board_fru_file_id;
428
ipmi_fru_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS];
429
const char *string = NULL;
431
struct tm mfg_date_time_tm;
432
char mfg_date_time_buf[IPMI_FRU_STR_BUFLEN + 1];
434
upsdebugx(1, "entering libfreeipmi_get_board_info()");
437
memset (&board_manufacturer, '\0', sizeof (ipmi_fru_field_t));
438
memset (&board_product_name, '\0', sizeof (ipmi_fru_field_t));
439
memset (&board_serial_number, '\0', sizeof (ipmi_fru_field_t));
440
memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_field_t));
441
memset (&board_custom_fields[0], '\0',
442
sizeof (ipmi_fru_field_t) * IPMI_FRU_CUSTOM_FIELDS);
444
/* parse FRU buffer */
445
if (ipmi_fru_board_info_area (fru_ctx,
452
&board_serial_number,
456
IPMI_FRU_CUSTOM_FIELDS) < 0)
458
libfreeipmi_cleanup();
459
fatalx(EXIT_FAILURE, "ipmi_fru_board_info_area: %s",
460
ipmi_fru_ctx_errormsg (fru_ctx));
464
if (IPMI_FRU_LANGUAGE_CODE_VALID (language_code)) {
465
upsdebugx (5, "FRU Board Language: %s", ipmi_fru_language_codes[language_code]);
468
upsdebugx (5, "FRU Board Language Code: %02Xh", language_code);
471
/* Posix says individual calls need not clear/set all portions of
472
* 'struct tm', thus passing 'struct tm' between functions could
473
* have issues. So we need to memset */
474
memset (&mfg_date_time_tm, '\0', sizeof (struct tm));
475
timetmp = mfg_date_time;
476
localtime_r (&timetmp, &mfg_date_time_tm);
477
memset (mfg_date_time_buf, '\0', IPMI_FRU_STR_BUFLEN + 1);
478
strftime (mfg_date_time_buf, IPMI_FRU_STR_BUFLEN, "%D - %T", &mfg_date_time_tm);
481
ipmi_dev->date = xstrdup(mfg_date_time_buf);
482
upsdebugx(2, "FRU Board Manufacturing Date/Time: %s", ipmi_dev->date);
484
if ((string = libfreeipmi_getfield (language_code, &board_manufacturer)) != NULL)
485
ipmi_dev->manufacturer = xstrdup(string);
487
ipmi_dev->manufacturer = xstrdup("Generic IPMI manufacturer");
489
if ((string = libfreeipmi_getfield (language_code, &board_product_name)) != NULL)
490
ipmi_dev->product = xstrdup(string);
492
ipmi_dev->product = xstrdup("Generic PSU");
494
if ((string = libfreeipmi_getfield (language_code, &board_serial_number)) != NULL)
495
ipmi_dev->serial = xstrdup(string);
497
ipmi_dev->serial = NULL;
499
if ((string = libfreeipmi_getfield (language_code, &board_part_number)) != NULL)
500
ipmi_dev->part = xstrdup(string);
502
ipmi_dev->part = NULL;
508
/* Get the sensors list & values, specific to the given FRU ID
509
* Return -1 on error, or the number of sensors found otherwise */
510
static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev)
512
uint8_t sdr_record[IPMI_SDR_MAX_RECORD_LENGTH];
513
uint8_t record_type, logical_physical_fru_device, logical_fru_device_device_slave_address;
514
uint8_t tmp_entity_id, tmp_entity_instance;
516
uint16_t record_count;
517
int found_device_id = 0;
519
uint8_t entity_id, entity_instance;
522
if (ipmi_ctx == NULL)
525
/* Clear the sensors list */
526
ipmi_dev->sensors_count = 0;
527
memset(ipmi_dev->sensors_id_list, 0, sizeof(ipmi_dev->sensors_id_list));
529
if (!(sdr_ctx = ipmi_sdr_ctx_create ()))
531
libfreeipmi_cleanup();
532
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_ctx_create()");
535
#ifndef HAVE_FREEIPMI_11X_12X
536
if (!(sdr_parse_ctx = ipmi_sdr_parse_ctx_create ()))
538
libfreeipmi_cleanup();
539
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_parse_ctx_create()");
543
if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0)
545
if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
547
libfreeipmi_cleanup();
548
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s",
549
ipmi_sdr_ctx_errormsg (sdr_ctx));
553
if (ipmi_sdr_ctx_errnum (sdr_ctx) == IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
555
if (ipmi_sdr_cache_create (sdr_ctx,
556
ipmi_ctx, CACHE_LOCATION,
557
IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT,
558
#ifndef HAVE_FREEIPMI_11X_12X
559
IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT,
563
libfreeipmi_cleanup();
564
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s",
565
ipmi_sdr_ctx_errormsg (sdr_ctx));
567
if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0)
569
if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
571
libfreeipmi_cleanup();
572
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s",
573
ipmi_sdr_ctx_errormsg (sdr_ctx));
578
if (ipmi_sdr_cache_record_count (sdr_ctx, &record_count) < 0) {
580
"ipmi_sdr_cache_record_count: %s\n",
581
ipmi_sdr_ctx_errormsg (sdr_ctx));
585
upsdebugx(3, "Found %i records in SDR cache", record_count);
587
for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx))
589
memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH);
591
if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_ctx,
593
IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
595
fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n",
596
ipmi_sdr_ctx_errormsg (sdr_ctx));
599
if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX,
605
fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n",
606
ipmi_sdr_ctx_errormsg (sdr_ctx));
610
upsdebugx (5, "Checking record %i (/%i)", i, record_count);
612
if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD) {
613
upsdebugx(1, "=======> not device locator (%i)!!", record_type);
617
if (ipmi_sdr_parse_fru_device_locator_parameters (SDR_PARSE_CTX,
621
&logical_fru_device_device_slave_address,
624
&logical_physical_fru_device,
627
fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s\n",
628
ipmi_sdr_ctx_errormsg (sdr_ctx));
632
upsdebugx(2, "Checking device %i/%i", logical_physical_fru_device,
633
logical_fru_device_device_slave_address);
635
if (logical_physical_fru_device
636
&& logical_fru_device_device_slave_address == ipmi_dev->ipmi_id)
640
if (ipmi_sdr_parse_fru_entity_id_and_instance (SDR_PARSE_CTX,
644
&entity_instance) < 0)
647
"ipmi_sdr_parse_fru_entity_id_and_instance: %s\n",
648
ipmi_sdr_ctx_errormsg (sdr_ctx));
655
if (!found_device_id)
657
fprintf (stderr, "Couldn't find device id %d\n", ipmi_dev->ipmi_id);
661
upsdebugx(1, "Found device id %d", ipmi_dev->ipmi_id);
663
if (ipmi_sdr_cache_first (sdr_ctx) < 0)
665
fprintf (stderr, "ipmi_sdr_cache_first: %s\n",
666
ipmi_sdr_ctx_errormsg (sdr_ctx));
670
for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx))
672
/* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH];
673
uint8_t record_type, tmp_entity_id, tmp_entity_instance;
674
int sdr_record_len; */
676
memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH);
677
if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_ctx,
679
IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
681
fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n",
682
ipmi_sdr_ctx_errormsg (sdr_ctx));
686
if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX,
692
fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n",
693
ipmi_sdr_ctx_errormsg (sdr_ctx));
697
upsdebugx (5, "Checking record %i (/%i)", record_id, record_count);
699
if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
700
&& record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
701
&& record_type != IPMI_SDR_FORMAT_EVENT_ONLY_RECORD) {
705
if (ipmi_sdr_parse_entity_id_instance_type (SDR_PARSE_CTX,
709
&tmp_entity_instance,
712
fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s\n",
713
ipmi_sdr_ctx_errormsg (sdr_ctx));
717
if (tmp_entity_id == entity_id
718
&& tmp_entity_instance == entity_instance)
720
upsdebugx (1, "Found record id = %u for device id %u",
721
record_id, ipmi_dev->ipmi_id);
723
/* Add it to the tracked list */
724
ipmi_dev->sensors_id_list[ipmi_dev->sensors_count] = record_id;
725
ipmi_dev->sensors_count++;
733
ipmi_sdr_ctx_destroy (sdr_ctx);
736
#ifndef HAVE_FREEIPMI_11X_12X
738
ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx);
740
#endif /* HAVE_FREEIPMI_11X_12X */
742
return ipmi_dev->sensors_count;
747
=> Nominal conditions
750
Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String
751
52, Presence, 84, Entity Presence, Nominal, N/A, N/A, 6Fh, 1h, 'Entity Present'
752
57, Status, 100, Power Supply, Nominal, N/A, N/A, 6Fh, 1h, 'Presence detected'
753
116, Current, 148, Current, Nominal, 0.20, A, 1h, C0h, 'OK'
754
118, Voltage, 150, Voltage, Nominal, 236.00, V, 1h, C0h, 'OK'
756
=> Power failure conditions
758
Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String
759
52, Presence, 84, Entity Presence, Nominal, N/A, N/A, 6Fh, 1h, 'Entity Present'
760
57, Status, 100, Power Supply, Critical, N/A, N/A, 6Fh, 9h, 'Presence detected' 'Power Supply input lost (AC/DC)'
764
Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String
765
52, Presence, 84, Entity Presence, Critical, N/A, N/A, 6Fh, 2h, 'Entity Absent'
766
57, Status, 100, Power Supply, Critical, N/A, N/A, 6Fh, 8h, 'Power Supply input lost (AC/DC)'
770
int nut_ipmi_monitoring_init()
774
if (ipmi_monitoring_init (0, &errnum) < 0) {
775
upsdebugx (1, "ipmi_monitoring_init() error: %s", ipmi_monitoring_ctx_strerror (errnum));
779
if (!(mon_ctx = ipmi_monitoring_ctx_create ())) {
780
upsdebugx (1, "ipmi_monitoring_ctx_create() failed");
784
#if HAVE_FREEIPMI_MONITORING
785
/* FIXME: replace "/tmp" by a proper place, using mkdtemp() or similar */
786
if (ipmi_monitoring_ctx_sdr_cache_directory (mon_ctx, "/tmp") < 0) {
787
upsdebugx (1, "ipmi_monitoring_ctx_sdr_cache_directory() error: %s",
788
ipmi_monitoring_ctx_errormsg (mon_ctx));
792
if (ipmi_monitoring_ctx_sensor_config_file (mon_ctx, NULL) < 0) {
793
upsdebugx (1, "ipmi_monitoring_ctx_sensor_config_file() error: %s",
794
ipmi_monitoring_ctx_errormsg (mon_ctx));
797
#endif /* HAVE_FREEIPMI_MONITORING */
802
int nut_ipmi_get_sensors_status(IPMIDevice_t *ipmi_dev)
806
#if HAVE_FREEIPMI_MONITORING
807
/* It seems we don't need more! */
808
unsigned int sensor_reading_flags = IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
809
int sensor_count, i, str_count;
810
int psu_status = PSU_STATUS_UNKNOWN;
812
if (mon_ctx == NULL) {
813
upsdebugx (1, "Monitoring context not initialized!");
817
/* Monitor only the list of sensors found previously */
818
if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (mon_ctx,
819
NULL, /* hostname is NULL for In-band communication */
820
NULL, /* FIXME: needed? ipmi_config */
821
sensor_reading_flags,
822
ipmi_dev->sensors_id_list,
823
ipmi_dev->sensors_count,
827
upsdebugx (1, "ipmi_monitoring_sensor_readings_by_record_id() error: %s",
828
ipmi_monitoring_ctx_errormsg (mon_ctx));
832
upsdebugx (1, "nut_ipmi_get_sensors_status: %i sensors to check", sensor_count);
834
for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (mon_ctx))
836
int record_id, sensor_type;
837
int sensor_bitmask_type = -1;
838
/* int sensor_reading_type, sensor_state; */
839
char **sensor_bitmask_strings = NULL;
840
void *sensor_reading = NULL;
842
if ((record_id = ipmi_monitoring_sensor_read_record_id (mon_ctx)) < 0)
844
upsdebugx (1, "ipmi_monitoring_sensor_read_record_id() error: %s",
845
ipmi_monitoring_ctx_errormsg (mon_ctx));
849
if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (mon_ctx)) < 0)
851
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_type() error: %s",
852
ipmi_monitoring_ctx_errormsg (mon_ctx));
856
upsdebugx (1, "checking sensor #%i, type %i", record_id, sensor_type);
858
/* should we consider this for ALARM?
859
* IPMI_MONITORING_STATE_NOMINAL
860
* IPMI_MONITORING_STATE_WARNING
861
* IPMI_MONITORING_STATE_CRITICAL
862
* if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (mon_ctx)) < 0)
865
if ((sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (mon_ctx)) < 0)
867
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_reading() error: %s",
868
ipmi_monitoring_ctx_errormsg (mon_ctx));
871
/* This can be needed to interpret sensor_reading format!
872
if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
874
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_reading_type() error: %s",
875
ipmi_monitoring_ctx_errormsg (mon_ctx));
878
if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (mon_ctx)) < 0)
880
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_bitmask_type() error: %s",
881
ipmi_monitoring_ctx_errormsg (mon_ctx));
885
if ((sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (mon_ctx)) < 0)
887
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_bitmask_strings() error: %s",
888
ipmi_monitoring_ctx_errormsg (mon_ctx));
892
/* Only the few possibly interesting sensors are considered */
895
case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
896
ipmi_dev->temperature = *((double *)sensor_reading);
897
upsdebugx (3, "Temperature: %.2f", *((double *)sensor_reading));
898
dstate_setinfo("ambient.temperature", "%.2f", *((double *)sensor_reading));
901
case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
902
ipmi_dev->voltage = *((double *)sensor_reading);
903
upsdebugx (3, "Voltage: %.2f", *((double *)sensor_reading));
904
dstate_setinfo("input.voltage", "%.2f", *((double *)sensor_reading));
907
case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
908
ipmi_dev->input_current = *((double *)sensor_reading);
909
upsdebugx (3, "Current: %.2f", *((double *)sensor_reading));
910
dstate_setinfo("input.current", "%.2f", *((double *)sensor_reading));
914
case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
916
* 'Presence detected'
917
* 'Power Supply input lost (AC/DC)' => maps to status:OFF */
918
upsdebugx (3, "Power Supply: status string");
919
if (sensor_bitmask_type == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN) {
920
upsdebugx(3, "No status string");
923
while (sensor_bitmask_strings[str_count])
925
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
926
if (!strncmp("Power Supply input lost (AC/DC)",
927
sensor_bitmask_strings[str_count],
928
strlen("Power Supply input lost (AC/DC)"))) {
929
/* Don't override PSU absence! */
930
if (psu_status != PSU_ABSENT) {
931
psu_status = PSU_POWER_FAILURE; /* = status OFF */
937
case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
939
* 'Entity Present' => maps to status:OL
940
* 'Entity Absent' (PSU has been removed!) => declare staleness */
941
upsdebugx (3, "Entity Presence: status string");
942
if (sensor_bitmask_type == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN) {
943
upsdebugx(3, "No status string");
946
while (sensor_bitmask_strings[str_count])
948
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
949
if (!strncmp("Entity Present",
950
sensor_bitmask_strings[str_count],
951
strlen("Entity Present"))) {
952
psu_status = PSU_PRESENT;
954
else if (!strncmp("Entity Absent",
955
sensor_bitmask_strings[str_count],
956
strlen("Entity Absent"))) {
957
psu_status = PSU_ABSENT;
963
/* Not sure of the values of these, so get as much as possible... */
964
case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
965
upsdebugx (3, "Power Unit: status string");
967
while (sensor_bitmask_strings[str_count])
969
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
973
case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
974
upsdebugx (3, "System ACPI Power State: status string");
976
while (sensor_bitmask_strings[str_count])
978
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
982
case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
983
upsdebugx (3, "Battery: status string");
985
while (sensor_bitmask_strings[str_count])
987
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
994
/* Process status if needed */
995
if (psu_status != PSU_STATUS_UNKNOWN) {
1010
case PSU_POWER_FAILURE:
1018
#endif /* HAVE_FREEIPMI_MONITORING */
1024
--chassis-control=CONTROL
1025
Control the chassis. This command provides power-up, power-down, and reset control. Supported values: POWER-DOWN, POWER-UP, POWER-CYCLE, HARD-RESET, DIAGNOS‐
1026
TIC-INTERRUPT, SOFT-SHUTDOWN.