| #!/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 |
| |
| DELAY_POWER_ON="0.5" |
| DELAY_POWER_OFF="5" |
| 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_AC_ON="AC On" |
| HOST_AC_OFF="AC Off" |
| |
| 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 set_gpio() |
| { |
| NET_NAME=$1 |
| OUT_VAL=$2 |
| mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME") |
| if [ "${#GPIO_INFO[@]}" -ne 2 ]; then |
| echo "set_gpio: can not find gpio, $NET_NAME" |
| return 1 |
| fi |
| echo -n "set_gpio: set $NET_NAME = $OUT_VAL" |
| if ! gpioset "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}"="$OUT_VAL"; then |
| echo " failed" |
| return 1 |
| fi |
| echo " success" |
| return 0 |
| } |
| |
| function get_gpio() |
| { |
| NET_NAME=$1 |
| RET_VAL=2 |
| |
| mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME") |
| if [ "${#GPIO_INFO[@]}" -ne 2 ]; then |
| echo "get_gpio: can not find gpio, $NET_NAME" >&2 |
| return 1 |
| fi |
| if ! RET_VAL=$(gpioget "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}") ; then |
| echo "get_gpio: get ${NET_NAME} failed" >&2 |
| return 1 |
| fi |
| echo "${RET_VAL}" |
| return 0 |
| } |
| |
| 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() |
| { |
| SLED_NUM=$1 |
| 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 |
| |
| CHECK_CNT=0 |
| MDIO_ERR_CNT=0 |
| CUR_HOST_ST=$HOST_ST_UNKNOW |
| |
| 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#0800)) ]; then |
| TMP_HOST_ST="$HOST_ST_ON" |
| else |
| TMP_HOST_ST="$HOST_ST_OFF" |
| 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 |
| local board_rev |
| |
| board_rev=$(get_board_rev) |
| |
| if [ "$board_rev" = "$REV_EVT" ]; then |
| get_host_status_dbus "$sled_num" |
| else |
| get_host_status_mdio "$sled_num" |
| fi |
| |
| return $? |
| } |
| |
| 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] [on off ac-on ac-off status dfu recovery]" |
| 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 |
| SLED_PRESENT=$(get_gpio "presence-sled${SLED_NUM}") |
| if [ "$SLED_PRESENT" != 0 ];then |
| echo "${SLED} is not present!" |
| exit 1 |
| fi |
| |
| if [[ "$ACTION" == "on" ]]; then |
| if [ "$(get_ac_status "$SLED_NUM")" == "$HOST_AC_ON" ];then |
| host_power_st=$(get_host_status "$SLED_NUM") |
| if [ "$host_power_st" == "$HOST_ST_ON" ]; then |
| echo "${SLED} is already On" |
| elif [ "$host_power_st" == "$HOST_ST_OFF" ]; then |
| echo "Power on ${SLED}" |
| trigger_power_button "$SLED_NUM" "$DELAY_POWER_ON" |
| else |
| echo "${SLED} power state is $host_power_st" |
| exit 1 |
| fi |
| else |
| echo "${SLED} is ac-off, please turn on ac before power on" |
| exit 1 |
| fi |
| elif [[ "$ACTION" == "off" ]];then |
| if [ "$(get_ac_status "$SLED_NUM")" == "$HOST_AC_ON" ];then |
| host_power_st=$(get_host_status "$SLED_NUM") |
| if [ "$host_power_st" == "$HOST_ST_ON" ]; then |
| echo "Power off ${SLED}" |
| trigger_power_button "$SLED_NUM" "$DELAY_POWER_OFF" |
| elif [ "$host_power_st" == "$HOST_ST_OFF" ]; then |
| echo "${SLED} is already Off" |
| else |
| echo "${SLED} power state is $host_power_st" |
| exit 1 |
| fi |
| else |
| echo "${SLED} is already ac-off" |
| exit 1 |
| fi |
| elif [[ "$ACTION" == "status" ]];then |
| AC_ST=$(get_ac_status "$SLED_NUM") |
| if [ "$AC_ST" == "$HOST_AC_ON" ]; then |
| # check host power status if AC is on |
| get_host_status "$SLED_NUM" || exit 1 |
| else |
| # AC off |
| echo "$HOST_AC_OFF" |
| fi |
| elif [[ "$ACTION" == "ac-on" ]];then |
| set_gpio "power-host${SLED_NUM}" 1 |
| elif [[ "$ACTION" == "ac-off" ]];then |
| set_gpio "power-host${SLED_NUM}" 0 |
| elif [[ "$ACTION" == "dfu" ]]; then |
| echo "Set host$SLED_NUM DFU mode" |
| |
| # turn ac off, and hold for 25 seconds |
| echo "SLED$SLED_NUM: turn ac-off" |
| set_gpio "power-host${SLED_NUM}" 0 |
| 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" |
| set_gpio "power-host${SLED_NUM}" 1 |
| 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 |
| elif [[ "$ACTION" == "recovery" ]]; then |
| if [ "$(get_host_status "$SLED_NUM")" != "$HOST_ST_OFF" ]; then |
| echo "Please turn off host before trigger recovery mode" |
| exit 1 |
| fi |
| echo "Set host$SLED_NUM Recovery mode" |
| |
| # 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 10 |
| |
| # 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 |
| else |
| echo "Unknown action: [ ${ACTION} ]" |
| show_usage |
| fi |