meta-facebook: minerva: add service to monitor fan status

Minerva rack has six fan control boards (FCB) and each has four fan
modules, CMM should monitor each FCB presence and fan sensor status to
control one fan status LED on the CMM front panel.

Change-Id: I7c7eb4043ceefead5fa25c0ffad14b88649d5e81
Signed-off-by: Yang Chen <yang.chen@quantatw.com>
Signed-off-by: Yi-Shum <EasonChen1@quantatw.com>
diff --git a/meta-facebook/meta-minerva/recipes-minerva/plat-svc/files/minerva-fan-status-monitor b/meta-facebook/meta-minerva/recipes-minerva/plat-svc/files/minerva-fan-status-monitor
new file mode 100644
index 0000000..687098c
--- /dev/null
+++ b/meta-facebook/meta-minerva/recipes-minerva/plat-svc/files/minerva-fan-status-monitor
@@ -0,0 +1,97 @@
+#!/bin/bash -e
+
+FAN_STATUS_UNKNOWN="Unknown"
+FAN_STATUS_NORMAL="Normal"
+FAN_STATUS_ABNORMAL="Abnormal"
+
+create_log()
+{
+    local service="xyz.openbmc_project.Logging"
+    local object_path="/xyz/openbmc_project/logging"
+    local interface="xyz.openbmc_project.Logging.Create"
+    local message="Fan status abnormal"
+    local severity="xyz.openbmc_project.Logging.Entry.Level.Error"
+    local arg="CALLOUT_INVENTORY_PATH"
+    local value="/xyz/openbmc_project/inventory/fan"
+
+    busctl call "$service" "$object_path" "$interface" Create "ssa{ss}" "$message" "$severity" 1 "$arg" "$value"
+}
+
+resolve_log()
+{
+    local service="xyz.openbmc_project.ObjectMapper"
+    local object_path="/xyz/openbmc_project/inventory/fan/fault"
+    local interface="xyz.openbmc_project.Association"
+    local property="endpoints"
+
+    mapfile -t -d " " endpoint_array < <(busctl get-property "$service" "$object_path" "$interface" "$property" | tr -d '"\n')
+
+    for ((i = 2; i < ${#endpoint_array[@]}; i++)); do
+        endpoint="${endpoint_array[$i]}"
+        busctl set-property xyz.openbmc_project.Logging "$endpoint" xyz.openbmc_project.Logging.Entry Resolved b true
+    done
+}
+
+check_fcb_fan_status()
+{
+    local fcb_num=$1
+
+    if ! [[ $fcb_num =~ ^[0-5]$ ]]; then
+        echo "$FAN_STATUS_UNKNOWN"
+        return 1
+    fi
+
+    local service="xyz.openbmc_project.FanSensor"
+    local interface="xyz.openbmc_project.Sensor.Threshold.Critical"
+    local property_list=("CriticalAlarmHigh" "CriticalAlarmLow")
+    local fan_name_prefix=("FCB_BOT_0" "FCB_BOT_1" "FCB_MID_0" "FCB_MID_1" "FCB_TOP_0" "FCB_TOP_1")
+    local in_out=("IL" "OL")
+
+    for index in {0..7}
+    do
+        local object_path="/xyz/openbmc_project/sensors/fan_tach/${fan_name_prefix[$fcb_num]}_FAN$((index / 2))_TACH_${in_out[$((index % 2))]}_SPEED_RPM"
+        for property in "${property_list[@]}"; do
+            tach_alarm=$(busctl get-property "$service" "$object_path" "$interface" "$property" | cut -d ' ' -f2)
+            if [ "$tach_alarm" = "true" ]; then
+                echo "$FAN_STATUS_ABNORMAL"
+                return 0
+            fi
+        done
+    done
+
+    echo "$FAN_STATUS_NORMAL"
+    return 0
+}
+
+pre_status=$FAN_STATUS_UNKNOWN
+
+while true
+do
+    fan_status=$FAN_STATUS_NORMAL
+    # Get the FCBs' presence status from the CMM CPLD
+    fcb_prsnt_reg=$(i2cget -f -y 0x00 0x15 0x01)
+
+    for i in {0..5}
+    do
+        # Check the presence of each FCB
+        if (( (fcb_prsnt_reg & (1 << i)) != 0 )); then
+            fan_status=$FAN_STATUS_ABNORMAL
+            break
+        else
+            # Check each sensor on the FCB whether alert critical alarm
+            fan_status=$(check_fcb_fan_status "$i")
+            if [ "$fan_status" = "$FAN_STATUS_ABNORMAL" ]; then
+                break
+            fi
+        fi
+    done
+
+    if [ "$fan_status" = "$FAN_STATUS_ABNORMAL" ] && [ "$pre_status" != "$FAN_STATUS_ABNORMAL" ]; then
+        create_log
+        pre_status="$FAN_STATUS_ABNORMAL"
+    elif [ "$fan_status" = "$FAN_STATUS_NORMAL" ] && [ "$pre_status" != "$FAN_STATUS_NORMAL" ]; then
+        resolve_log
+        pre_status="$FAN_STATUS_NORMAL"
+    fi
+    sleep 1
+done
diff --git a/meta-facebook/meta-minerva/recipes-minerva/plat-svc/files/minerva-fan-status-monitor.service b/meta-facebook/meta-minerva/recipes-minerva/plat-svc/files/minerva-fan-status-monitor.service
new file mode 100644
index 0000000..a62cac2
--- /dev/null
+++ b/meta-facebook/meta-minerva/recipes-minerva/plat-svc/files/minerva-fan-status-monitor.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Minerva Fan Status Monitor
+Wants=xyz.openbmc_project.fansensor.service
+After=xyz.openbmc_project.fansensor.service
+
+[Service]
+ExecStart=/usr/libexec/minerva-fan-status-monitor
+SyslogIdentifier=Minerva Fan Status Monitor
+Type=simple
+Restart=on-failure
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-facebook/meta-minerva/recipes-minerva/plat-svc/plat-svc_0.1.bb b/meta-facebook/meta-minerva/recipes-minerva/plat-svc/plat-svc_0.1.bb
index 57611bb..c60b1f5 100644
--- a/meta-facebook/meta-minerva/recipes-minerva/plat-svc/plat-svc_0.1.bb
+++ b/meta-facebook/meta-minerva/recipes-minerva/plat-svc/plat-svc_0.1.bb
@@ -10,15 +10,19 @@
 SRC_URI += " \
     file://minerva-sys-init.service \
     file://minerva-early-sys-init \
+    file://minerva-fan-status-monitor \
+    file://minerva-fan-status-monitor.service \
     "
 
 SYSTEMD_PACKAGES = "${PN}"
 SYSTEMD_SERVICE:${PN}:append = " \
     minerva-sys-init.service \
+    minerva-fan-status-monitor.service \
     "
 
 do_install() {
     install -d ${D}${libexecdir}
     install -m 0755 ${WORKDIR}/minerva-early-sys-init ${D}${libexecdir}
+    install -m 0755 ${WORKDIR}/minerva-fan-status-monitor ${D}${libexecdir}
 }
 
diff --git a/meta-facebook/meta-minerva/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend b/meta-facebook/meta-minerva/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend
new file mode 100644
index 0000000..2d3b76b
--- /dev/null
+++ b/meta-facebook/meta-minerva/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend
@@ -0,0 +1,9 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI:append = " \
+    file://minerva-fan.yaml \
+"
+
+do_install:append() {
+    cat minerva-fan.yaml >> ${D}${settings_datadir}/defaults.yaml
+}
diff --git a/meta-facebook/meta-minerva/recipes-phosphor/settings/phosphor-settings-defaults-native/minerva-fan.yaml b/meta-facebook/meta-minerva/recipes-phosphor/settings/phosphor-settings-defaults-native/minerva-fan.yaml
new file mode 100644
index 0000000..c9da7d7
--- /dev/null
+++ b/meta-facebook/meta-minerva/recipes-phosphor/settings/phosphor-settings-defaults-native/minerva-fan.yaml
@@ -0,0 +1,5 @@
+/xyz/openbmc_project/inventory/fan:
+- Interface: xyz.openbmc_project.Inventory.Item
+  Properties:
+    PrettyName:
+      Default: '"MINERVA CMM FAN LED"'