| #!/bin/bash |
| # |
| # Power Control tool |
| # Enable/disable AC relay |
| # On/off System by step moter to press power key |
| |
| export PATH=$PATH:/usr/sbin:/usr/libexec |
| |
| # shellcheck source=meta-facebook/meta-bletchley/recipes-bletchley/plat-tools/files/bletchley-common-functions |
| source /usr/libexec/bletchley-common-functions |
| |
| DELAY_POWER_ON="0.5" |
| DELAY_POWER_OFF="5" |
| DELAY_POWER_RECOVERY_MODE="10" |
| POWER_BTN_TIMEOUT_CNT=60 |
| |
| REV_EVT="EVT" |
| REV_DVT="DVT" |
| REV_UNKNOW="UNKNOW" |
| |
| DBUS_HOST_ST_ON="xyz.openbmc_project.State.Host.HostState.Running" |
| DBUS_HOST_ST_OFF="xyz.openbmc_project.State.Host.HostState.Off" |
| |
| HOST_ST_UNKNOW="Unknow" |
| HOST_ST_ON="On" |
| HOST_ST_OFF="Off" |
| HOST_ST_SLEEP="Sleep" |
| HOST_ST_DFU="DFU" |
| HOST_ST_RECOVERY="Recovery" |
| HOST_AC_ON="AC On" |
| HOST_AC_OFF="AC Off" |
| |
| ACTION_ON="on" |
| ACTION_OFF="off" |
| ACTION_DFU="dfu" |
| ACTION_RECOVERY="recovery" |
| ACTION_CYCLE="cycle" |
| ACTION_RESET="reset" |
| ACTION_AC_ON="ac-on" |
| ACTION_AC_OFF="ac-off" |
| ACTION_STATUS="status" |
| |
| VALID_SLED_ACTIONS=" |
| $ACTION_ON |
| $ACTION_OFF |
| $ACTION_AC_ON |
| $ACTION_AC_OFF |
| $ACTION_STATUS |
| $ACTION_DFU |
| $ACTION_RECOVERY |
| $ACTION_CYCLE |
| $ACTION_RESET |
| " |
| |
| function is_valid_sled_action() |
| { |
| local ACTION=$1 |
| for i in $VALID_SLED_ACTIONS |
| do |
| if [ "$i" = "$ACTION" ]; then |
| return 0 |
| fi |
| done |
| return 1 |
| } |
| |
| function get_board_rev() |
| { |
| local rev_id0 |
| local rev_id1 |
| local rev_id2 |
| local rev_val |
| |
| rev_id0=$(get_gpio "REV_ID0") |
| rev_id1=$(get_gpio "REV_ID1") |
| rev_id2=$(get_gpio "REV_ID2") |
| rev_val=$((rev_id0+(rev_id1<<1)+(rev_id2<<2))) |
| |
| case $rev_val in |
| 0) |
| echo "$REV_EVT" |
| ;; |
| 1) |
| echo "$REV_DVT" |
| ;; |
| *) |
| echo "$REV_UNKNOW" |
| return 1 |
| ;; |
| esac |
| |
| return 0 |
| } |
| |
| #Switch pull low while it be touched |
| function wait_for_switch() |
| { |
| TARGET_PIN=$1 |
| TARGET_SWITCH=1 |
| TIME_CNT=0 |
| while [ "$TARGET_SWITCH" -eq 1 ] ;do |
| TARGET_SWITCH=$(get_gpio "$TARGET_PIN") |
| sleep 0.1 |
| TIME_CNT=$(( TIME_CNT +1)) |
| if [ $TIME_CNT -gt $POWER_BTN_TIMEOUT_CNT ];then |
| echo "Error: Too long to get target switch, force exit" >&2 |
| break |
| fi |
| done |
| } |
| |
| function trigger_power_button() |
| { |
| local sled_num=$1 |
| local delay_time=$2 |
| |
| #SLED{N}_MS_DETECT1 (initial position) |
| GPIO_DETECT_PIN1="SLED${sled_num}_MS_DETECT1" |
| #SLED{N}_MS_DETECT0 (MAC position) |
| GPIO_DETECT_PIN0="SLED${sled_num}_MS_DETECT0" |
| |
| echo "Motor go forward to press Power key" |
| motor-ctrl "sled${sled_num}" f >/dev/null |
| wait_for_switch "${GPIO_DETECT_PIN0}" |
| motor-ctrl "sled${sled_num}" s >/dev/null |
| |
| if [ "$(get_gpio "$GPIO_DETECT_PIN0")" -eq 0 ];then |
| echo "Power key switch triggered" |
| echo "Press power key for Sled${1} ${delay_time} seconds..." |
| sleep "$delay_time" |
| else |
| echo "Power key switch not trigger, back motor to initial position" |
| fi |
| |
| motor-ctrl "sled${sled_num}" r >/dev/null |
| wait_for_switch "${GPIO_DETECT_PIN1}" |
| motor-ctrl "sled${sled_num}" s >/dev/null |
| if [ "$(get_gpio "$GPIO_DETECT_PIN1")" -eq 0 ];then |
| echo "Motor reverse to initial position successful" |
| else |
| echo "Initial position switch not trigger, force stop motor" |
| fi |
| } |
| |
| function release_power_button() |
| { |
| local sled_num=$1 |
| GPIO_DETECT_PIN1="SLED${sled_num}_MS_DETECT1" |
| |
| if [ "$(get_gpio "$GPIO_DETECT_PIN1")" -eq 0 ]; then |
| echo "Motor at initial position already" |
| return 0 |
| fi |
| |
| motor-ctrl "sled${sled_num}" r >/dev/null |
| wait_for_switch "${GPIO_DETECT_PIN1}" |
| motor-ctrl "sled${sled_num}" s >/dev/null |
| if [ "$(get_gpio "$GPIO_DETECT_PIN1")" -eq 0 ];then |
| echo "Motor reverse to initial position successful" |
| return 0 |
| fi |
| |
| echo "Error: Initial position switch not trigger" |
| return 1 |
| } |
| |
| function press_power_button() |
| { |
| local sled_num=$1 |
| |
| GPIO_DETECT_PIN0="SLED${sled_num}_MS_DETECT0" |
| |
| echo "Motor go forward to press Power button" |
| motor-ctrl "sled${sled_num}" f >/dev/null |
| wait_for_switch "${GPIO_DETECT_PIN0}" |
| motor-ctrl "sled${sled_num}" s >/dev/null |
| |
| if [ "$(get_gpio "$GPIO_DETECT_PIN0")" -eq 0 ];then |
| echo "Power button switch triggered" |
| return 0 |
| fi |
| |
| echo "Error: Power button switch not trigger" |
| return 1 |
| } |
| |
| #Get i2c bus number for sledN |
| function get_bus_num() |
| { |
| SLED_NUM=$1 |
| local bus=0 |
| #Mapping Sled number 1~6 to i2c bus number 0~5 |
| if [[ "$SLED_NUM" = [1-6] ]]; then |
| bus=$(( SLED_NUM - 1 )) |
| fi |
| echo "$bus" |
| } |
| |
| function get_ac_status() |
| { |
| i2c_bus=$(get_bus_num "$1") |
| p1_output_reg=$(i2cget -f -y "$i2c_bus" 0x76 0x03) |
| p1_config_reg=$(i2cget -f -y "$i2c_bus" 0x76 0x07) |
| host_pwr="$(( (p1_output_reg & 0x80)>>7 ))" |
| is_output="$(( (~p1_config_reg & 0x80)>>7 ))" |
| |
| if [ "$(( host_pwr & is_output ))" -eq 1 ];then |
| echo "$HOST_AC_ON" |
| else |
| echo "$HOST_AC_OFF" |
| fi |
| } |
| |
| function get_host_status_dbus() |
| { |
| local sled_num=$1 |
| local object="/xyz/openbmc_project/state/host${sled_num}" |
| local service="xyz.openbmc_project.State.Host${sled_num}" |
| local interface="xyz.openbmc_project.State.Host" |
| local property="CurrentHostState" |
| local host_state |
| |
| host_state=$(busctl get-property "$service" "$object" "$interface" "$property" | cut -d '"' -f2) |
| |
| if [ "$host_state" = "$DBUS_HOST_ST_ON" ]; then |
| echo "$HOST_ST_ON" |
| elif [ "$host_state" = "$DBUS_HOST_ST_OFF" ]; then |
| echo "$HOST_ST_OFF" |
| else |
| echo "$HOST_ST_UNKNOW" |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| function get_host_status_mdio() |
| { |
| local SLED_NUM=$1 |
| local MDIO_BUS=0 |
| |
| declare -a PORT_MAP=(0 3 2 1 7 6 5) |
| |
| # check /dev/mem |
| if ! create_dev_mem; then |
| return 1 |
| fi |
| |
| local CHECK_CNT=0 |
| local MDIO_ERR_CNT=0 |
| local CUR_HOST_ST=$HOST_ST_UNKNOW |
| local SLED_LAST_ACTION |
| |
| if [ -f /tmp/sled"${SLED_NUM}"-last-action ]; then |
| SLED_LAST_ACTION=$(cat /tmp/sled"${SLED_NUM}"-last-action) |
| fi |
| |
| while true |
| do |
| if POST_ST_VAL=$(mdio-util c22 r $MDIO_BUS "${PORT_MAP[SLED_NUM]}" 0); then |
| if [ $((POST_ST_VAL&16#0800)) -eq $((16#0000)) ]; then |
| case $SLED_LAST_ACTION in |
| "$ACTION_DFU") |
| TMP_HOST_ST="$HOST_ST_DFU" |
| ;; |
| *) |
| TMP_HOST_ST="$HOST_ST_OFF" |
| ;; |
| esac |
| elif [ $((POST_ST_VAL&16#0A00)) -eq $((16#0A00)) ]; then |
| TMP_HOST_ST="$HOST_ST_ON" |
| case $SLED_LAST_ACTION in |
| "$ACTION_RECOVERY") |
| TMP_HOST_ST="$HOST_ST_RECOVERY" |
| ;; |
| *) |
| TMP_HOST_ST="$HOST_ST_ON" |
| ;; |
| esac |
| elif [ $((POST_ST_VAL&16#0900)) -eq $((16#0900)) ]; then |
| TMP_HOST_ST="$HOST_ST_SLEEP" |
| else |
| TMP_HOST_ST="$HOST_ST_UNKNOW" |
| fi |
| |
| if [ "$CUR_HOST_ST" == "$TMP_HOST_ST" ]; then |
| CHECK_CNT=$((CHECK_CNT+1)) |
| else |
| CUR_HOST_ST=$TMP_HOST_ST |
| CHECK_CNT=0 |
| fi |
| |
| if [ "$CHECK_CNT" -ge 5 ]; then |
| echo "$CUR_HOST_ST" |
| break |
| fi |
| else |
| MDIO_ERR_CNT=$((MDIO_ERR_CNT+1)) |
| if [ "$MDIO_ERR_CNT" -ge 5 ]; then |
| echo "$HOST_ST_UNKNOW" |
| return 1 |
| fi |
| fi |
| done |
| |
| return 0 |
| } |
| |
| function get_host_status() |
| { |
| local sled_num=$1 |
| |
| if [ "$(get_ac_status "$SLED_NUM")" == "$HOST_AC_OFF" ];then |
| echo "$HOST_AC_OFF" |
| return 0 |
| fi |
| |
| if [ "$(get_board_rev)" = "$REV_EVT" ]; then |
| get_host_status_dbus "$sled_num" |
| else |
| get_host_status_mdio "$sled_num" |
| fi |
| return $? |
| } |
| |
| function do_action_reset() |
| { |
| # 1. Power off |
| # 2. Power on |
| |
| local SLED_NUM=$1 |
| local CUR_ST=$2 |
| |
| if [ "$CUR_ST" != "$HOST_ST_OFF" ]; then |
| do_action_off "$SLED_NUM" |
| else |
| echo "sled${SLED_NUM}: already powered off" |
| fi |
| |
| sleep 3 |
| do_action_on "$SLED_NUM" |
| } |
| |
| function do_action_cycle() |
| { |
| # 1. AC off |
| # 2. AC on |
| # 3. Power on |
| |
| local SLED_NUM=$1 |
| |
| do_action_ac_off "$SLED_NUM" |
| sleep 3 |
| do_action_ac_on "$SLED_NUM" |
| sleep 3 |
| do_action_on "$SLED_NUM" |
| } |
| |
| function do_action_ac_on() |
| { |
| local SLED_NUM=$1 |
| echo "sled${SLED_NUM}: turn on AC" |
| set_gpio "power-host${SLED_NUM}" 1 |
| echo "$ACTION_AC_ON" > "/tmp/sled${SLED_NUM}-last-action" |
| } |
| |
| function do_action_ac_off() |
| { |
| local SLED_NUM=$1 |
| echo "sled${SLED_NUM}: turn off AC" |
| set_gpio "power-host${SLED_NUM}" 0 |
| echo "$ACTION_AC_OFF" > "/tmp/sled${SLED_NUM}-last-action" |
| } |
| |
| function do_action_on() |
| { |
| local SLED_NUM=$1 |
| echo "sled${SLED_NUM}: power on host" |
| trigger_power_button "$SLED_NUM" "$DELAY_POWER_ON" |
| echo "$ACTION_ON" > "/tmp/sled${SLED_NUM}-last-action" |
| } |
| |
| function do_action_off() |
| { |
| local SLED_NUM=$1 |
| echo "sled${SLED_NUM}: power off host" |
| trigger_power_button "$SLED_NUM" "$DELAY_POWER_OFF" |
| echo "$ACTION_OFF" > "/tmp/sled${SLED_NUM}-last-action" |
| } |
| |
| function do_action_recovery() |
| { |
| local SLED_NUM=$1 |
| echo "sled${SLED_NUM}: trigger host recovery mode" |
| trigger_power_button "$SLED_NUM" "$DELAY_POWER_RECOVERY_MODE" |
| echo "$ACTION_RECOVERY" > "/tmp/sled${SLED_NUM}-last-action" |
| } |
| |
| function do_action_dfu() |
| { |
| local SLED_NUM=$1 |
| echo "sled${SLED_NUM}: trigger host dfu mode" |
| |
| # turn ac off, and hold for 25 seconds |
| do_action_ac_off "$SLED_NUM" |
| sleep 25 |
| |
| # press power button |
| echo "SLED$SLED_NUM: pressing power button" |
| if ! press_power_button "$SLED_NUM"; then |
| echo "SLED$SLED_NUM: press power button failed" |
| echo "SLED$SLED_NUM: releasing power button" |
| release_power_button "$SLED_NUM" |
| exit 1 |
| fi |
| sleep 1 |
| |
| # turn ac on |
| echo "SLED$SLED_NUM: turn ac-on" |
| do_action_ac_on "$SLED_NUM" |
| sleep 3 |
| |
| # release power button |
| echo "SLED$SLED_NUM: releasing host power button" |
| if ! release_power_button "$SLED_NUM"; then |
| echo "SLED$SLED_NUM: release power button failed" |
| exit 1 |
| fi |
| echo "$ACTION_DFU" > "/tmp/sled${SLED_NUM}-last-action" |
| } |
| |
| function host_state_on_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_OFF") |
| do_action_off "$SLED_NUM" |
| ;; |
| "$ACTION_AC_OFF") |
| do_action_ac_off "$SLED_NUM" |
| ;; |
| "$ACTION_RESET") |
| do_action_reset "$SLED_NUM" "$HOST_ST_ON" |
| ;; |
| "$ACTION_CYCLE") |
| do_action_cycle "$SLED_NUM" |
| ;; |
| *) |
| echo "Invalid action ($ACTION) for current host state (On)" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function host_state_sleep_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_ON") |
| do_action_on "$SLED_NUM" |
| ;; |
| "$ACTION_OFF") |
| do_action_off "$SLED_NUM" |
| ;; |
| "$ACTION_AC_OFF") |
| do_action_ac_off "$SLED_NUM" |
| ;; |
| "$ACTION_RESET") |
| do_action_reset "$SLED_NUM" "$HOST_ST_ON" |
| ;; |
| "$ACTION_CYCLE") |
| do_action_cycle "$SLED_NUM" |
| ;; |
| *) |
| echo "Invalid action ($ACTION) for current host state (Sleep)" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function host_state_off_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_ON") |
| do_action_on "$SLED_NUM" |
| ;; |
| "$ACTION_RECOVERY") |
| do_action_recovery "$SLED_NUM" |
| ;; |
| "$ACTION_AC_OFF") |
| do_action_ac_off "$SLED_NUM" |
| ;; |
| "$ACTION_RESET") |
| do_action_reset "$SLED_NUM" "$HOST_ST_ON" |
| ;; |
| "$ACTION_CYCLE") |
| do_action_cycle "$SLED_NUM" |
| ;; |
| *) |
| echo "Invalid action ($ACTION) for current host state (Off)" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function host_state_ac_off_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_AC_ON") |
| do_action_ac_on "$SLED_NUM" |
| ;; |
| "$ACTION_DFU") |
| do_action_dfu "$SLED_NUM" |
| ;; |
| "$ACTION_AC_OFF") |
| echo "sled${SLED_NUM}: already ac off" |
| return 1 |
| ;; |
| "$ACTION_CYCLE") |
| do_action_reset "$SLED_NUM" |
| ;; |
| *) |
| echo "Invalid action ($ACTION) for current host state (AC Off)" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function host_state_ac_on_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_AC_OFF") |
| do_action_ac_off "$SLED_NUM" |
| ;; |
| "$ACTION_CYCLE") |
| do_action_cycle "$SLED_NUM" |
| ;; |
| *) |
| echo "sled${SLED_NUM}: already ac on" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function host_state_recovery_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_OFF") |
| do_action_off "$SLED_NUM" |
| ;; |
| "$ACTION_AC_OFF") |
| do_action_ac_off "$SLED_NUM" |
| ;; |
| "$ACTION_RESET") |
| do_action_reset "$SLED_NUM" "$HOST_ST_ON" |
| ;; |
| "$ACTION_CYCLE") |
| do_action_cycle "$SLED_NUM" |
| ;; |
| *) |
| echo "Invalid action ($ACTION) for current host state (Recovery)" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function host_state_dfu_action_handler() |
| { |
| local SLED_NUM=$1 |
| local ACTION=$2 |
| |
| case $ACTION in |
| "$ACTION_AC_OFF") |
| do_action_ac_off "$SLED_NUM" |
| ;; |
| "$ACTION_CYCLE") |
| do_action_cycle "$SLED_NUM" |
| ;; |
| *) |
| echo "Invalid action ($ACTION) for current host state (DFU)" |
| return 1 |
| ;; |
| esac |
| } |
| |
| function create_dev_mem() |
| { |
| CHECK_CNT=0 |
| while true |
| do |
| CHECK_CNT=$((CHECK_CNT+1)) |
| if [ -c /dev/mem ]; then |
| # /dev/mem already exist |
| return 0 |
| elif mknod /dev/mem c 1 1; then |
| # mknod success |
| return 0 |
| elif [ "$CHECK_CNT" -ge 5 ]; then |
| break |
| fi |
| sleep 1 |
| done |
| |
| echo "create /dev/mem failed" |
| return 1 |
| } |
| |
| function show_usage(){ |
| echo "Usage: power-ctrl [sled1 | sled2 | sled3 | sled4 | sled5 | sled6] [$VALID_SLED_ACTIONS]" |
| echo " power-ctrl chassis-cycle" |
| } |
| |
| |
| if [ $# -eq 1 ]; then |
| if [ "$1" = "chassis-cycle" ];then |
| echo "chassis cycle...." |
| i2cset -y -f 12 0x11 0xd9 c |
| exit 0 |
| else |
| echo "Invalid argument: [ $1 ]" |
| show_usage |
| exit 1; |
| fi |
| fi |
| |
| if [ $# -gt 2 ]; then |
| echo "Too many arguments" |
| show_usage |
| exit 1; |
| fi |
| |
| if [[ "$1" =~ ^(sled[1-6]{1})$ ]]; then |
| SLED=$1 |
| ACTION=$2 |
| SLED_NUM=${SLED:4} |
| else |
| echo "invalid sled name: ${1}" |
| show_usage |
| exit 1; |
| fi |
| |
| #Check if sled is present |
| if ! is_sled_present "${SLED_NUM}"; then |
| echo "${SLED} is not present!" |
| exit 1 |
| elif ! is_valid_sled_action "$ACTION"; then |
| echo "Unknown action: $ACTION" |
| show_usage |
| exit 1 |
| fi |
| |
| if [ "$ACTION" = "$ACTION_AC_ON" ]; then |
| if [ "$(get_ac_status "$SLED_NUM")" = "$HOST_AC_OFF" ]; then |
| do_action_ac_on "$SLED_NUM" |
| fi |
| elif [ "$ACTION" = "$ACTION_AC_OFF" ]; then |
| if [ "$(get_ac_status "$SLED_NUM")" != "$HOST_AC_OFF" ]; then |
| do_action_ac_off "$SLED_NUM" |
| fi |
| elif [ "$ACTION" = "$ACTION_STATUS" ];then |
| HOST_CURR_STATUS=$(get_host_status "$SLED_NUM") |
| echo "$HOST_CURR_STATUS" |
| else |
| HOST_CURR_STATUS=$(get_host_status "$SLED_NUM") |
| case $HOST_CURR_STATUS in |
| "$HOST_AC_OFF") |
| host_state_ac_off_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| "$HOST_AC_ON") |
| host_state_ac_on_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| "$HOST_ST_OFF") |
| host_state_off_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| "$HOST_ST_ON") |
| host_state_on_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| "$HOST_ST_SLEEP") |
| host_state_sleep_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| "$HOST_ST_DFU") |
| host_state_dfu_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| "$HOST_ST_RECOVERY") |
| host_state_recovery_action_handler "$SLED_NUM" "$ACTION" |
| ;; |
| esac |
| fi |