blob: b4e69d2bf4d6505c4414c97fcceaf2a11398085a [file] [log] [blame]
Steven Sombar6b280142018-02-12 10:45:13 -06001*** Settings ***
Steven Sombar43d6ba32018-02-16 11:25:09 -06002Documentation Utilities for fan tests.
Steven Sombar6b280142018-02-12 10:45:13 -06003
Steven Sombar43d6ba32018-02-16 11:25:09 -06004Library ../lib/bmc_ssh_utils.py
5Resource ../lib/openbmc_ffdc_utils.robot
6Variables ../data/variables.py
Steven Sombar6b280142018-02-12 10:45:13 -06007
Steven Sombar47ac2f42019-04-17 21:13:43 -05008*** Variables ***
9
10# Fan state values.
11${fan_functional} ${1}
12${fan_nonfunctional} ${0}
13
14# Criteria for a fan at maximum speed.
15${max_speed}= ${10400}
16
17
Steven Sombar6b280142018-02-12 10:45:13 -060018*** Keywords ***
19
Steven Sombar6b280142018-02-12 10:45:13 -060020Is Water Cooled
21 [Documentation] Return 1 if system is water cooled, 0 othersise.
22
23 ${water_cooled}= Read Attribute
Steven Sombaraaaab222018-12-19 13:16:23 -060024 ... ${HOST_INVENTORY_URI}system/chassis WaterCooled
Steven Sombar6b280142018-02-12 10:45:13 -060025 [Return] ${water_cooled}
26
27
Steven Sombar43d6ba32018-02-16 11:25:09 -060028Get Fan Names
Steven Sombar1e656462018-07-13 14:04:27 -050029 [Documentation] Get the names of the fans marked present in inventory.
Steven Sombar43d6ba32018-02-16 11:25:09 -060030 [Arguments] ${fan_names}
31 # This keyword populates the fan_names list with the names of
32 # fans present in inventory e.g. fan0, fan2, fan3.
Steven Sombar6b280142018-02-12 10:45:13 -060033
Steven Sombar43d6ba32018-02-16 11:25:09 -060034 # Description of Argument(s):
35 # fan_names The list of fan names to which new fan names are to be
36 # added to. This list is returned to the caller.
37
Steven Sombaraaaab222018-12-19 13:16:23 -060038 ${fan_uris}= Get Endpoint Paths ${HOST_INVENTORY_URI}system fan
Steven Sombar6b280142018-02-12 10:45:13 -060039 : FOR ${fan_uri} IN @{fan_uris}
Steven Sombar43d6ba32018-02-16 11:25:09 -060040 \ ${fan_properties}= Read Properties ${fan_uri}
Steven Sombar1e656462018-07-13 14:04:27 -050041 \ ${fan_present}= Get Variable Value ${fan_properties['Present']} 0
Steven Sombar47ac2f42019-04-17 21:13:43 -050042 \ ${fan_functional}= Get Variable Value
43 ... ${fan_properties['Functional']} 0
Steven Sombar84689182018-09-07 13:46:06 -050044 \ Continue For Loop If ${fan_present} == 0 or ${fan_functional} == 0
Steven Sombar43d6ba32018-02-16 11:25:09 -060045 \ ${remaining_uri} ${fan_name}= Split Path ${fan_uri}
46 \ Append To List ${fan_names} ${fan_name}
47
48 [Return] ${fan_names}
49
50
51Verify System Error Indication Due To Fans
52 [Documentation] Verify enclosure LEDs are on and there's an error log.
53
54 # Both enclosure LEDs should now be On.
55 Verify Front And Rear LED State On
56
57 # An error log should now exist.
58 Error Logs Should Exist
59
60
61Verify Front And Rear LED State
62 [Documentation] Check state of the front and rear enclsure fault LEDs.
63 [Arguments] ${state}
64 # Both LEDs should be in the specified state. If not fail the test case.
65
66 # Description of Argument(s):
67 # state The state to check for, either 'Off' or 'On'.
68
69 ${front_fault}= Get System LED State front_fault
70 ${rear_fault}= Get System LED State rear_fault
Steven Sombar1508aff2018-04-06 12:53:42 -050071
Steven Sombar43d6ba32018-02-16 11:25:09 -060072 Run Keyword If
73 ... '${front_fault}' != '${state}' or '${rear_fault}' != '${state}'
74 ... Fail msg=Expecting both enclosure LEDs to be ${state}.
75
76
77Set Fan State
78 [Documentation] Set the fan state, either functional or non-functional.
79 [Arguments] ${fan_name} ${fan_state}
80
81 # Description of Argument(s):
82 # fan_name The name of the fan, e.g. "fan2".
83 # fan_state The state to set, 1 for functional, 2 for non-functional.
84
85 ${valueDict}= Create Dictionary data=${fan_state}
86 Write Attribute
87 ... ${HOST_INVENTORY_URI}system/chassis/motherboard/${fan_name}
88 ... Functional data=${valueDict}
89
90
Steven Sombar1508aff2018-04-06 12:53:42 -050091Set Fan Target Speed
92 [Documentation] Set the target speed of a fan.
93 [Arguments] ${fan_name} ${fan_speed}
94
95 # Description of argument(s):
96 # fan_name The name of the fan (e.g. "fan0").
97 # fan_speed The target speed to set (e.g. "9000").
98
99 ${valueDict}= Create Dictionary data=${fan_speed}
100 Write Attribute ${SENSORS_URI}fan_tach/${fan_name}_0
101 ... Target data=${valueDict}
102
103
Steven Sombar43d6ba32018-02-16 11:25:09 -0600104Get Target Speed Of Fans
Steven Sombar1508aff2018-04-06 12:53:42 -0500105 [Documentation] Return the maximum target speed of the system fans.
Steven Sombar43d6ba32018-02-16 11:25:09 -0600106
107 ${max_target}= Set Variable 0
108 ${paths}= Get Endpoint Paths ${SENSORS_URI}fan_tach/ 0
109 :FOR ${path} IN @{paths}
110 \ ${response}= OpenBMC Get Request ${path}
111 \ ${json}= To JSON ${response.content}
112 \ ${target_speed}= Set Variable ${json["data"]["Target"]}
113 \ ${max_target}= Run Keyword If ${target_speed} > ${max_target}
114 ... Set Variable ${target_speed} ELSE Set Variable ${max_target}
115 [Return] ${max_target}
Steven Sombar6b280142018-02-12 10:45:13 -0600116
117
Steven Sombar1508aff2018-04-06 12:53:42 -0500118Get Target And Blade Speeds
119 [Documentation] Return the fan target speed setting, the speed of the
120 ... fan's clockwise blade, and the speed of the counter-clockwise blade.
121 # Each fan unit has two counter-rotating fan blades
122 # One blade is expected to be moving but the other blade may not be
123 # moving whenever the fan unit is transitioning to a new target speed.
124 [Arguments] ${fan_name}
125
126 # Description of argument(s):
127 # fan_name The name of a fan (e.g. "fan0")
128
129 # Get the fan target speed and the clockwise blade speed.
130 ${path}= Catenate ${SENSORS_URI}fan_tach/${fan_name}_0
131 ${response}= OpenBMC Get Request ${path}
132 ${json}= To JSON ${response.content}
133 ${fan_clockwise_speed}= Set Variable ${json["data"]["Value"]}
134 ${target_speed}= Set Variable ${json["data"]["Target"]}
135
136 # Get the counter-clockwise blade speed.
137 ${path}= Catenate ${SENSORS_URI}fan_tach/${fan_name}_1
138 ${response}= OpenBMC Get Request ${path}
139 ${json}= To JSON ${response.content}
140 ${fan_counterclockwise_speed}= Set Variable ${json["data"]["Value"]}
141
142 [Return] ${target_speed} ${fan_clockwise_speed}
143 ... ${fan_counterclockwise_speed}
144
145
146Get Fan Target And Speed
147 [Documentation] Return the fan target speed setting and the
148 ... speed of the fastest blade.
149 [Arguments] ${fan_name}
150
151 # Description of argument(s):
152 # fan_name The name of a fan (e.g. "fan0")
153
154 ${target_speed} ${clockwise_speed} ${counterclockwise_speed}=
155 ... Get Target And Blade Speeds ${fan_name}
156 ${blade_speed}= Run Keyword If
157 ... ${clockwise_speed} > ${counterclockwise_speed}
158 ... Set Variable ${clockwise_speed} ELSE
159 ... Set Variable ${counterclockwise_speed}
160 [Return] ${target_speed} ${blade_speed}
161
162
163Set Fan Daemon State
164 [Documentation] Set the state of the fan control service.
165 [Arguments] ${state}
166
167 # Description of argument(s):
168 # state The desired state of the service, usually
169 # "start", "stop", or "restart".
170
171 ${cmd}= Catenate systemctl ${state} phosphor-fan-control@0.service
172 ${stdout} ${stderr} ${rc}= BMC Execute Command ${cmd}
173
174
Steven Sombar6b280142018-02-12 10:45:13 -0600175Verify Minimum Number Of Fans With Cooling Type
176 [Documentation] Verify minimum number of fans.
Steven Sombar43d6ba32018-02-16 11:25:09 -0600177 [Arguments] ${num_fans} ${water_cooled}
Steven Sombar6b280142018-02-12 10:45:13 -0600178
179 # Description of argument(s):
Steven Sombar43d6ba32018-02-16 11:25:09 -0600180 # num_fans The number of fans present in the system.
Steven Sombar6b280142018-02-12 10:45:13 -0600181 # water_cooled The value 1 if the system is water cooled,
Steven Sombar43d6ba32018-02-16 11:25:09 -0600182 # 0 if air cooled.
Steven Sombar6b280142018-02-12 10:45:13 -0600183
184 # For a water cooled system.
185 ${min_fans_water}= Set Variable 2
186
187 # For an air cooled system.
188 ${min_fans_air}= Set Variable 3
189
Michael Walshc108e422019-03-28 12:27:18 -0500190 Printn
Steven Sombar43d6ba32018-02-16 11:25:09 -0600191 Rpvars num_fans water_cooled
Steven Sombar6b280142018-02-12 10:45:13 -0600192
193 # If water cooled must have at least min_fans_water fans, otherwise
194 # issue Fatal Error and terminate testing.
195 Run Keyword If ${water_cooled} == 1 and ${num_fans} < ${min_fans_water}
196 ... Fatal Error
197 ... msg=Water cooled but less than ${min_fans_water} fans present.
198
199 # If air cooled must have at least min_fans_air fans.
200 Run Keyword If ${water_cooled} == 0 and ${num_fans} < ${min_fans_air}
201 ... Fatal Error
202 ... msg=Air cooled but less than ${min_fans_air} fans present.
203
204
205Verify Fan Monitors With State
206 [Documentation] Verify fan monitor daemons in the system state.
Steven Sombar43d6ba32018-02-16 11:25:09 -0600207 [Arguments] ${power_state}
Steven Sombar6b280142018-02-12 10:45:13 -0600208 # The number of monitoring daemons is dependent upon the system
209 # power state. If power is off there should be 0, if power
210 # is on there should be several.
Steven Sombar6b280142018-02-12 10:45:13 -0600211
212 # Description of argument(s):
213 # power_state Power staet of the system, either "On" or "Off"
214
215 ${cmd}= Catenate systemctl list-units | grep phosphor-fan | wc -l
216 ${num_fan_daemons} ${stderr} ${rc}= BMC Execute Command ${cmd}
217
218 Rpvars power_state num_fan_daemons
219
220 # Fail if system is On and there are no fan monitors.
221 Run Keyword If '${power_state}' == 'On' and ${num_fan_daemons} == 0
222 ... Fail msg=No phosphor-fan monitors found at power on.
223
224 # Fail if system is Off and the fan monitors are present.
225 Run Keyword If '${power_state}' == 'Off' and ${num_fan_daemons} != 0
226 ... Fail msg=Phosphor-fan monitors found at power off.
Steven Sombar47ac2f42019-04-17 21:13:43 -0500227
228
229Get Fan Count And Names
230 [Documentation] Return the number of fans and the fan names.
231
232 # The @{fan_names} list holds the names of the fans in the system.
233 @{fan_names} Create List
234 ${fan_names}= Get Fan Names ${fan_names}
235
236 ${number_of_fans}= Get Length ${fan_names}
237
238 Printn
239 Rprint Vars number_of_fans fan_names
240 [Return] ${number_of_fans} ${fan_names}
241
242
243Reset Fans
244 [Documentation] Set the fans to functional state.
245 # Set state of fans to functional by writing 1 to the Functional
246 # attribute of each fan in the @{fan_names} list. If @{fan_names}
247 # is empty nothing is done.
248 [Arguments] ${fan_names}
249
250 # Description of Argument(s):
251 # fan_names A list containing the names of the fans (e.g. fan0
252 # fan2 fan3).
253
254 :FOR ${fan_name} IN @{fan_names}
255 \ Set Fan State ${fan_name} ${fan_functional}
256
257
258Verify Fan Speed
259 [Documentation] Verify fans are running at or near target speed.
260 [Arguments] ${tolerance} ${fan_names}
261
262 # Description of argument(s):
263 # tolerance The speed tolerance criteria.
264 # A tolerance value of .15 means that the fan's speed
265 # should be within 15% of its set target speed.
266 # Fans may be accelerating to meet a new target, so
267 # allow .10 extra.
268 # fan_names A list containing the names of the fans (e.g. fan0 fan1).
269
270 # Compare the fan's speed with its target speed.
271 :FOR ${fan_name} IN @{fan_names}
272 \ ${target_speed} ${fan_speed}= Get Fan Target And Speed ${fan_name}
273 \ Rpvars fan_name target_speed fan_speed
274 \ # Calculate tolerance, which is a % of the target speed.
275 \ ${tolerance_value}= Evaluate ${tolerance}*${target_speed}
276 \ # Calculate upper and lower speed limits.
277 \ ${max_limit}= Evaluate ${target_speed}+${tolerance_value}
278 \ ${min_limit}= Evaluate ${target_speed}-${tolerance_value}
279 \ Run Keyword If
280 ... ${fan_speed} < ${min_limit} or ${fan_speed} > ${max_limit}
281 ... Fail msg=${fan_name} speed of ${fan_speed} is out of range.
282
283
284Verify Direct Fan Control
285 [Documentation] Verify direct control of fans.
286 [Arguments] ${max_fan_target_setting} ${min_speed}
287 ... ${minutes_to_stabilize} ${number_of_fans} ${fan_names}
288
289 # Overview:
290 # Turn off BMC's fan control daemon, then test to confirm
291 # that fans can be controlled manually.
292 # The app that takes data from sysfs and updates dbus is named hwmon.
293 # Verify hwmon functionality by comparing with what's on dbus
294 # (/xyz/openbmc_project/sensors/fan_tach/fan0_0, fan0_1, etc.)
295 # with what's in the BMC's file system at
296 # /sys/class/hwmon/hwmon9/fan*_input.
297
298 # Description of argument(s):
299 # max_fan_target_setting Integer value of maximum fan speed.
300 # min_speed Integer value of minimum speed.
301 # minutes_to_stabilize Time to wait for fan daemons to
302 # stabilize fan operation after
303 # tests (e.g. "4").
304 # number_of_fans The number of fans in the system.
305 # fan_names A list containing the names of the
306 # fans (e.g. fan0 fan1).
307
308 # Login to BMC and disable the fan daemon. Disabling the daemon sets
309 # manual mode.
310 Open Connection And Log In
311 Set Fan Daemon State stop
312
313 # For each fan, set a new target speed and wait for the fan to
314 # accelerate. Then check that the fan is running near that speed.
315 :FOR ${fan_name} IN @{fan_names}
316 \ Set Fan Target Speed ${fan_name} ${max_fan_target_setting}
317 \ Run Key U Sleep \ 60s
318 \ ${target_speed} ${cw_speed} ${ccw_speed}=
319 ... Get Target And Blade Speeds ${fan_name}
320 \ Rpvars fan_name target_speed cw_speed ccw_speed
321 \ Run Keyword If
322 ... ${cw_speed} < ${min_speed} or ${ccw_speed} < ${min_speed}
323 ... Fail msg=${fan_name} failed manual speed test.
324
325 # Check the fan speeds in the BMC file system.
326
327 # Get the location of the fan hwmon.
328 ${controller_path} ${stderr} ${rc}= BMC Execute Command
329 ... grep -ir max31785a /sys/class/hwmon/hwmon* | grep name
330 # E.g., controller_path=/sys/class/hwmon/hwmon10/name:max31785a.
331
332 ${hwmon_path} ${file_name}= Split Path ${controller_path}
333 # E.g., /sys/class/hwmon/hwmon10 or /sys/class/hwmon/hwmon9.
334
335 Rpvars controller_path hwmon_path
336
337 # Run the BMC command which gets fan speeds from the file system.
338 ${cmd}= Catenate cat ${hwmon_path}/fan*_input
339 ${stdout} ${stderr} ${rc}=
340 ... BMC Execute Command ${cmd}
341
342 # Convert output to integer values.
343 ${speeds}= Evaluate map(int, $stdout.split(${\n}))
344 Rpvars speeds
345 # Count the number of speeds > ${min_speed}.
346 ${count}= Set Variable ${0}
347 :FOR ${speed} IN @{speeds}
348 \ ${count}= Run Keyword If ${speed} > ${min_speed}
349 ... Evaluate ${count}+1 ELSE Set Variable ${count}
350 # Because each fan has two rotating fan blades, the count should be
351 # equual to 2*${number_of_fans}. On water-cooled systems some
352 # speeds may be reported by hwmon as 0. That is expected,
353 # and the number_of_fans reported in the system will be less.
354 ${fail_test}= Evaluate (2*${number_of_fans})-${count}
355
356 # Re-enable the fan daemon
357 Set Fan Daemon State restart
358
359 Run Keyword If ${fail_test} > ${0} Fail
360 ... msg=hwmon did not properly report fan speeds.
361
362 # Wait for the daemon to take control and gracefully set fan speeds
363 # back to normal.
364 ${msg}= Catenate Waiting ${minutes_to_stabilize} minutes
365 ... for fan daemon to stabilize fans.
366 Print Timen ${msg}
367 Run Key U Sleep \ ${minutes_to_stabilize}m
368
369
370Verify Fan Speed Increase
371 [Documentation] Verify that the speed of working fans increase when
372 ... one fan is marked as disabled.
373 # A non-functional fan should cause an error log and
374 # an enclosure LED will light. The other fans should speed up.
375 [Arguments] ${fan_names}
376
377 # Description of argument(s):
378 # fan_names A list containing the names of the fans (e.g. fan0 fan1).
379
380 # Allow system_response_time before checking if there was a
381 # response by the system to an applied fault.
382 ${system_response_time}= Set Variable 60s
383
384 # Choose a fan to test with, e.g., fan0.
385 ${test_fan_name}= Get From List ${fan_names} 0
386
387 ${initial_speed}= Get Target Speed Of Fans
388 Rpvars test_fan_name initial_speed
389
390 # If initial speed is not already at maximum, set expect_increase.
391 # This flag is used later to determine if speed checking is
392 # to be done or not.
393 ${expect_increase}= Run Keyword If
394 ... ${initial_speed} < ${max_speed}
395 ... Set Variable 1 ELSE Set Variable 0
396
397 Set Fan State ${test_fan_name} ${fan_nonfunctional}
398
399 # Wait for error to be asserted.
400
401 :FOR ${n} IN RANGE 30
402 \ ${front_fault}= Get System LED State front_fault
403 \ ${rear_fault}= Get System LED State rear_fault
404 \ Run Key U Sleep \ 1s
405 \ Exit For Loop If '${front_fault}' == 'On' and '${rear_fault}' == 'On'
406
407 Verify System Error Indication Due To Fans
408
409 # Verify the error log is for test_fan_name.
410 ${elog_entries}= Get Logging Entry List
411 :FOR ${elog_entry} IN @{elog_entries}
412 \ ${elog_entry_callout}= Set Variable ${elog_entry}/callout
413 \ ${endpoint}= Read Attribute ${elog_entry_callout} endpoints
414 \ ${endpoint_name}= Get From List ${endpoint} 0
415 \ Should Contain ${endpoint_name} ${test_fan_name}
416 ... msg=Error log present but not for ${test_fan_name}.
417
418 Run Key U Sleep \ ${system_response_time}
419
420 # A heavily loaded system may have powered-off.
421 ${host_state}= Get Host State
422 Rpvars host_state
423 Run Keyword If 'Running' != '${host_state}' Pass Execution
424 ... msg=System shutdown so skipping remainder of test.
425
426 ${new_fan_speed}= Get Target Speed Of Fans
427 Rpvars expect_increase initial_speed new_fan_speed
428
429 # Fail if current fan speed did not increase past the initial
430 # speed, but do this check only if not at maximum speed to begin with.
431 Run Keyword If
432 ... ${expect_increase} == 1 and ${new_fan_speed} < ${initial_speed}
433 ... Fail msg=Remaining fans did not increase speed with loss of one fan.
434
435
436
437Verify System Shutdown Due To Fans
438 [Documentation] Shut down when not enough fans.
439 [Arguments] ${fan_names}
440
441 # Description of argument(s):
442 # fan_names A list containing the names of the fans (e.g. fan0 fan1).
443
444 ${wait_after_poweroff}= Set Variable 15s
445
446 # A previous test may have shutdown the system.
447 REST Power On stack_mode=skip
448
449 # Set fans to be non-functional.
450 :FOR ${fan_name} IN @{fan_names}
451 \ Set Fan State ${fan_name} ${fan_nonfunctional}
452
453 # System should notice the non-functional fans and power-off.
454 # The Wait For PowerOff keyword will time-out and report
455 # an error if power off does not happen within a reasonable time.
456 Wait For PowerOff
457
458 Run Key U Sleep \ ${wait_after_poweroff}
459
460 Verify System Error Indication Due To Fans
461
462 # Verify there is an error log because of the shutdown.
463 ${expect}= Catenate
464 ... xyz.openbmc_project.State.Shutdown.Inventory.Error.Fan
465 ${elog_entries}= Get Logging Entry List
466 :FOR ${elog_entry} IN @{elog_entries}
467 \ ${elog_message}= Read Attribute ${elog_entry} Message
468 \ ${found}= Set Variable 1
469 \ Run Keyword If '${elog_message}' == '${expect}' Exit For Loop
470 \ ${found}= Set Variable 0
471 Run Keyword If not ${found} Fail
472 ... msg=No error log for event Shutdown.Inventory.Error.Fan.