/*****************************************************************************\ * $Id: ipmi-fru.c,v 1.59 2010-02-08 22:20:58 chu11 Exp $ ***************************************************************************** * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. * Copyright (C) 2007 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Albert Chu * UCRL-CODE-232183 * * This file is part of Ipmi-fru, a tool used for retrieving * motherboard field replaceable unit (FRU) information. For details, * see http://www.llnl.gov/linux/. * * Ipmi-fru is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 3 of the License, or (at your * option) any later version. * * Ipmi-fru is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with Ipmi-fru. If not, see . \*****************************************************************************/ #include #include #include #include #include #include /* haven't seen a motherboard with more than 2-3 so far, 64 should be more than enough */ #define IPMI_FRU_CUSTOM_FIELDS 64 #define IPMI_FRU_STR_BUFLEN 1024 ipmi_ctx_t ipmi_ctx = NULL; ipmi_fru_parse_ctx_t fru_parse_ctx = NULL; int _output_field (uint8_t language_code, ipmi_fru_parse_field_t *field, char *str) { char strbuf[IPMI_FRU_PARSE_AREA_STRING_MAX + 1]; unsigned int strbuflen = IPMI_FRU_PARSE_AREA_STRING_MAX; assert (field); assert (str); if (!field->type_length_field_length) return (0); memset (strbuf, '\0', IPMI_FRU_PARSE_AREA_STRING_MAX + 1); if (ipmi_fru_parse_type_length_field_to_string (fru_parse_ctx, field->type_length_field, field->type_length_field_length, language_code, strbuf, &strbuflen) < 0) { fprintf (stderr, "ipmi_fru_parse_type_length_field_to_string: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } if (strbuflen) printf (" FRU %s: %s\n", str, strbuf); return (0); } int ipmi_fru_output_chassis_info_area (const void *areabuf, unsigned int area_length) { uint8_t chassis_type; ipmi_fru_parse_field_t chassis_part_number; ipmi_fru_parse_field_t chassis_serial_number; ipmi_fru_parse_field_t chassis_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; unsigned int i; assert (areabuf); assert (area_length); memset (&chassis_part_number, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&chassis_serial_number, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&chassis_custom_fields[0], '\0', sizeof (ipmi_fru_parse_field_t) * IPMI_FRU_CUSTOM_FIELDS); if (ipmi_fru_parse_chassis_info_area (fru_parse_ctx, areabuf, area_length, &chassis_type, &chassis_part_number, &chassis_serial_number, chassis_custom_fields, IPMI_FRU_CUSTOM_FIELDS) < 0) { fprintf (stderr, "ipmi_fru_parse_chassis_info_area: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } if (IPMI_FRU_CHASSIS_TYPE_VALID (chassis_type)) printf (" FRU Chassis Type: %s\n", ipmi_fru_chassis_types[chassis_type]); else printf (" FRU Chassis Type: %s\n", ipmi_fru_chassis_types[IPMI_FRU_CHASSIS_TYPE_UNKNOWN]); /* achu: Chassis Info Area has no language code, assume English. */ if (_output_field (IPMI_FRU_LANGUAGE_CODE_ENGLISH, &chassis_part_number, "Chassis Part Number") < 0) return (-1); if (_output_field (IPMI_FRU_LANGUAGE_CODE_ENGLISH, &chassis_serial_number, "Chassis Serial Number") < 0) return (-1); for (i = 0; i < IPMI_FRU_CUSTOM_FIELDS; i++) { if (_output_field (IPMI_FRU_LANGUAGE_CODE_ENGLISH, &chassis_custom_fields[i], "Chassis Custom Info") < 0) return (-1); } return (0); } int ipmi_fru_output_board_info_area (const void *areabuf, unsigned int area_length) { uint8_t language_code; uint32_t mfg_date_time; ipmi_fru_parse_field_t board_manufacturer; ipmi_fru_parse_field_t board_product_name; ipmi_fru_parse_field_t board_serial_number; ipmi_fru_parse_field_t board_part_number; ipmi_fru_parse_field_t board_fru_file_id; ipmi_fru_parse_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; time_t timetmp; struct tm mfg_date_time_tm; char mfg_date_time_buf[IPMI_FRU_STR_BUFLEN + 1]; unsigned int i; assert (areabuf); assert (area_length); memset (&board_manufacturer, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&board_product_name, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&board_serial_number, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&board_custom_fields[0], '\0', sizeof (ipmi_fru_parse_field_t) * IPMI_FRU_CUSTOM_FIELDS); if (ipmi_fru_parse_board_info_area (fru_parse_ctx, areabuf, area_length, &language_code, &mfg_date_time, &board_manufacturer, &board_product_name, &board_serial_number, &board_part_number, &board_fru_file_id, board_custom_fields, IPMI_FRU_CUSTOM_FIELDS) < 0) { fprintf (stderr, "ipmi_fru_parse_board_info_area: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } if (IPMI_FRU_LANGUAGE_CODE_VALID (language_code)) printf (" FRU Board Language: %s\n", ipmi_fru_language_codes[language_code]); else printf (" FRU Board Language Code: %02Xh\n", language_code); /* Posix says individual calls need not clear/set all portions of * 'struct tm', thus passing 'struct tm' between functions could * have issues. So we need to memset. */ memset (&mfg_date_time_tm, '\0', sizeof (struct tm)); timetmp = mfg_date_time; localtime_r (&timetmp, &mfg_date_time_tm); memset (mfg_date_time_buf, '\0', IPMI_FRU_STR_BUFLEN + 1); strftime (mfg_date_time_buf, IPMI_FRU_STR_BUFLEN, "%D - %T", &mfg_date_time_tm); printf (" FRU Board Manufacturing Date/Time: %s\n", mfg_date_time_buf); if (_output_field (language_code, &board_manufacturer, "Board Manufacturer") < 0) return (-1); if (_output_field (language_code, &board_product_name, "Board Product Name") < 0) return (-1); if (_output_field (language_code, &board_serial_number, "Board Serial Number") < 0) return (-1); if (_output_field (language_code, &board_part_number, "Board Part Number") < 0) return (-1); if (_output_field (language_code, &board_fru_file_id, "FRU File ID") < 0) return (-1); for (i = 0; i < IPMI_FRU_CUSTOM_FIELDS; i++) { if (_output_field (language_code, &board_custom_fields[i], "Board Custom Info") < 0) return (-1); } return (0); } int ipmi_fru_output_product_info_area (const void *areabuf, unsigned int area_length) { uint8_t language_code; ipmi_fru_parse_field_t product_manufacturer_name; ipmi_fru_parse_field_t product_name; ipmi_fru_parse_field_t product_part_model_number; ipmi_fru_parse_field_t product_version; ipmi_fru_parse_field_t product_serial_number; ipmi_fru_parse_field_t product_asset_tag; ipmi_fru_parse_field_t product_fru_file_id; ipmi_fru_parse_field_t product_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; unsigned int i; assert (areabuf); assert (area_length); memset (&product_manufacturer_name, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_name, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_part_model_number, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_version, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_serial_number, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_asset_tag, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_fru_file_id, '\0', sizeof (ipmi_fru_parse_field_t)); memset (&product_custom_fields[0], '\0', sizeof (ipmi_fru_parse_field_t) * IPMI_FRU_CUSTOM_FIELDS); if (ipmi_fru_parse_product_info_area (fru_parse_ctx, areabuf, area_length, &language_code, &product_manufacturer_name, &product_name, &product_part_model_number, &product_version, &product_serial_number, &product_asset_tag, &product_fru_file_id, product_custom_fields, IPMI_FRU_CUSTOM_FIELDS) < 0) { fprintf (stderr, "ipmi_fru_parse_product_info_area: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } if (IPMI_FRU_LANGUAGE_CODE_VALID (language_code)) printf (" FRU Product Language: %s\n", ipmi_fru_language_codes[language_code]); else printf (" FRU Product Language Code: %02Xh\n", language_code); if (_output_field (language_code, &product_manufacturer_name, "Product Manufacturer Name") < 0) return (-1); if (_output_field (language_code, &product_name, "Product Name") < 0) return (-1); if (_output_field (language_code, &product_part_model_number, "Product Part/Model Number") < 0) return (-1); if (_output_field (language_code, &product_version, "Product Version") < 0) return (-1); if (_output_field (language_code, &product_serial_number, "Product Serial Number") < 0) return (-1); if (_output_field (language_code, &product_asset_tag, "Product Asset Tag") < 0) return (-1); if (_output_field (language_code, &product_fru_file_id, "FRU File ID") < 0) return (-1); for (i = 0; i < IPMI_FRU_CUSTOM_FIELDS; i++) { if (_output_field (language_code, &product_custom_fields[i], "Product Custom Info") < 0) return (-1); } return (0); } static char * _voltage_str (uint8_t voltage) { if (voltage == IPMI_FRU_VOLTAGE_12V) return "12V"; else if (voltage == IPMI_FRU_VOLTAGE_MINUS12V) return "-12V"; else if (voltage == IPMI_FRU_VOLTAGE_5V) return "5V"; else if (voltage == IPMI_FRU_VOLTAGE_3_3V) return "3.3V"; else return ""; } int ipmi_fru_output_power_supply_information (const void *areabuf, uint8_t area_length) { unsigned int overall_capacity; unsigned int peak_va; unsigned int inrush_current; unsigned int inrush_interval; unsigned int low_end_input_voltage_range_1; unsigned int high_end_input_voltage_range_1; unsigned int low_end_input_voltage_range_2; unsigned int high_end_input_voltage_range_2; unsigned int low_end_input_frequency_range; unsigned int high_end_input_frequency_range; unsigned int ac_dropout_tolerance; unsigned int predictive_fail_support; unsigned int power_factor_correction; unsigned int autoswitch; unsigned int hot_swap_support; unsigned int tachometer_pulses_per_rotation_predictive_fail_polarity; unsigned int peak_capacity; unsigned int hold_up_time; unsigned int voltage_1; unsigned int voltage_2; unsigned int total_combined_wattage; unsigned int predictive_fail_tachometer_lower_threshold; assert (areabuf); assert (area_length); if (ipmi_fru_parse_multirecord_power_supply_information (fru_parse_ctx, areabuf, area_length, &overall_capacity, &peak_va, &inrush_current, &inrush_interval, &low_end_input_voltage_range_1, &high_end_input_voltage_range_1, &low_end_input_voltage_range_2, &high_end_input_voltage_range_2, &low_end_input_frequency_range, &high_end_input_frequency_range, &ac_dropout_tolerance, &predictive_fail_support, &power_factor_correction, &autoswitch, &hot_swap_support, &tachometer_pulses_per_rotation_predictive_fail_polarity, &peak_capacity, &hold_up_time, &voltage_1, &voltage_2, &total_combined_wattage, &predictive_fail_tachometer_lower_threshold) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_power_supply_information: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } printf (" FRU Power Supply Overall Capacity: %u Watts\n", overall_capacity); printf (" FRU Power Supply Peak VA: %u VA\n", peak_va); printf (" FRU Power Supply Max Inrush Current: %u Amps\n", inrush_current); printf (" FRU Power Supply Inrush Interval: %u ms\n", inrush_interval); printf (" FRU Power Supply Low End Input Voltage 1: %u mV\n", low_end_input_voltage_range_1); printf (" FRU Power Supply High End Input Voltage 1: %u mV\n", high_end_input_voltage_range_1); printf (" FRU Power Supply Low End Input Voltage 2: %u mV\n", low_end_input_voltage_range_2); printf (" FRU Power Supply High End Input Voltage 2: %u mV\n", high_end_input_voltage_range_2); printf (" FRU Power Supply Low End Acceptable Frequencey: %u Hz\n", low_end_input_frequency_range); printf (" FRU Power Supply High End Acceptable Frequencey: %u Hz\n", high_end_input_frequency_range); printf (" FRU Power Supply A/C Dropout Tolerance: %u ms\n", ac_dropout_tolerance); printf (" FRU Power Supply Predictive Fail Support: %s\n", (predictive_fail_support) ? "Yes" : "No"); if (predictive_fail_support) { if (tachometer_pulses_per_rotation_predictive_fail_polarity) { if (predictive_fail_tachometer_lower_threshold) printf (" FRU Power Supply Predictive Fail: Tach output, two pulses per rotation\n"); else printf (" FRU Power Supply Predictive Fail: Pass/Fail predictive fail pin (0 = fail)\n"); } else { if (predictive_fail_tachometer_lower_threshold) printf (" FRU Power Supply Predictive Fail: Tach output, one pulse per rotation\n"); else printf (" FRU Power Supply Predictive Fail: Pass/Fail predictive fail pin (1 = fail)\n"); } } printf (" FRU Power Supply Power Factor Correction Supported: %s\n", (power_factor_correction) ? "Yes" : "No"); printf (" FRU Power Supply AutoSwitch Supprt: %s\n", (autoswitch) ? "Yes" : "No"); printf (" FRU Power Supply Hot Swap Support: %s\n", (hot_swap_support) ? "Yes" : "No"); printf (" FRU Power Supply Peak Capacity: %u Watts\n", peak_capacity); printf (" FRU Power Supply Hold Up Time: %u s\n", hold_up_time); printf (" FRU Power Supply Voltage 1: %s\n", _voltage_str (voltage_1)); printf (" FRU Power Supply Voltage 2: %s\n", _voltage_str (voltage_2)); printf (" FRU Power Supply Total Combined Wattage: %u Watts\n", total_combined_wattage); return (0); } int ipmi_fru_output_dc_output (const void *areabuf, uint8_t area_length) { unsigned int output_number; unsigned int standby; int nominal_voltage; int maximum_negative_voltage_deviation; int maximum_positive_voltage_deviation; unsigned int ripple_and_noise_pk_pk; unsigned int minimum_current_draw; unsigned int maximum_current_draw; assert (areabuf); assert (area_length); if (ipmi_fru_parse_multirecord_dc_output (fru_parse_ctx, areabuf, area_length, &output_number, &standby, &nominal_voltage, &maximum_negative_voltage_deviation, &maximum_positive_voltage_deviation, &ripple_and_noise_pk_pk, &minimum_current_draw, &maximum_current_draw) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_dc_output: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } printf (" FRU DC Output Output Number: %u\n", output_number); printf (" FRU DC Output Output on Standy: %s\n", (standby) ? "Yes" : "No"); printf (" FRU DC Output Nominal Voltage: %d mV\n", (int16_t)nominal_voltage); printf (" FRU DC Output Maximum Negative Voltage Deviation: %d mV\n", (int16_t)maximum_negative_voltage_deviation); printf (" FRU DC Output Maximum Positive Voltage Deviation: %d mV\n", (int16_t)maximum_positive_voltage_deviation); printf (" FRU DC Output Ripple and Noise pk-pk: %u mV\n", ripple_and_noise_pk_pk); printf (" FRU DC Output Minimum Current Draw: %u mA\n", minimum_current_draw); printf (" FRU DC Output Maximum Current Draw: %u mA\n", maximum_current_draw); return (0); } int ipmi_fru_output_dc_load (const void *areabuf, uint8_t area_length) { unsigned int output_number; unsigned int standby; int nominal_voltage; int specd_minimum_voltage; int specd_maximum_voltage; unsigned int specd_ripple_and_noise_pk_pk; unsigned int minimum_current_load; unsigned int maximum_current_load; assert (areabuf); assert (area_length); if (ipmi_fru_parse_multirecord_dc_load (fru_parse_ctx, areabuf, area_length, &output_number, &standby, &nominal_voltage, &specd_minimum_voltage, &specd_maximum_voltage, &specd_ripple_and_noise_pk_pk, &minimum_current_load, &maximum_current_load) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_dc_load: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } printf (" FRU DC Load Output Number: %u\n", output_number); printf (" FRU DC Load Nominal Voltage: %d mV\n", (int16_t)nominal_voltage); printf (" FRU DC Load Spec'd Minimum Voltage: %d mV\n", (int16_t)specd_minimum_voltage); printf (" FRU DC Load Spec'd Maximum Voltage: %d mV\n", (int16_t)specd_maximum_voltage); printf (" FRU DC Load Spec'd Ripple and Noise pk-pk: %u mV\n", specd_ripple_and_noise_pk_pk); printf (" FRU DC Load Minimum Current Load: %u mA\n", minimum_current_load); printf (" FRU DC Load Maximum Current Load: %u mA\n", maximum_current_load); return (0); } int ipmi_fru_output_management_access_record (const void *areabuf, uint8_t area_length) { uint8_t sub_record_type; uint8_t sub_record_data[IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1]; unsigned int sub_record_data_len = IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX; unsigned int i; assert (areabuf); assert (area_length); memset (sub_record_data, '\0', IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1); if (ipmi_fru_parse_multirecord_management_access_record (fru_parse_ctx, areabuf, area_length, &sub_record_type, sub_record_data, &sub_record_data_len) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_management_access_record: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_SYSTEM_MANAGEMENT_URL) printf (" FRU Management Access System Management URL: %s\n", (char *)sub_record_data); else if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_SYSTEM_NAME) printf (" FRU Management Access System Name: %s\n", (char *)sub_record_data); else if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_SYSTEM_PING_ADDRESS) printf (" FRU Management Access System Ping Address: %s\n", (char *)sub_record_data); else if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_COMPONENT_MANAGEMENT_URL) printf (" FRU Management Access Component Management URL: %s\n", (char *)sub_record_data); else if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_COMPONENT_NAME) printf (" FRU Management Access Component Name: %s\n", (char *)sub_record_data); else if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_COMPONENT_PING_ADDRESS) printf (" FRU Management Access Component Ping Address: %s\n", (char *)sub_record_data); else if (sub_record_type == IPMI_FRU_SUB_RECORD_TYPE_SYSTEM_UNIQUE_ID) { printf (" FRU Management Access System Unique ID:"); for (i = 0; i < sub_record_data_len; i++) { if (sub_record_data_len > 8 && (i % 8) == 0) printf ("\n "); printf (" %02Xh", sub_record_data[i]); } printf ("\n"); } else { printf (" FRU Management Access Record: Unknown Sub Record Type:"); for (i = 0; i < sub_record_data_len; i++) { if (sub_record_data_len > 8 && (i % 8) == 0) printf ("\n "); printf (" %02Xh", sub_record_data[i]); } printf ("\n"); } return (0); } int ipmi_fru_output_base_compatibility_record (const void *areabuf, uint8_t area_length) { uint32_t manufacturer_id; unsigned int entity_id_code; unsigned int compatibility_base; unsigned int compatibility_code_start_value; uint8_t code_range_mask[IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1]; unsigned int code_range_mask_len = IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX; char iana_buf[IPMI_FRU_STR_BUFLEN + 1]; int ret; assert (areabuf); assert (area_length); memset (code_range_mask, '\0', IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1); if (ipmi_fru_parse_multirecord_base_compatibility_record (fru_parse_ctx, areabuf, area_length, &manufacturer_id, &entity_id_code, &compatibility_base, &compatibility_code_start_value, code_range_mask, &code_range_mask_len) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_base_compatibility_record: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } memset (iana_buf, '\0', IPMI_FRU_STR_BUFLEN + 1); /* if ret == 0 means no string, < 0 means bad manufacturer id * either way, output just the number */ ret = ipmi_iana_enterprise_numbers_string (manufacturer_id, iana_buf, IPMI_FRU_STR_BUFLEN); if (ret > 0) printf (" FRU Base Compatibility Manufacturer ID: %s (%Xh)\n", iana_buf, manufacturer_id); else printf (" FRU Base Compatibility Manufacturer ID: %Xh\n", manufacturer_id); printf (" FRU Base Compatibility Entity ID: %Xh\n", entity_id_code); printf (" FRU Base Compatibility Comptability Base: %Xh\n", compatibility_base); printf (" FRU Base Compatibility Comptability Code Start Value: %Xh\n", compatibility_code_start_value); if (code_range_mask_len) { unsigned int i; printf (" FRU Base Compatibility Code Mask:"); for (i = 0; i < code_range_mask_len; i++) { if (code_range_mask_len > 8 && (i % 8) == 0) printf ("\n "); printf (" %02Xh", code_range_mask[i]); } printf ("\n"); } return (0); } int ipmi_fru_output_extended_compatibility_record (const void *areabuf, uint8_t area_length) { uint32_t manufacturer_id; unsigned int entity_id_code; unsigned int compatibility_base; unsigned int compatibility_code_start_value; uint8_t code_range_mask[IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1]; unsigned int code_range_mask_len = IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX; char iana_buf[IPMI_FRU_STR_BUFLEN + 1]; int ret; assert (areabuf); assert (area_length); memset (code_range_mask, '\0', IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1); if (ipmi_fru_parse_multirecord_extended_compatibility_record (fru_parse_ctx, areabuf, area_length, &manufacturer_id, &entity_id_code, &compatibility_base, &compatibility_code_start_value, code_range_mask, &code_range_mask_len) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_extended_compatibility_record: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } memset (iana_buf, '\0', IPMI_FRU_STR_BUFLEN + 1); /* if ret == 0 means no string, < 0 means bad manufacturer id * either way, output just the number */ ret = ipmi_iana_enterprise_numbers_string (manufacturer_id, iana_buf, IPMI_FRU_STR_BUFLEN); if (ret > 0) printf (" FRU Extended Compatibility Manufacturer ID: %s (%Xh)\n", iana_buf, manufacturer_id); else printf (" FRU Extended Compatibility Manufacturer ID: %Xh\n", manufacturer_id); printf (" FRU Extended Compatibility Entity ID: %Xh\n", entity_id_code); printf (" FRU Extended Compatibility Comptability Base: %Xh\n", compatibility_base); printf (" FRU Extended Compatibility Comptability Code Start Value: %Xh\n", compatibility_code_start_value); if (code_range_mask_len) { unsigned int i; printf (" FRU Extended Compatibility Code Mask:"); for (i = 0; i < code_range_mask_len; i++) { if (code_range_mask_len > 8 && (i % 8) == 0) printf ("\n "); printf (" %02Xh", code_range_mask[i]); } printf ("\n"); } return (0); } int ipmi_fru_output_oem_record (const void *areabuf, uint8_t area_length) { uint32_t manufacturer_id; uint8_t oem_data[IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1]; unsigned int oem_data_len = IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX; char iana_buf[IPMI_FRU_STR_BUFLEN + 1]; int ret; assert (areabuf); assert (area_length); memset (oem_data, '\0', IPMI_FRU_PARSE_AREA_TYPE_LENGTH_FIELD_MAX + 1); if (ipmi_fru_parse_multirecord_oem_record (fru_parse_ctx, areabuf, area_length, &manufacturer_id, oem_data, &oem_data_len) < 0) { fprintf (stderr, "ipmi_fru_parse_multirecord_oem_record: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); return (-1); } memset (iana_buf, '\0', IPMI_FRU_STR_BUFLEN + 1); /* if ret == 0 means no string, < 0 means bad manufacturer id * either way, output just the number */ ret = ipmi_iana_enterprise_numbers_string (manufacturer_id, iana_buf, IPMI_FRU_STR_BUFLEN); if (ret > 0) printf (" FRU OEM Manufacturer ID: %s (%Xh)\n", iana_buf, manufacturer_id); else printf (" FRU OEM Manufacturer ID: %Xh\n", manufacturer_id); if (oem_data_len) { unsigned int i; printf (" FRU OEM Code Mask:"); for (i = 0; i < oem_data_len; i++) { if (oem_data_len > 8 && (i % 8) == 0) printf ("\n "); printf (" %02Xh", oem_data[i]); } printf ("\n"); } return (0); } int main (int argc, char **argv) { int exit_code = 1; int ret; if (!(ipmi_ctx = ipmi_ctx_create ())) { perror ("ipmi_ctx_create"); goto cleanup; } if ((ret = ipmi_ctx_find_inband (ipmi_ctx, NULL, 0, /* don't disable auto-probe */ 0, 0, NULL, 0, /* workaround flags, none by default */ 0 /* flags */ )) < 0) { fprintf (stderr, "ipmi_ctx_find_inband: %s", ipmi_ctx_errormsg (ipmi_ctx)); goto cleanup; } if (!ret) { fprintf (stderr, "could not find inband device"); goto cleanup; } if (!(fru_parse_ctx = ipmi_fru_parse_ctx_create (ipmi_ctx))) { perror ("ipmi_fru_parse_ctx_create()"); goto cleanup; } /* lots of motherboards calculate checksums incorrectly, maybe want to strongly consider setting this */ if (ipmi_fru_parse_ctx_set_flags (fru_parse_ctx, IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) { fprintf (stderr, "ipmi_fru_parse_ctx_set_flags: %s\n", ipmi_fru_parse_ctx_strerror (ipmi_fru_parse_ctx_errnum (fru_parse_ctx))); goto cleanup; } /* only consider default device id of 0 */ if (ipmi_fru_parse_open_device_id (fru_parse_ctx, 0) < 0) { fprintf (stderr, "ipmi_fru_parse_open_device_id: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); goto cleanup; } do { uint8_t areabuf[IPMI_FRU_PARSE_AREA_SIZE_MAX+1]; unsigned int area_type = 0; unsigned int area_length = 0; memset (areabuf, '\0', IPMI_FRU_PARSE_AREA_SIZE_MAX + 1); if (ipmi_fru_parse_read_data_area (fru_parse_ctx, &area_type, &area_length, areabuf, IPMI_FRU_PARSE_AREA_SIZE_MAX) < 0) { fprintf (stderr, "ipmi_fru_parse_open_device_id: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); goto cleanup; } if (area_length) { switch (area_type) { case IPMI_FRU_PARSE_AREA_TYPE_CHASSIS_INFO_AREA: if (ipmi_fru_output_chassis_info_area (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA: if (ipmi_fru_output_board_info_area (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_PRODUCT_INFO_AREA: if (ipmi_fru_output_product_info_area (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION: if (ipmi_fru_output_power_supply_information (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_DC_OUTPUT: if (ipmi_fru_output_dc_output (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_DC_LOAD: if (ipmi_fru_output_dc_load (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_MANAGEMENT_ACCESS_RECORD: if (ipmi_fru_output_management_access_record (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_BASE_COMPATABILITY_RECORD: if (ipmi_fru_output_base_compatibility_record (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_EXTENDED_COMPATABILITY_RECORD: if (ipmi_fru_output_extended_compatibility_record (areabuf, area_length) < 0) goto cleanup; break; case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_OEM: if (ipmi_fru_output_oem_record (areabuf, area_length) < 0) goto cleanup; break; default: fprintf (stderr, " FRU Error: Unknown FRU Area Type Read: %02Xh\n", area_type); goto next; break; } } next: printf ("\n"); ; } while ((ret = ipmi_fru_parse_next (fru_parse_ctx)) == 1); if (ret < 0) { fprintf (stderr, "ipmi_fru_parse_next: %s\n", ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); goto cleanup; } exit_code = 0; cleanup: if (fru_parse_ctx) { ipmi_fru_parse_close_device_id (fru_parse_ctx); ipmi_fru_parse_ctx_destroy (fru_parse_ctx); } if (ipmi_ctx) { ipmi_ctx_close (ipmi_ctx); ipmi_ctx_destroy (ipmi_ctx); } return (exit_code); }