| *** Settings *** |
| Documentation Test IPMI FRU data. |
| |
| Resource ../lib/ipmi_client.robot |
| Resource ../lib/bmc_dbus.robot |
| Variables ../data/ipmi_raw_cmd_table.py |
| Library ../lib/ipmi_utils.py |
| |
| Force Tags IPMI_FRU_Device |
| |
| *** Variables *** |
| |
| ${FRU_NAME} dimm01 dimm02 cpu0 cpu1 motherboard |
| ${BUSCTL_FRU} xyz.openbmc_project.FruDevice |
| ${FRU_DBUS_URL} /xyz/openbmc_project/FruDevice |
| ${fru_device_id} 0x00 |
| ${fru_device_id_invalid} 0xff |
| ${read_write_offset} 0x00 0x00 |
| &{dbus_dict} |
| &{ipmi_dbus_name_mapping} Chassis Part Number=.CHASSIS_PART_NUMBER |
| ... Board Mfg Date=.BOARD_MANUFACTURE_DATE Board Mfg=.BOARD_MANUFACTURER |
| ... Board Product=.BOARD_PRODUCT_NAME Board Serial=.BOARD_SERIAL_NUMBER |
| ... Board Part Number=.BOARD_PART_NUMBER Product Manufacturer=.PRODUCT_MANUFACTURER |
| ... Product Name=.PRODUCT_PRODUCT_NAME Product Part Number=.PRODUCT_PART_NUMBER |
| ... Product Version=.PRODUCT_VERSION Product Serial=.PRODUCT_SERIAL_NUMBER |
| |
| *** Test Cases *** |
| Test FRU Device Name |
| [Documentation] Search FRU for device name |
| [Tags] Test_FRU_Device_Name |
| |
| ${output}= Run External IPMI Standard Command fru |
| Should Contain ${output} ${FRU_NAME} msg=Fail: Given FRU device ${FRU_NAME} not found |
| |
| |
| Verify Fru Device Configuration |
| [Documentation] Read the FRU device configuration of each device |
| ... and compare with DBUS data. |
| [Tags] Verify_Fru_Device_Configuration |
| |
| # IPMI FRU print. |
| ${ipmi_output}= Run External IPMI Standard Command fru |
| |
| # Create dictionary with FRU device serial number as key and details as value from IPMI. |
| ${ipmi_fru}= Get IPMI FRU Devices Data ${ipmi_output} |
| |
| # Returns all the available FRU dbus uri. |
| ${dbus_fru_uri}= Get DBUS URI List From BMC ${BUSCTL_FRU} ${FRU_DBUS_URL} |
| |
| # Returns all the FRU device uri with special characters removed. |
| ${dbus_fru_uri_list}= Fetch DBUS URI List Without Unicode ${dbus_fru_uri} |
| |
| # Creates dictionary with serial number as key, and corresponding FRU device uri as value from dbus. |
| Get DBUS Dictionary For FRU Devices ${dbus_fru_uri_list} ${ipmi_fru} |
| |
| # Compare dbus dictionary each field, with IPMI FRU device fields for each FRU device. |
| Compare IPMI FRU with DBUS ${ipmi_fru} |
| |
| |
| Verify Get FRU Inventory Area Info |
| [Documentation] Verify IPMI get FRU inventory area info command. |
| [Tags] Verify_Get_FRU_Inventory_Area_Info |
| |
| # IPMI read FRU data command. |
| ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} |
| ${bytes_read}= Set Variable ${resp.split()[0]} |
| |
| # IPMI get FRU inventory area info command. |
| ${bytes_inventory}= Get FRU Inventory Area Info |
| |
| # Compare read FRU data Count returned -- count is ‘1’ based, with inventory area count. |
| Should Be Equal ${bytes_inventory} ${bytes_read} |
| |
| |
| Verify Get FRU Inventory Area Info For Invalid Device Data |
| [Documentation] Verify IPMI get FRU inventory area info command for Invalid Device Data. |
| [Tags] Verify_Get_FRU_Inventory_Area_Info_For_Invalid_Device_Data |
| |
| # Verify response for invalid FRU device id. |
| Run Keyword and Expect Error *${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][1]}* |
| ... Run IPMI Standard Command raw ${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][0]} ${fru_device_id_invalid} |
| |
| |
| Verify Get FRU Inventory Area Info For Invalid Data Request |
| [Documentation] Verify IPMI get FRU inventory area info command for Invalid Data Request. |
| [Tags] Verify_Get_FRU_Inventory_Area_Info_For_Invalid_Data_Request |
| |
| # Verify response for invalid response data - extra bytes. |
| Run Keyword and Expect Error *${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][2]}* |
| ... Run IPMI Standard Command raw ${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][0]} ${fru_device_id} 0x00 |
| |
| |
| Verify IPMI Write FRU Data |
| [Documentation] Verify write data in FRU and compare data from read FRU data command via IPMI. |
| [Tags] Verify_IPMI_Write_FRU_Data |
| [Setup] Get Default FRU Data |
| [Teardown] Restore Default FRU Data |
| |
| # Generate random data to write in FRU device. |
| ${write_data_prefixed} ${write_data}= Generate Random Data For FRU |
| |
| # Get the length of the data generated and convert to hex. |
| ${write_data_length}= Get Length ${write_data} |
| ${write_data_length}= Convert To Hex ${write_data_length} lowercase=yes |
| |
| # Write the data to FRU device. |
| Write FRU Data Via IPMI ${fru_device_id} ${read_write_offset} ${write_data_prefixed} ${write_data_length} |
| |
| # Read the FRU data. |
| ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} |
| ${resp_data}= Set Variable ${resp.split()[1:]} |
| |
| # Verify if the data written and read are same. |
| Should Be Equal ${write_data} ${resp_data} |
| |
| |
| Verify IPMI Write FRU Data With BMC Reboot |
| [Documentation] Verify IPMI write data in FRU and compare data from read FRU data command after BMC reboot. |
| [Tags] Verify_IPMI_Write_FRU_Data_With_BMC_Reboot |
| [Setup] Get Default FRU Data |
| [Teardown] Restore Default FRU Data |
| |
| # Generate random data to write in FRU device. |
| ${write_data_prefixed} ${write_data}= Generate Random Data For FRU |
| |
| # Get the length of the data generated and convert to hex. |
| ${write_data_length}= Get Length ${write_data} |
| ${write_data_length}= Convert To Hex ${write_data_length} lowercase=yes |
| |
| # Write the data to FRU device. |
| Write FRU Data Via IPMI ${fru_device_id} ${read_write_offset} ${write_data_prefixed} ${write_data_length} |
| |
| # Read the FRU data. |
| ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} |
| ${resp_data}= Set Variable ${resp.split()[1:]} |
| |
| # Verify if the data written and read are same. |
| Should Be Equal ${write_data} ${resp_data} |
| |
| # Reboot BMC and verify if the data written and read are same. |
| IPMI MC Reset Cold (run) |
| ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} |
| Should Not Be Equal ${resp} ${initial_fru_data} |
| Should Be Equal ${resp[1:]} ${write_data} |
| |
| |
| *** Keywords *** |
| |
| Get IPMI FRU Devices Data |
| [Documentation] Get response from IPMI FRU command and format data |
| ... with Board or Product serial as key and corresponding data as value. |
| [Arguments] ${ipmi_output} |
| |
| # Description of Argument(s): |
| # ipmi_output All the FRU devices listed in IPMI FRU command. |
| |
| # Get the FRU list and return as a dictionary with serial number as key. |
| # Example: |
| # fru_data = { |
| # "123456789012345XYZ": |
| # { |
| # FRU Device Description : Builtin FRU Device (ID 0), |
| # Chassis Type : Rack Mount Chassis, |
| # Chassis Part Number : xxx-xxxxx-xxxx-xxx, |
| # Board Mfg Date : Fri Oct 16 06:34:00 2020 UTC, |
| # Board Mfg : XXXXX, |
| # Board Product : XXXXX, |
| # Board Serial : 123456789012345XYZ, |
| # Board Part Number : xxx.xxxxx.xxxx |
| # Board Extra : 01 |
| # Product Manufacturer : XXXXX |
| # Product Name : XXXXX |
| # Product Part Number : xxx-xxxx-xxxx-xxx |
| # Product Version : v1.0 |
| # Product Serial : 1234567890XYZ |
| # },....} |
| |
| # Gets response from FRU data and split each device. |
| ${output}= Set Variable ${ipmi_output.strip("\n")} |
| ${output}= Split String ${output} \n\n |
| &{fru}= Create Dictionary |
| ${num}= Set Variable 0 |
| |
| # For each device, identify either Board Serial/Product Serial (whichever is available). |
| FOR ${devices} IN @{output} |
| &{tmp}= Create Dictionary |
| ${dev}= Split String ${devices} \n |
| FOR ${device} IN @{dev} |
| ${ipmi_fru_board_serial_status}= Run Keyword And Return Status Should Contain ${device} Board Serial |
| Exit For Loop If '${ipmi_fru_board_serial_status}' == 'True' |
| END |
| ${frudata}= Get From List ${output} ${num} |
| ${serial_no}= Run Keyword If '${ipmi_fru_board_serial_status}' == 'True' |
| ... Get Lines Containing String ${frudata} Board Serial |
| ... ELSE |
| ... Get Lines Containing String ${frudata} Product Serial |
| |
| # Get each device and split field as key and value and append to a dictionary. |
| ${serial_nos}= Set Variable ${serial_no.strip()} |
| ${data}= Split String ${serial_nos} : |
| ${serial_number}= Get From List ${data} 1 |
| ${num}= Evaluate int(${num}) + 1 |
| FOR ${entry} IN @{dev} |
| ${entry}= Split String ${entry} ${SPACE}:${SPACE} |
| ${entry1}= Set Variable ${entry[0].strip()} |
| ${entry2}= Set Variable ${entry[1].strip()} |
| Set To Dictionary ${tmp} ${entry1} ${entry2} |
| END |
| ${serial_number}= Set Variable ${serial_number.strip()} |
| # Assign serial number as key for main dictionary and a each device detail as value. |
| Set To Dictionary ${fru} ${serial_number} ${tmp} |
| END |
| |
| [Return] ${fru} |
| |
| |
| Get DBUS Dictionary For FRU Devices |
| [Documentation] Provides the dictionary of DBUS FRU devices from DBUS FRU. |
| [Arguments] ${dbus_fru} ${ipmi_fru} |
| |
| # Description of Argument(s): |
| # dbus_fru FRU dbus uri list. |
| # ipmi_fru IPMI FRU details. |
| |
| # Execute DBUS Introspect Command for each device, |
| # Appends dictionary with serial number as key and FRU dbus uri as value, |
| # if the IPMI FRU key matches the serial number of each device dbus response. |
| # Example : |
| # ${dbus_output} = { "123456789012345XYZ" : "xyz.openbmc_project.FruDevice/xyz/openbmc_project/FruDevice/Device_0" } |
| FOR ${fru} IN @{dbus_fru} |
| ${cmd}= Catenate ${BUSCTL_FRU} ${fru} |
| ${dbus_output}= Execute DBUS Introspect Command ${cmd} |
| ${dbus_fru_board_serial_status}= Run Keyword And Return Status Should Contain ${dbus_output} .BOARD_SERIAL |
| ${dbus_fru_product_serial_status}= Run Keyword And Return Status Should Contain ${dbus_output} .PRODUCT_SERIAL |
| Run Keyword If '${dbus_fru_board_serial_status}' == 'True' or '${dbus_fru_product_serial_status}' == 'True' |
| ... Create Dictionary For DBUS URI ${dbus_output} ${ipmi_fru} ${dbus_fru_board_serial_status} ${cmd} |
| END |
| |
| |
| Create Dictionary For DBUS URI |
| [Documentation] Create Dictionary For DBUS URI |
| [Arguments] ${dbus_output} ${ipmi_fru} ${dbus_fru_board_serial_status} ${fru_command} |
| |
| # Description of Argument(s): |
| # dbus_output Dbus response got from BMC console. |
| # ipmi_fru IPMI FRU details. |
| # dbus_fru_board_serial_status FRU devices may have either BOARD_SERIAL or PRODUCT_SERIAL |
| # ... if status was true value of BOARD_SERIAL will be taken for dictionary as an key |
| # ... otherwise value of PRODUCT_SERIAL will be taken as an key for dictionary. |
| # fru_command FRU command to map into dictionary as value. |
| |
| # Validates the IPMI FRU dictionary key with dbus uri response serial number. |
| # If matches then, sets the serial number as key and FRU uri as value. |
| # ${dbus_dict} defined under variable section. |
| FOR ${ipmi_fru_serial_no} IN @{ipmi_fru.keys()} |
| ${serial_no}= Run Keyword If '${dbus_fru_board_serial_status}' == 'True' |
| ... Get Lines Containing String ${dbus_output} .BOARD_SERIAL |
| ... ELSE |
| ... Get Lines Containing String ${dbus_output} .PRODUCT_SERIAL |
| ${serial_no}= Split String ${serial_no} " |
| ${dbus_serial_no}= Set Variable ${serial_no[1].strip()} |
| ${serial_no_status}= Run Keyword And Return Status Should Be Equal As Strings ${ipmi_fru_serial_no} ${dbus_serial_no} |
| Run Keyword If '${serial_no_status}' == 'True' |
| ... Run Keywords Set To Dictionary ${dbus_dict} ${dbus_serial_no} ${fru_command} AND |
| ... Exit For Loop |
| END |
| |
| |
| Compare IPMI FRU with DBUS |
| [Documentation] Compare the IPMI FRU dictionary values with DBUS dictionary values, |
| ... if the serial number is present in both FRU and dbus dictionaries. |
| [Arguments] ${ipmi_fru} |
| |
| # Description of Argument(s): |
| # ipmi_fru IPMI FRU device details. |
| |
| # With each IPMI FRU key, get the corresponding valid from dbus dictionary, |
| # Execute the value which is dbus uri and, |
| # validate each dbus field value with IPMI FRU field value. |
| # Values are validated for keys present in the ipmi_dbus_name_mapping dictionary. |
| # Example : |
| # IPMI FRU field : |
| # Board Part Number : 111.22222.0000 |
| # DBUS FRU field : |
| # .BOARD_PART_NUMBER property s "111.22222.0000" emits-change |
| FOR ${key} ${ipmi_fru_value} IN &{ipmi_fru} |
| ${dbus_resp}= Execute DBUS Introspect Command ${dbus_dict}[${key}] |
| ${ipmi_fru_subkeys}= Get Dictionary Keys ${ipmi_fru_value} |
| FOR ${subkeys} IN @{ipmi_fru_subkeys} |
| ${key_status}= Run Keyword And Return Status Dictionary Should Contain Key |
| ... ${ipmi_dbus_name_mapping} ${subkeys} |
| Continue For Loop If '${key_status}' == 'False' |
| ${property_name}= Get From Dictionary ${ipmi_dbus_name_mapping} ${subkeys} |
| ${dbus_data}= Get Lines Containing String ${dbus_resp} ${property_name} |
| ${dbus_value}= Set Variable ${dbus_data.split('"')[1].strip()} |
| ${ipmi_response}= Get From Dictionary ${ipmi_fru_value} ${subkeys} |
| ${status}= Run Keyword And Return Status Should Contain ${property_name} DATE |
| IF ${status} |
| # If the required IPMI field has date field, the IPMI FRU value is converted to |
| # format = %Y-%m-%d - %H:%M:%S and validated against dbus FRU data. |
| ${ipmi_date}= Convert Date ${ipmi_response} date_format=%a %b %d %H:%M:%S %Y |
| ... result_format=%Y-%m-%d - %H:%M:%S |
| Run Keyword And Continue On Failure Should Be Equal As Strings ${ipmi_date} ${dbus_value} |
| ... message=${property_name} Property value mismatch with IPMI and DBUS |
| ELSE |
| Run Keyword And Continue On Failure Should Be Equal As Strings ${ipmi_response} ${dbus_value} |
| ... message=${property_name} Property value mismatch with IPMI and DBUS |
| END |
| END |
| END |
| |
| |
| Get FRU Inventory Area Info |
| [Documentation] IPMI Get FRU Inventory Area Info and returns FRU Inventory area size in bytes. |
| |
| ${resp}= Run IPMI Standard Command raw ${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][0]} ${fru_device_id} |
| ${resp}= Split String ${resp} |
| |
| [Return] ${resp[0]} |
| |
| |
| Read FRU Data Via IPMI |
| [Documentation] Read FRU data using IPMI raw command. |
| [Arguments] ${fru_id} ${offset} |
| |
| # Description of Argument(s): |
| # fru_id FRU id. |
| # offset Offset byte for read FRU command. |
| |
| # IPMI Read FRU Data Command. |
| # 0xff - Count to read --- count is ‘1’ based |
| ${resp}= Run IPMI Standard Command |
| ... raw ${IPMI_RAW_CMD['FRU']['Read'][0]} ${fru_id} ${offset} 0xff |
| |
| [Return] ${resp} |
| |
| |
| Write FRU Data Via IPMI |
| [Documentation] Write FRU data using IPMI raw command. |
| [Arguments] ${fru_id} ${offset} ${data} ${length} |
| |
| # Description of Argument(s): |
| # fru_id FRU id. |
| # offset Offset byte for read FRU command. |
| # data Data to write for write FRU command. |
| # length Count of bytes that gets written in write FRU command. |
| |
| # IPMI Write FRU Data Command. |
| ${resp}= Run IPMI Standard Command |
| ... raw ${IPMI_RAW_CMD['FRU']['Write'][0]} ${fru_id} ${offset} ${data} |
| |
| Should Be Equal As Strings ${resp} ${length} |
| |
| |
| Generate Random Data For FRU |
| [Documentation] Generate random data for write in FRU. |
| |
| # Description: |
| # Generates string of bytes and convert to hexadecimal data. |
| # Gets the length of initial FRU data read with IPMI read FRU device command. |
| |
| # ${frudata_prefixed} string with bytes prefixed 0x by default |
| # ${fru_data} string with only hexadecimal bytes without prefix |
| |
| ${string}= Generate Random String ${initial_fru_length} [LETTERS] |
| ${frudata_prefixed} ${fru_data}= Identify Request Data ${string} |
| |
| [Return] ${frudata_prefixed} ${fru_data} |
| |
| |
| Get Default FRU Data |
| [Documentation] Get default data via read FRU data IPMI command. |
| |
| # Read the default FRU device data. |
| # split the response and identify length of Requested data. |
| ${initial_fru_data}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} |
| ${initial_fru_list}= Split String ${initial_fru_data} |
| ${initial_fru_list}= Set Variable ${initial_fru_list[1:]} |
| ${initial_fru_length}= Get Length ${initial_fru_list} |
| Set Test Variable ${initial_fru_data} |
| Set Test Variable ${initial_fru_list} |
| Set Test Variable ${initial_fru_length} |
| |
| |
| Restore Default FRU Data |
| [Documentation] Restore default FRU data. |
| |
| # Prefix 0x to initial request data. |
| ${fru_list}= Prefix Bytes ${initial_fru_list} |
| ${fru_byte}= Evaluate " ".join(${fru_list}) |
| ${initial_frulength_hex}= Convert To Hex ${initial_fru_length} lowercase=yes |
| # Write the initial FRU data to restore. |
| Write FRU Data Via IPMI ${fru_device_id} ${read_write_offset} ${fru_byte} ${initial_frulength_hex} |
| # Verify whether initial FRU data is restored. |
| ${fru_data}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} |
| Should Be Equal ${fru_data} ${initial_fru_data} |