blob: dee75953d7ec91039110ff6cda4c98c3f092793b [file] [log] [blame]
*** 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}