1*** Settings *** 2Documentation Test IPMI FRU data. 3 4Resource ../lib/ipmi_client.robot 5Resource ../lib/bmc_dbus.robot 6Variables ../data/ipmi_raw_cmd_table.py 7Library ../lib/ipmi_utils.py 8 9Force Tags IPMI_FRU_Device 10 11*** Variables *** 12 13${FRU_NAME} dimm01 dimm02 cpu0 cpu1 motherboard 14${BUSCTL_FRU} xyz.openbmc_project.FruDevice 15${FRU_DBUS_URL} /xyz/openbmc_project/FruDevice 16${fru_device_id} 0x00 17${fru_device_id_invalid} 0xff 18${read_write_offset} 0x00 0x00 19&{dbus_dict} 20&{ipmi_dbus_name_mapping} Chassis Part Number=.CHASSIS_PART_NUMBER 21... Board Mfg Date=.BOARD_MANUFACTURE_DATE Board Mfg=.BOARD_MANUFACTURER 22... Board Product=.BOARD_PRODUCT_NAME Board Serial=.BOARD_SERIAL_NUMBER 23... Board Part Number=.BOARD_PART_NUMBER Product Manufacturer=.PRODUCT_MANUFACTURER 24... Product Name=.PRODUCT_PRODUCT_NAME Product Part Number=.PRODUCT_PART_NUMBER 25... Product Version=.PRODUCT_VERSION Product Serial=.PRODUCT_SERIAL_NUMBER 26 27*** Test Cases *** 28Test FRU Device Name 29 [Documentation] Search FRU for device name 30 [Tags] Test_FRU_Device_Name 31 32 ${output}= Run External IPMI Standard Command fru 33 Should Contain ${output} ${FRU_NAME} msg=Fail: Given FRU device ${FRU_NAME} not found 34 35 36Verify Fru Device Configuration 37 [Documentation] Read the FRU device configuration of each device 38 ... and compare with DBUS data. 39 [Tags] Verify_Fru_Device_Configuration 40 41 # IPMI FRU print. 42 ${ipmi_output}= Run External IPMI Standard Command fru 43 44 # Create dictionary with FRU device serial number as key and details as value from IPMI. 45 ${ipmi_fru}= Get IPMI FRU Devices Data ${ipmi_output} 46 47 # Returns all the available FRU dbus uri. 48 ${dbus_fru_uri}= Get DBUS URI List From BMC ${BUSCTL_FRU} ${FRU_DBUS_URL} 49 50 # Returns all the FRU device uri with special characters removed. 51 ${dbus_fru_uri_list}= Fetch DBUS URI List Without Unicode ${dbus_fru_uri} 52 53 # Creates dictionary with serial number as key, and corresponding FRU device uri as value from dbus. 54 Get DBUS Dictionary For FRU Devices ${dbus_fru_uri_list} ${ipmi_fru} 55 56 # Compare dbus dictionary each field, with IPMI FRU device fields for each FRU device. 57 Compare IPMI FRU with DBUS ${ipmi_fru} 58 59 60Verify Get FRU Inventory Area Info 61 [Documentation] Verify IPMI get FRU inventory area info command. 62 [Tags] Verify_Get_FRU_Inventory_Area_Info 63 64 # IPMI read FRU data command. 65 ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} 66 ${bytes_read}= Set Variable ${resp.split()[0]} 67 68 # IPMI get FRU inventory area info command. 69 ${bytes_inventory}= Get FRU Inventory Area Info 70 71 # Compare read FRU data Count returned -- count is ‘1’ based, with inventory area count. 72 Should Be Equal ${bytes_inventory} ${bytes_read} 73 74 75Verify Get FRU Inventory Area Info For Invalid Device Data 76 [Documentation] Verify IPMI get FRU inventory area info command for Invalid Device Data. 77 [Tags] Verify_Get_FRU_Inventory_Area_Info_For_Invalid_Device_Data 78 79 # Verify response for invalid FRU device id. 80 Run Keyword and Expect Error *${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][1]}* 81 ... Run IPMI Standard Command raw ${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][0]} ${fru_device_id_invalid} 82 83 84Verify Get FRU Inventory Area Info For Invalid Data Request 85 [Documentation] Verify IPMI get FRU inventory area info command for Invalid Data Request. 86 [Tags] Verify_Get_FRU_Inventory_Area_Info_For_Invalid_Data_Request 87 88 # Verify response for invalid response data - extra bytes. 89 Run Keyword and Expect Error *${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][2]}* 90 ... Run IPMI Standard Command raw ${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][0]} ${fru_device_id} 0x00 91 92 93Verify IPMI Write FRU Data 94 [Documentation] Verify write data in FRU and compare data from read FRU data command via IPMI. 95 [Tags] Verify_IPMI_Write_FRU_Data 96 [Setup] Get Default FRU Data 97 [Teardown] Restore Default FRU Data 98 99 # Generate random data to write in FRU device. 100 ${write_data_prefixed} ${write_data}= Generate Random Data For FRU 101 102 # Get the length of the data generated and convert to hex. 103 ${write_data_length}= Get Length ${write_data} 104 ${write_data_length}= Convert To Hex ${write_data_length} lowercase=yes 105 106 # Write the data to FRU device. 107 Write FRU Data Via IPMI ${fru_device_id} ${read_write_offset} ${write_data_prefixed} ${write_data_length} 108 109 # Read the FRU data. 110 ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} 111 ${resp_data}= Set Variable ${resp.split()[1:]} 112 113 # Verify if the data written and read are same. 114 Should Be Equal ${write_data} ${resp_data} 115 116 117Verify IPMI Write FRU Data With BMC Reboot 118 [Documentation] Verify IPMI write data in FRU and compare data from read FRU data command after BMC reboot. 119 [Tags] Verify_IPMI_Write_FRU_Data_With_BMC_Reboot 120 [Setup] Get Default FRU Data 121 [Teardown] Restore Default FRU Data 122 123 # Generate random data to write in FRU device. 124 ${write_data_prefixed} ${write_data}= Generate Random Data For FRU 125 126 # Get the length of the data generated and convert to hex. 127 ${write_data_length}= Get Length ${write_data} 128 ${write_data_length}= Convert To Hex ${write_data_length} lowercase=yes 129 130 # Write the data to FRU device. 131 Write FRU Data Via IPMI ${fru_device_id} ${read_write_offset} ${write_data_prefixed} ${write_data_length} 132 133 # Read the FRU data. 134 ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} 135 ${resp_data}= Set Variable ${resp.split()[1:]} 136 137 # Verify if the data written and read are same. 138 Should Be Equal ${write_data} ${resp_data} 139 140 # Reboot BMC and verify if the data written and read are same. 141 IPMI MC Reset Cold (run) 142 ${resp}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} 143 Should Not Be Equal ${resp} ${initial_fru_data} 144 Should Be Equal ${resp[1:]} ${write_data} 145 146 147*** Keywords *** 148 149Get IPMI FRU Devices Data 150 [Documentation] Get response from IPMI FRU command and format data 151 ... with Board or Product serial as key and corresponding data as value. 152 [Arguments] ${ipmi_output} 153 154 # Description of Argument(s): 155 # ipmi_output All the FRU devices listed in IPMI FRU command. 156 157 # Get the FRU list and return as a dictionary with serial number as key. 158 # Example: 159 # fru_data = { 160 # "123456789012345XYZ": 161 # { 162 # FRU Device Description : Builtin FRU Device (ID 0), 163 # Chassis Type : Rack Mount Chassis, 164 # Chassis Part Number : xxx-xxxxx-xxxx-xxx, 165 # Board Mfg Date : Fri Oct 16 06:34:00 2020 UTC, 166 # Board Mfg : XXXXX, 167 # Board Product : XXXXX, 168 # Board Serial : 123456789012345XYZ, 169 # Board Part Number : xxx.xxxxx.xxxx 170 # Board Extra : 01 171 # Product Manufacturer : XXXXX 172 # Product Name : XXXXX 173 # Product Part Number : xxx-xxxx-xxxx-xxx 174 # Product Version : v1.0 175 # Product Serial : 1234567890XYZ 176 # },....} 177 178 # Gets response from FRU data and split each device. 179 ${output}= Set Variable ${ipmi_output.strip("\n")} 180 ${output}= Split String ${output} \n\n 181 &{fru}= Create Dictionary 182 ${num}= Set Variable 0 183 184 # For each device, identify either Board Serial/Product Serial (whichever is available). 185 FOR ${devices} IN @{output} 186 &{tmp}= Create Dictionary 187 ${dev}= Split String ${devices} \n 188 FOR ${device} IN @{dev} 189 ${ipmi_fru_board_serial_status}= Run Keyword And Return Status Should Contain ${device} Board Serial 190 Exit For Loop If '${ipmi_fru_board_serial_status}' == 'True' 191 END 192 ${frudata}= Get From List ${output} ${num} 193 ${serial_no}= Run Keyword If '${ipmi_fru_board_serial_status}' == 'True' 194 ... Get Lines Containing String ${frudata} Board Serial 195 ... ELSE 196 ... Get Lines Containing String ${frudata} Product Serial 197 198 # Get each device and split field as key and value and append to a dictionary. 199 ${serial_nos}= Set Variable ${serial_no.strip()} 200 ${data}= Split String ${serial_nos} : 201 ${serial_number}= Get From List ${data} 1 202 ${num}= Evaluate int(${num}) + 1 203 FOR ${entry} IN @{dev} 204 ${entry}= Split String ${entry} ${SPACE}:${SPACE} 205 ${entry1}= Set Variable ${entry[0].strip()} 206 ${entry2}= Set Variable ${entry[1].strip()} 207 Set To Dictionary ${tmp} ${entry1} ${entry2} 208 END 209 ${serial_number}= Set Variable ${serial_number.strip()} 210 # Assign serial number as key for main dictionary and a each device detail as value. 211 Set To Dictionary ${fru} ${serial_number} ${tmp} 212 END 213 214 [Return] ${fru} 215 216 217Get DBUS Dictionary For FRU Devices 218 [Documentation] Provides the dictionary of DBUS FRU devices from DBUS FRU. 219 [Arguments] ${dbus_fru} ${ipmi_fru} 220 221 # Description of Argument(s): 222 # dbus_fru FRU dbus uri list. 223 # ipmi_fru IPMI FRU details. 224 225 # Execute DBUS Introspect Command for each device, 226 # Appends dictionary with serial number as key and FRU dbus uri as value, 227 # if the IPMI FRU key matches the serial number of each device dbus response. 228 # Example : 229 # ${dbus_output} = { "123456789012345XYZ" : "xyz.openbmc_project.FruDevice/xyz/openbmc_project/FruDevice/Device_0" } 230 FOR ${fru} IN @{dbus_fru} 231 ${cmd}= Catenate ${BUSCTL_FRU} ${fru} 232 ${dbus_output}= Execute DBUS Introspect Command ${cmd} 233 ${dbus_fru_board_serial_status}= Run Keyword And Return Status Should Contain ${dbus_output} .BOARD_SERIAL 234 ${dbus_fru_product_serial_status}= Run Keyword And Return Status Should Contain ${dbus_output} .PRODUCT_SERIAL 235 Run Keyword If '${dbus_fru_board_serial_status}' == 'True' or '${dbus_fru_product_serial_status}' == 'True' 236 ... Create Dictionary For DBUS URI ${dbus_output} ${ipmi_fru} ${dbus_fru_board_serial_status} ${cmd} 237 END 238 239 240Create Dictionary For DBUS URI 241 [Documentation] Create Dictionary For DBUS URI 242 [Arguments] ${dbus_output} ${ipmi_fru} ${dbus_fru_board_serial_status} ${fru_command} 243 244 # Description of Argument(s): 245 # dbus_output Dbus response got from BMC console. 246 # ipmi_fru IPMI FRU details. 247 # dbus_fru_board_serial_status FRU devices may have either BOARD_SERIAL or PRODUCT_SERIAL 248 # ... if status was true value of BOARD_SERIAL will be taken for dictionary as an key 249 # ... otherwise value of PRODUCT_SERIAL will be taken as an key for dictionary. 250 # fru_command FRU command to map into dictionary as value. 251 252 # Validates the IPMI FRU dictionary key with dbus uri response serial number. 253 # If matches then, sets the serial number as key and FRU uri as value. 254 # ${dbus_dict} defined under variable section. 255 FOR ${ipmi_fru_serial_no} IN @{ipmi_fru.keys()} 256 ${serial_no}= Run Keyword If '${dbus_fru_board_serial_status}' == 'True' 257 ... Get Lines Containing String ${dbus_output} .BOARD_SERIAL 258 ... ELSE 259 ... Get Lines Containing String ${dbus_output} .PRODUCT_SERIAL 260 ${serial_no}= Split String ${serial_no} " 261 ${dbus_serial_no}= Set Variable ${serial_no[1].strip()} 262 ${serial_no_status}= Run Keyword And Return Status Should Be Equal As Strings ${ipmi_fru_serial_no} ${dbus_serial_no} 263 Run Keyword If '${serial_no_status}' == 'True' 264 ... Run Keywords Set To Dictionary ${dbus_dict} ${dbus_serial_no} ${fru_command} AND 265 ... Exit For Loop 266 END 267 268 269Compare IPMI FRU with DBUS 270 [Documentation] Compare the IPMI FRU dictionary values with DBUS dictionary values, 271 ... if the serial number is present in both FRU and dbus dictionaries. 272 [Arguments] ${ipmi_fru} 273 274 # Description of Argument(s): 275 # ipmi_fru IPMI FRU device details. 276 277 # With each IPMI FRU key, get the corresponding valid from dbus dictionary, 278 # Execute the value which is dbus uri and, 279 # validate each dbus field value with IPMI FRU field value. 280 # Values are validated for keys present in the ipmi_dbus_name_mapping dictionary. 281 # Example : 282 # IPMI FRU field : 283 # Board Part Number : 111.22222.0000 284 # DBUS FRU field : 285 # .BOARD_PART_NUMBER property s "111.22222.0000" emits-change 286 FOR ${key} ${ipmi_fru_value} IN &{ipmi_fru} 287 ${dbus_resp}= Execute DBUS Introspect Command ${dbus_dict}[${key}] 288 ${ipmi_fru_subkeys}= Get Dictionary Keys ${ipmi_fru_value} 289 FOR ${subkeys} IN @{ipmi_fru_subkeys} 290 ${key_status}= Run Keyword And Return Status Dictionary Should Contain Key 291 ... ${ipmi_dbus_name_mapping} ${subkeys} 292 Continue For Loop If '${key_status}' == 'False' 293 ${property_name}= Get From Dictionary ${ipmi_dbus_name_mapping} ${subkeys} 294 ${dbus_data}= Get Lines Containing String ${dbus_resp} ${property_name} 295 ${dbus_value}= Set Variable ${dbus_data.split('"')[1].strip()} 296 ${ipmi_response}= Get From Dictionary ${ipmi_fru_value} ${subkeys} 297 ${status}= Run Keyword And Return Status Should Contain ${property_name} DATE 298 IF ${status} 299 # If the required IPMI field has date field, the IPMI FRU value is converted to 300 # format = %Y-%m-%d - %H:%M:%S and validated against dbus FRU data. 301 ${ipmi_date}= Convert Date ${ipmi_response} date_format=%a %b %d %H:%M:%S %Y 302 ... result_format=%Y-%m-%d - %H:%M:%S 303 Run Keyword And Continue On Failure Should Be Equal As Strings ${ipmi_date} ${dbus_value} 304 ... message=${property_name} Property value mismatch with IPMI and DBUS 305 ELSE 306 Run Keyword And Continue On Failure Should Be Equal As Strings ${ipmi_response} ${dbus_value} 307 ... message=${property_name} Property value mismatch with IPMI and DBUS 308 END 309 END 310 END 311 312 313Get FRU Inventory Area Info 314 [Documentation] IPMI Get FRU Inventory Area Info and returns FRU Inventory area size in bytes. 315 316 ${resp}= Run IPMI Standard Command raw ${IPMI_RAW_CMD['FRU']['Inventory_Area_Info'][0]} ${fru_device_id} 317 ${resp}= Split String ${resp} 318 319 [Return] ${resp[0]} 320 321 322Read FRU Data Via IPMI 323 [Documentation] Read FRU data using IPMI raw command. 324 [Arguments] ${fru_id} ${offset} 325 326 # Description of Argument(s): 327 # fru_id FRU id. 328 # offset Offset byte for read FRU command. 329 330 # IPMI Read FRU Data Command. 331 # 0xff - Count to read --- count is ‘1’ based 332 ${resp}= Run IPMI Standard Command 333 ... raw ${IPMI_RAW_CMD['FRU']['Read'][0]} ${fru_id} ${offset} 0xff 334 335 [Return] ${resp} 336 337 338Write FRU Data Via IPMI 339 [Documentation] Write FRU data using IPMI raw command. 340 [Arguments] ${fru_id} ${offset} ${data} ${length} 341 342 # Description of Argument(s): 343 # fru_id FRU id. 344 # offset Offset byte for read FRU command. 345 # data Data to write for write FRU command. 346 # length Count of bytes that gets written in write FRU command. 347 348 # IPMI Write FRU Data Command. 349 ${resp}= Run IPMI Standard Command 350 ... raw ${IPMI_RAW_CMD['FRU']['Write'][0]} ${fru_id} ${offset} ${data} 351 352 Should Be Equal As Strings ${resp} ${length} 353 354 355Generate Random Data For FRU 356 [Documentation] Generate random data for write in FRU. 357 358 # Description: 359 # Generates string of bytes and convert to hexadecimal data. 360 # Gets the length of initial FRU data read with IPMI read FRU device command. 361 362 # ${frudata_prefixed} string with bytes prefixed 0x by default 363 # ${fru_data} string with only hexadecimal bytes without prefix 364 365 ${string}= Generate Random String ${initial_fru_length} [LETTERS] 366 ${frudata_prefixed} ${fru_data}= Identify Request Data ${string} 367 368 [Return] ${frudata_prefixed} ${fru_data} 369 370 371Get Default FRU Data 372 [Documentation] Get default data via read FRU data IPMI command. 373 374 # Read the default FRU device data. 375 # split the response and identify length of Requested data. 376 ${initial_fru_data}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} 377 ${initial_fru_list}= Split String ${initial_fru_data} 378 ${initial_fru_list}= Set Variable ${initial_fru_list[1:]} 379 ${initial_fru_length}= Get Length ${initial_fru_list} 380 Set Test Variable ${initial_fru_data} 381 Set Test Variable ${initial_fru_list} 382 Set Test Variable ${initial_fru_length} 383 384 385Restore Default FRU Data 386 [Documentation] Restore default FRU data. 387 388 # Prefix 0x to initial request data. 389 ${fru_list}= Prefix Bytes ${initial_fru_list} 390 ${fru_byte}= Evaluate " ".join(${fru_list}) 391 ${initial_frulength_hex}= Convert To Hex ${initial_fru_length} lowercase=yes 392 # Write the initial FRU data to restore. 393 Write FRU Data Via IPMI ${fru_device_id} ${read_write_offset} ${fru_byte} ${initial_frulength_hex} 394 # Verify whether initial FRU data is restored. 395 ${fru_data}= Read FRU Data Via IPMI ${fru_device_id} ${read_write_offset} 396 Should Be Equal ${fru_data} ${initial_fru_data} 397