1#!/bin/bash
2
3# Define constants
4SERVICE="xyz.openbmc_project.FanSensor"
5FUNCTIONAL_INTERFACE="xyz.openbmc_project.State.Decorator.OperationalStatus"
6AVAILABILITY_INTERFACE="xyz.openbmc_project.State.Decorator.Availability"
7
8# D-Bus paths of fan rotors
9FAN_PATHS=(
10    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN0_TACH_INLET_SPEED_RPM"
11    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN0_TACH_OUTLET_SPEED_RPM"
12    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN1_TACH_INLET_SPEED_RPM"
13    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN1_TACH_OUTLET_SPEED_RPM"
14    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN2_TACH_INLET_SPEED_RPM"
15    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN2_TACH_OUTLET_SPEED_RPM"
16    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN3_TACH_INLET_SPEED_RPM"
17    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN3_TACH_OUTLET_SPEED_RPM"
18    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN4_TACH_INLET_SPEED_RPM"
19    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN4_TACH_OUTLET_SPEED_RPM"
20    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN5_TACH_INLET_SPEED_RPM"
21    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN5_TACH_OUTLET_SPEED_RPM"
22    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN6_TACH_INLET_SPEED_RPM"
23    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN6_TACH_OUTLET_SPEED_RPM"
24    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN7_TACH_INLET_SPEED_RPM"
25    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN7_TACH_OUTLET_SPEED_RPM"
26    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN8_TACH_INLET_SPEED_RPM"
27    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN8_TACH_OUTLET_SPEED_RPM"
28    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN9_TACH_INLET_SPEED_RPM"
29    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD0_FAN9_TACH_OUTLET_SPEED_RPM"
30    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN10_TACH_INLET_SPEED_RPM"
31    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN10_TACH_OUTLET_SPEED_RPM"
32    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN11_TACH_INLET_SPEED_RPM"
33    "/xyz/openbmc_project/sensors/fan_tach/FANBOARD1_FAN11_TACH_OUTLET_SPEED_RPM"
34)
35
36# Add event log
37add_sel()
38{
39  MESSAGE="$*"
40
41  busctl call \
42    xyz.openbmc_project.Logging /xyz/openbmc_project/logging \
43    xyz.openbmc_project.Logging.Create Create "ssa{ss}" "$MESSAGE" \
44    xyz.openbmc_project.Logging.Entry.Level.Error 0 >/dev/null 2>&1
45}
46
47# Check normal fans
48check_normal_fans() {
49    local normal_count=0
50    for path in "${FAN_PATHS[@]}"; do
51        # Get properties with error handling
52        functional=$(busctl get-property "$SERVICE" "$path" "$FUNCTIONAL_INTERFACE" Functional 2>/dev/null | awk '{print $2}')
53        available=$(busctl get-property "$SERVICE" "$path" "$AVAILABILITY_INTERFACE" Available 2>/dev/null | awk '{print $2}')
54
55        # Check if properties were fetched successfully
56        if [[ -z "$functional" || -z "$available" ]]; then
57            continue
58        fi
59
60        # Check for normal fan
61        if [[ "$functional" == "true" && "$available" == "true" ]]; then
62            normal_count=$((normal_count + 1))
63        fi
64    done
65    echo $normal_count
66}
67
68# Restart fan sensor service
69reload_fan_sensors() {
70    echo "Reloading fan sensors..."
71    if systemctl restart xyz.openbmc_project.fansensor; then
72        echo "Fan sensors reloaded successfully."
73    else
74        echo "Failed to reload fan sensors." >&2
75    fi
76    sleep 30  # Wait for the service to stabilize
77}
78
79# Power off a single slot
80power_off_slot(){
81    local slot_number=$1
82    local object_path="/xyz/openbmc_project/state/chassis${slot_number}"
83    local service_name="xyz.openbmc_project.State.Chassis${slot_number}"
84    local interface="xyz.openbmc_project.State.Chassis"
85    local property="RequestedPowerTransition"
86    local value="xyz.openbmc_project.State.Chassis.Transition.Off"
87    local ret=0
88
89    echo "AC Powering off slot $slot_number..."
90
91    busctl set-property "$service_name" "$object_path" "$interface" "$property" s "$value"
92    ret=$?
93
94    if [ $ret -eq 0 ]; then
95        echo "Slot $slot_number powered off successfully."
96    else
97        echo "Failed to power off slot $slot_number." >&2
98        return $ret
99    fi
100}
101
102# Power off all slots
103power_off_all_slots() {
104    # Log the event before shutting down
105    local msg=""
106
107    msg="Hosts 1 to 8 are being shut down due to the missing of more than 2 fan rotors."
108    echo "${msg}"
109    add_sel "${msg}"
110
111    for slot in {1..8}; do
112        power_off_slot "$slot"
113    done
114}
115
116# Main logic
117main() {
118	local normal_count=24
119	local normal_rototr_threashold=22
120    # Initial check
121    normal_count=$(check_normal_fans)
122    echo "Initial normal fan count: $normal_count"
123
124    if (( normal_count < normal_rototr_threashold )); then
125        echo "Normal fan count below threshold. Attempting recovery..."
126        normal_count=24
127        reload_fan_sensors
128
129        # Recheck after recovery
130        normal_count=$(check_normal_fans)
131        echo "Post-recovery normal fan count: $normal_count"
132
133        if (( normal_count < normal_rototr_threashold )); then
134            echo "Still > 2 rotors missing after reload the fan sensors. Initiating shutdown."
135            power_off_all_slots
136        else
137            echo "Recovery successful. System is stable."
138        fi
139    else
140        echo "System is stable. No action required."
141    fi
142}
143
144main
145