[device/celestica] Implement Watchdog APIs based on the new platform API (#3123)
This commit is contained in:
parent
8329ce1d63
commit
bd672000ab
@ -20,12 +20,15 @@ try:
|
|||||||
from sonic_platform.psu import Psu
|
from sonic_platform.psu import Psu
|
||||||
from sonic_platform.device import Device
|
from sonic_platform.device import Device
|
||||||
from sonic_platform.component import Component
|
from sonic_platform.component import Component
|
||||||
|
from sonic_platform.watchdog import Watchdog
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError(str(e) + "- required module not found")
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
|
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
|
||||||
NUM_FAN = 3
|
NUM_FAN = 3
|
||||||
NUM_PSU = 2
|
NUM_PSU = 2
|
||||||
|
RESET_REGISTER = "0x112"
|
||||||
|
REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt"
|
||||||
|
|
||||||
|
|
||||||
class Chassis(ChassisBase):
|
class Chassis(ChassisBase):
|
||||||
@ -42,6 +45,7 @@ class Chassis(ChassisBase):
|
|||||||
ChassisBase.__init__(self)
|
ChassisBase.__init__(self)
|
||||||
self._component_device = Device("component")
|
self._component_device = Device("component")
|
||||||
self._component_name_list = self._component_device.get_name_list()
|
self._component_name_list = self._component_device.get_name_list()
|
||||||
|
self._watchdog = Watchdog()
|
||||||
|
|
||||||
def __read_config_db(self):
|
def __read_config_db(self):
|
||||||
try:
|
try:
|
||||||
@ -51,6 +55,14 @@ class Chassis(ChassisBase):
|
|||||||
except IOError:
|
except IOError:
|
||||||
raise IOError("Unable to open config_db file !")
|
raise IOError("Unable to open config_db file !")
|
||||||
|
|
||||||
|
def __read_txt_file(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as fd:
|
||||||
|
data = fd.read()
|
||||||
|
return data.strip()
|
||||||
|
except IOError:
|
||||||
|
raise IOError("Unable to open %s file !" % file_path)
|
||||||
|
|
||||||
def get_base_mac(self):
|
def get_base_mac(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the base MAC address for the chassis
|
Retrieves the base MAC address for the chassis
|
||||||
@ -63,7 +75,7 @@ class Chassis(ChassisBase):
|
|||||||
base_mac = self.config_data["DEVICE_METADATA"]["localhost"]["mac"]
|
base_mac = self.config_data["DEVICE_METADATA"]["localhost"]["mac"]
|
||||||
return str(base_mac)
|
return str(base_mac)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise KeyError("Base MAC not found")
|
return str(None)
|
||||||
|
|
||||||
def get_firmware_version(self, component_name):
|
def get_firmware_version(self, component_name):
|
||||||
"""
|
"""
|
||||||
@ -94,3 +106,32 @@ class Chassis(ChassisBase):
|
|||||||
if component_name not in self._component_name_list:
|
if component_name not in self._component_name_list:
|
||||||
return False
|
return False
|
||||||
return self.component.upgrade_firmware(image_path)
|
return self.component.upgrade_firmware(image_path)
|
||||||
|
|
||||||
|
def get_reboot_cause(self):
|
||||||
|
"""
|
||||||
|
Retrieves the cause of the previous reboot
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A tuple (string, string) where the first element is a string
|
||||||
|
containing the cause of the previous reboot. This string must be
|
||||||
|
one of the predefined strings in this class. If the first string
|
||||||
|
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||||
|
to pass a description of the reboot cause.
|
||||||
|
"""
|
||||||
|
self.component = Component("SMC_CPLD")
|
||||||
|
description = 'None'
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
|
||||||
|
hw_reboot_cause = self.component.get_register_value(RESET_REGISTER)
|
||||||
|
sw_reboot_cause = self.__read_txt_file(REBOOT_CAUSE_PATH)
|
||||||
|
|
||||||
|
if sw_reboot_cause != "Unexpected reboot":
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
|
||||||
|
elif hw_reboot_cause == "0x11":
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_POWER_LOSS
|
||||||
|
elif hw_reboot_cause == "0x33" or hw_reboot_cause == "0x55":
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_WATCHDOG
|
||||||
|
else:
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
|
||||||
|
description = 'Unknown reason'
|
||||||
|
|
||||||
|
return (reboot_cause, description)
|
||||||
|
@ -23,7 +23,7 @@ MMC_CPLD_ADDR = '0x100'
|
|||||||
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||||
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
|
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
|
||||||
SMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/version"
|
SMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/version"
|
||||||
MMC_CPLD_PATH = "/sys/devices/platform/e1031.smc/getreg"
|
GETREG_PATH = "/sys/devices/platform/e1031.smc/getreg"
|
||||||
|
|
||||||
|
|
||||||
class Component(DeviceBase):
|
class Component(DeviceBase):
|
||||||
@ -51,16 +51,6 @@ class Component(DeviceBase):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __get_register_value(self, path, register):
|
|
||||||
# Retrieves the cpld register value
|
|
||||||
cmd = "echo {1} > {0}; cat {0}".format(path, register)
|
|
||||||
p = subprocess.Popen(
|
|
||||||
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
raw_data, err = p.communicate()
|
|
||||||
if err is not '':
|
|
||||||
return None
|
|
||||||
return raw_data.strip()
|
|
||||||
|
|
||||||
def __get_bios_version(self):
|
def __get_bios_version(self):
|
||||||
# Retrieves the BIOS firmware version
|
# Retrieves the BIOS firmware version
|
||||||
try:
|
try:
|
||||||
@ -70,6 +60,16 @@ class Component(DeviceBase):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_register_value(self, register):
|
||||||
|
# Retrieves the cpld register value
|
||||||
|
cmd = "echo {1} > {0}; cat {0}".format(GETREG_PATH, register)
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err is not '':
|
||||||
|
return None
|
||||||
|
return raw_data.strip()
|
||||||
|
|
||||||
def __get_cpld_version(self):
|
def __get_cpld_version(self):
|
||||||
# Retrieves the CPLD firmware version
|
# Retrieves the CPLD firmware version
|
||||||
cpld_version = dict()
|
cpld_version = dict()
|
||||||
@ -78,8 +78,7 @@ class Component(DeviceBase):
|
|||||||
smc_cpld_version = 'None' if smc_cpld_version is 'None' else "{}.{}".format(
|
smc_cpld_version = 'None' if smc_cpld_version is 'None' else "{}.{}".format(
|
||||||
int(smc_cpld_version[2], 16), int(smc_cpld_version[3], 16))
|
int(smc_cpld_version[2], 16), int(smc_cpld_version[3], 16))
|
||||||
|
|
||||||
mmc_cpld_version = self.__get_register_value(
|
mmc_cpld_version = self.get_register_value(MMC_CPLD_ADDR)
|
||||||
MMC_CPLD_PATH, MMC_CPLD_ADDR)
|
|
||||||
mmc_cpld_version = 'None' if mmc_cpld_version is 'None' else "{}.{}".format(
|
mmc_cpld_version = 'None' if mmc_cpld_version is 'None' else "{}.{}".format(
|
||||||
int(mmc_cpld_version[2], 16), int(mmc_cpld_version[3], 16))
|
int(mmc_cpld_version[2], 16), int(mmc_cpld_version[3], 16))
|
||||||
|
|
||||||
|
233
device/celestica/x86_64-cel_e1031-r0/sonic_platform/watchdog.py
Normal file
233
device/celestica/x86_64-cel_e1031-r0/sonic_platform/watchdog.py
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Celestica
|
||||||
|
#
|
||||||
|
# Watchdog contains an implementation of SONiC Platform Base API
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
import ctypes
|
||||||
|
import fcntl
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import array
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.watchdog_base import WatchdogBase
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
""" ioctl constants """
|
||||||
|
IO_WRITE = 0x40000000
|
||||||
|
IO_READ = 0x80000000
|
||||||
|
IO_READ_WRITE = 0xC0000000
|
||||||
|
IO_SIZE_INT = 0x00040000
|
||||||
|
IO_SIZE_40 = 0x00280000
|
||||||
|
IO_TYPE_WATCHDOG = ord('W') << 8
|
||||||
|
|
||||||
|
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG
|
||||||
|
WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG
|
||||||
|
WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG
|
||||||
|
|
||||||
|
""" Watchdog ioctl commands """
|
||||||
|
WDIOC_GETSUPPORT = 0 | WDR_40
|
||||||
|
WDIOC_GETSTATUS = 1 | WDR_INT
|
||||||
|
WDIOC_GETBOOTSTATUS = 2 | WDR_INT
|
||||||
|
WDIOC_GETTEMP = 3 | WDR_INT
|
||||||
|
WDIOC_SETOPTIONS = 4 | WDR_INT
|
||||||
|
WDIOC_KEEPALIVE = 5 | WDR_INT
|
||||||
|
WDIOC_SETTIMEOUT = 6 | WDWR_INT
|
||||||
|
WDIOC_GETTIMEOUT = 7 | WDR_INT
|
||||||
|
WDIOC_SETPRETIMEOUT = 8 | WDWR_INT
|
||||||
|
WDIOC_GETPRETIMEOUT = 9 | WDR_INT
|
||||||
|
WDIOC_GETTIMELEFT = 10 | WDR_INT
|
||||||
|
|
||||||
|
""" Watchdog status constants """
|
||||||
|
WDIOS_DISABLECARD = 0x0001
|
||||||
|
WDIOS_ENABLECARD = 0x0002
|
||||||
|
|
||||||
|
WDT_COMMON_ERROR = -1
|
||||||
|
WD_MAIN_IDENTITY = "iTCO_wdt"
|
||||||
|
WDT_SYSFS_PATH = "/sys/class/watchdog/"
|
||||||
|
|
||||||
|
|
||||||
|
class Watchdog(WatchdogBase):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.watchdog, self.wdt_main_dev_name = self._get_wdt()
|
||||||
|
self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name
|
||||||
|
self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name
|
||||||
|
self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name
|
||||||
|
# Set default value
|
||||||
|
self._disable()
|
||||||
|
self.armed = False
|
||||||
|
self.timeout = self._gettimeout(self.timeout_path)
|
||||||
|
|
||||||
|
def _is_wd_main(self, dev):
|
||||||
|
"""
|
||||||
|
Checks watchdog identity
|
||||||
|
"""
|
||||||
|
identity = self._read_file(
|
||||||
|
"{}/{}/identity".format(WDT_SYSFS_PATH, dev))
|
||||||
|
return identity == WD_MAIN_IDENTITY
|
||||||
|
|
||||||
|
def _get_wdt(self):
|
||||||
|
"""
|
||||||
|
Retrieves watchdog device
|
||||||
|
"""
|
||||||
|
wdt_main_dev_list = [dev for dev in os.listdir(
|
||||||
|
"/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)]
|
||||||
|
if not wdt_main_dev_list:
|
||||||
|
return None
|
||||||
|
wdt_main_dev_name = wdt_main_dev_list[0]
|
||||||
|
watchdog_device_path = "/dev/{}".format(wdt_main_dev_name)
|
||||||
|
watchdog = os.open(watchdog_device_path, os.O_RDWR)
|
||||||
|
return watchdog, wdt_main_dev_name
|
||||||
|
|
||||||
|
def _read_file(self, file_path):
|
||||||
|
"""
|
||||||
|
Read text file
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(file_path, "r") as fd:
|
||||||
|
txt = fd.read()
|
||||||
|
except IOError:
|
||||||
|
return WDT_COMMON_ERROR
|
||||||
|
return txt.strip()
|
||||||
|
|
||||||
|
def _enable(self):
|
||||||
|
"""
|
||||||
|
Turn on the watchdog timer
|
||||||
|
"""
|
||||||
|
req = array.array('h', [WDIOS_ENABLECARD])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
|
||||||
|
|
||||||
|
def _disable(self):
|
||||||
|
"""
|
||||||
|
Turn off the watchdog timer
|
||||||
|
"""
|
||||||
|
req = array.array('h', [WDIOS_DISABLECARD])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
|
||||||
|
|
||||||
|
def _keepalive(self):
|
||||||
|
"""
|
||||||
|
Keep alive watchdog timer
|
||||||
|
"""
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE)
|
||||||
|
|
||||||
|
def _settimeout(self, seconds):
|
||||||
|
"""
|
||||||
|
Set watchdog timer timeout
|
||||||
|
@param seconds - timeout in seconds
|
||||||
|
@return is the actual set timeout
|
||||||
|
"""
|
||||||
|
req = array.array('I', [seconds])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True)
|
||||||
|
return int(req[0])
|
||||||
|
|
||||||
|
def _gettimeout(self, timeout_path):
|
||||||
|
"""
|
||||||
|
Get watchdog timeout
|
||||||
|
@return watchdog timeout
|
||||||
|
"""
|
||||||
|
req = array.array('I', [0])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True)
|
||||||
|
|
||||||
|
return int(req[0])
|
||||||
|
|
||||||
|
def _gettimeleft(self):
|
||||||
|
"""
|
||||||
|
Get time left before watchdog timer expires
|
||||||
|
@return time left in seconds
|
||||||
|
"""
|
||||||
|
req = array.array('I', [0])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True)
|
||||||
|
|
||||||
|
return int(req[0])
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
def arm(self, seconds):
|
||||||
|
"""
|
||||||
|
Arm the hardware watchdog with a timeout of <seconds> seconds.
|
||||||
|
If the watchdog is currently armed, calling this function will
|
||||||
|
simply reset the timer to the provided value. If the underlying
|
||||||
|
hardware does not support the value provided in <seconds>, this
|
||||||
|
method should arm the watchdog with the *next greater* available
|
||||||
|
value.
|
||||||
|
Returns:
|
||||||
|
An integer specifying the *actual* number of seconds the watchdog
|
||||||
|
was armed with. On failure returns -1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ret = WDT_COMMON_ERROR
|
||||||
|
if seconds < 0:
|
||||||
|
return ret
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.timeout != seconds:
|
||||||
|
self.timeout = self._settimeout(seconds)
|
||||||
|
if self.armed:
|
||||||
|
self._keepalive()
|
||||||
|
else:
|
||||||
|
self._enable()
|
||||||
|
self.armed = True
|
||||||
|
ret = self.timeout
|
||||||
|
except IOError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def disarm(self):
|
||||||
|
"""
|
||||||
|
Disarm the hardware watchdog
|
||||||
|
Returns:
|
||||||
|
A boolean, True if watchdog is disarmed successfully, False if not
|
||||||
|
"""
|
||||||
|
disarmed = False
|
||||||
|
if self.is_armed():
|
||||||
|
try:
|
||||||
|
self._disable()
|
||||||
|
self.armed = False
|
||||||
|
disarmed = True
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return disarmed
|
||||||
|
|
||||||
|
def is_armed(self):
|
||||||
|
"""
|
||||||
|
Retrieves the armed state of the hardware watchdog.
|
||||||
|
Returns:
|
||||||
|
A boolean, True if watchdog is armed, False if not
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.armed
|
||||||
|
|
||||||
|
def get_remaining_time(self):
|
||||||
|
"""
|
||||||
|
If the watchdog is armed, retrieve the number of seconds remaining on
|
||||||
|
the watchdog timer
|
||||||
|
Returns:
|
||||||
|
An integer specifying the number of seconds remaining on thei
|
||||||
|
watchdog timer. If the watchdog is not armed, returns -1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
timeleft = WDT_COMMON_ERROR
|
||||||
|
|
||||||
|
if self.armed:
|
||||||
|
try:
|
||||||
|
timeleft = self._gettimeleft()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return timeleft
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""
|
||||||
|
Close watchdog
|
||||||
|
"""
|
||||||
|
|
||||||
|
os.close(self.watchdog)
|
@ -20,12 +20,15 @@ try:
|
|||||||
from sonic_platform.psu import Psu
|
from sonic_platform.psu import Psu
|
||||||
from sonic_platform.device import Device
|
from sonic_platform.device import Device
|
||||||
from sonic_platform.component import Component
|
from sonic_platform.component import Component
|
||||||
|
from sonic_platform.watchdog import Watchdog
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError(str(e) + "- required module not found")
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
|
CONFIG_DB_PATH = "/etc/sonic/config_db.json"
|
||||||
NUM_FAN = 5
|
NUM_FAN = 5
|
||||||
NUM_PSU = 2
|
NUM_PSU = 2
|
||||||
|
RESET_REGISTER = "0x103"
|
||||||
|
REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt"
|
||||||
|
|
||||||
|
|
||||||
class Chassis(ChassisBase):
|
class Chassis(ChassisBase):
|
||||||
@ -42,6 +45,7 @@ class Chassis(ChassisBase):
|
|||||||
ChassisBase.__init__(self)
|
ChassisBase.__init__(self)
|
||||||
self._component_device = Device("component")
|
self._component_device = Device("component")
|
||||||
self._component_name_list = self._component_device.get_name_list()
|
self._component_name_list = self._component_device.get_name_list()
|
||||||
|
self._watchdog = Watchdog()
|
||||||
|
|
||||||
def __read_config_db(self):
|
def __read_config_db(self):
|
||||||
try:
|
try:
|
||||||
@ -51,6 +55,14 @@ class Chassis(ChassisBase):
|
|||||||
except IOError:
|
except IOError:
|
||||||
raise IOError("Unable to open config_db file !")
|
raise IOError("Unable to open config_db file !")
|
||||||
|
|
||||||
|
def __read_txt_file(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as fd:
|
||||||
|
data = fd.read()
|
||||||
|
return data.strip()
|
||||||
|
except IOError:
|
||||||
|
raise IOError("Unable to open %s file !" % file_path)
|
||||||
|
|
||||||
def get_base_mac(self):
|
def get_base_mac(self):
|
||||||
"""
|
"""
|
||||||
Retrieves the base MAC address for the chassis
|
Retrieves the base MAC address for the chassis
|
||||||
@ -63,7 +75,7 @@ class Chassis(ChassisBase):
|
|||||||
base_mac = self.config_data["DEVICE_METADATA"]["localhost"]["mac"]
|
base_mac = self.config_data["DEVICE_METADATA"]["localhost"]["mac"]
|
||||||
return str(base_mac)
|
return str(base_mac)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise KeyError("Base MAC not found")
|
return str(None)
|
||||||
|
|
||||||
def get_firmware_version(self, component_name):
|
def get_firmware_version(self, component_name):
|
||||||
"""
|
"""
|
||||||
@ -94,3 +106,33 @@ class Chassis(ChassisBase):
|
|||||||
if component_name not in self._component_name_list:
|
if component_name not in self._component_name_list:
|
||||||
return False
|
return False
|
||||||
return self.component.upgrade_firmware(image_path)
|
return self.component.upgrade_firmware(image_path)
|
||||||
|
|
||||||
|
def get_reboot_cause(self):
|
||||||
|
"""
|
||||||
|
Retrieves the cause of the previous reboot
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A tuple (string, string) where the first element is a string
|
||||||
|
containing the cause of the previous reboot. This string must be
|
||||||
|
one of the predefined strings in this class. If the first string
|
||||||
|
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||||
|
to pass a description of the reboot cause.
|
||||||
|
"""
|
||||||
|
self.component = Component("CPLD1")
|
||||||
|
description = 'None'
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
|
||||||
|
hw_reboot_cause = self.component.get_register_value(RESET_REGISTER)
|
||||||
|
sw_reboot_cause = self.__read_txt_file(REBOOT_CAUSE_PATH)
|
||||||
|
|
||||||
|
if sw_reboot_cause != "Unexpected reboot":
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE
|
||||||
|
description = sw_reboot_cause
|
||||||
|
elif hw_reboot_cause == "0x11":
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_POWER_LOSS
|
||||||
|
elif hw_reboot_cause == "0x22":
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_WATCHDOG,
|
||||||
|
else:
|
||||||
|
reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER
|
||||||
|
description = 'Unknown reason'
|
||||||
|
|
||||||
|
return (reboot_cause, description)
|
||||||
|
@ -55,16 +55,6 @@ class Component(DeviceBase):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __get_register_value(self, path, register):
|
|
||||||
# Retrieves the cpld register value
|
|
||||||
cmd = "echo {1} > {0}; cat {0}".format(path, register)
|
|
||||||
p = subprocess.Popen(
|
|
||||||
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
raw_data, err = p.communicate()
|
|
||||||
if err is not '':
|
|
||||||
return None
|
|
||||||
return raw_data.strip()
|
|
||||||
|
|
||||||
def __get_bios_version(self):
|
def __get_bios_version(self):
|
||||||
# Retrieves the BIOS firmware version
|
# Retrieves the BIOS firmware version
|
||||||
try:
|
try:
|
||||||
@ -74,14 +64,23 @@ class Component(DeviceBase):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_register_value(self, register):
|
||||||
|
# Retrieves the cpld register value
|
||||||
|
cmd = "echo {1} > {0}; cat {0}".format(GETREG_PATH, register)
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err is not '':
|
||||||
|
return None
|
||||||
|
return raw_data.strip()
|
||||||
|
|
||||||
def __get_cpld_version(self):
|
def __get_cpld_version(self):
|
||||||
# Retrieves the CPLD firmware version
|
# Retrieves the CPLD firmware version
|
||||||
cpld_version = dict()
|
cpld_version = dict()
|
||||||
for cpld_name in CPLD_ADDR_MAPPING:
|
for cpld_name in CPLD_ADDR_MAPPING:
|
||||||
try:
|
try:
|
||||||
cpld_addr = CPLD_ADDR_MAPPING[cpld_name]
|
cpld_addr = CPLD_ADDR_MAPPING[cpld_name]
|
||||||
cpld_version_raw = self.__get_register_value(
|
cpld_version_raw = self.get_register_value(cpld_addr)
|
||||||
GETREG_PATH, cpld_addr)
|
|
||||||
cpld_version_str = "{}.{}".format(int(cpld_version_raw[2], 16), int(
|
cpld_version_str = "{}.{}".format(int(cpld_version_raw[2], 16), int(
|
||||||
cpld_version_raw[3], 16)) if cpld_version_raw is not None else 'None'
|
cpld_version_raw[3], 16)) if cpld_version_raw is not None else 'None'
|
||||||
cpld_version[cpld_name] = cpld_version_str
|
cpld_version[cpld_name] = cpld_version_str
|
||||||
|
@ -0,0 +1,233 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Celestica
|
||||||
|
#
|
||||||
|
# Watchdog contains an implementation of SONiC Platform Base API
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
import ctypes
|
||||||
|
import fcntl
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import array
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.watchdog_base import WatchdogBase
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
""" ioctl constants """
|
||||||
|
IO_WRITE = 0x40000000
|
||||||
|
IO_READ = 0x80000000
|
||||||
|
IO_READ_WRITE = 0xC0000000
|
||||||
|
IO_SIZE_INT = 0x00040000
|
||||||
|
IO_SIZE_40 = 0x00280000
|
||||||
|
IO_TYPE_WATCHDOG = ord('W') << 8
|
||||||
|
|
||||||
|
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG
|
||||||
|
WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG
|
||||||
|
WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG
|
||||||
|
|
||||||
|
""" Watchdog ioctl commands """
|
||||||
|
WDIOC_GETSUPPORT = 0 | WDR_40
|
||||||
|
WDIOC_GETSTATUS = 1 | WDR_INT
|
||||||
|
WDIOC_GETBOOTSTATUS = 2 | WDR_INT
|
||||||
|
WDIOC_GETTEMP = 3 | WDR_INT
|
||||||
|
WDIOC_SETOPTIONS = 4 | WDR_INT
|
||||||
|
WDIOC_KEEPALIVE = 5 | WDR_INT
|
||||||
|
WDIOC_SETTIMEOUT = 6 | WDWR_INT
|
||||||
|
WDIOC_GETTIMEOUT = 7 | WDR_INT
|
||||||
|
WDIOC_SETPRETIMEOUT = 8 | WDWR_INT
|
||||||
|
WDIOC_GETPRETIMEOUT = 9 | WDR_INT
|
||||||
|
WDIOC_GETTIMELEFT = 10 | WDR_INT
|
||||||
|
|
||||||
|
""" Watchdog status constants """
|
||||||
|
WDIOS_DISABLECARD = 0x0001
|
||||||
|
WDIOS_ENABLECARD = 0x0002
|
||||||
|
|
||||||
|
WDT_COMMON_ERROR = -1
|
||||||
|
WD_MAIN_IDENTITY = "iTCO_wdt"
|
||||||
|
WDT_SYSFS_PATH = "/sys/class/watchdog/"
|
||||||
|
|
||||||
|
|
||||||
|
class Watchdog(WatchdogBase):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.watchdog, self.wdt_main_dev_name = self._get_wdt()
|
||||||
|
self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name
|
||||||
|
self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name
|
||||||
|
self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name
|
||||||
|
# Set default value
|
||||||
|
self._disable()
|
||||||
|
self.armed = False
|
||||||
|
self.timeout = self._gettimeout(self.timeout_path)
|
||||||
|
|
||||||
|
def _is_wd_main(self, dev):
|
||||||
|
"""
|
||||||
|
Checks watchdog identity
|
||||||
|
"""
|
||||||
|
identity = self._read_file(
|
||||||
|
"{}/{}/identity".format(WDT_SYSFS_PATH, dev))
|
||||||
|
return identity == WD_MAIN_IDENTITY
|
||||||
|
|
||||||
|
def _get_wdt(self):
|
||||||
|
"""
|
||||||
|
Retrieves watchdog device
|
||||||
|
"""
|
||||||
|
wdt_main_dev_list = [dev for dev in os.listdir(
|
||||||
|
"/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)]
|
||||||
|
if not wdt_main_dev_list:
|
||||||
|
return None
|
||||||
|
wdt_main_dev_name = wdt_main_dev_list[0]
|
||||||
|
watchdog_device_path = "/dev/{}".format(wdt_main_dev_name)
|
||||||
|
watchdog = os.open(watchdog_device_path, os.O_RDWR)
|
||||||
|
return watchdog, wdt_main_dev_name
|
||||||
|
|
||||||
|
def _read_file(self, file_path):
|
||||||
|
"""
|
||||||
|
Read text file
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(file_path, "r") as fd:
|
||||||
|
txt = fd.read()
|
||||||
|
except IOError:
|
||||||
|
return WDT_COMMON_ERROR
|
||||||
|
return txt.strip()
|
||||||
|
|
||||||
|
def _enable(self):
|
||||||
|
"""
|
||||||
|
Turn on the watchdog timer
|
||||||
|
"""
|
||||||
|
req = array.array('h', [WDIOS_ENABLECARD])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
|
||||||
|
|
||||||
|
def _disable(self):
|
||||||
|
"""
|
||||||
|
Turn off the watchdog timer
|
||||||
|
"""
|
||||||
|
req = array.array('h', [WDIOS_DISABLECARD])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
|
||||||
|
|
||||||
|
def _keepalive(self):
|
||||||
|
"""
|
||||||
|
Keep alive watchdog timer
|
||||||
|
"""
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE)
|
||||||
|
|
||||||
|
def _settimeout(self, seconds):
|
||||||
|
"""
|
||||||
|
Set watchdog timer timeout
|
||||||
|
@param seconds - timeout in seconds
|
||||||
|
@return is the actual set timeout
|
||||||
|
"""
|
||||||
|
req = array.array('I', [seconds])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True)
|
||||||
|
return int(req[0])
|
||||||
|
|
||||||
|
def _gettimeout(self, timeout_path):
|
||||||
|
"""
|
||||||
|
Get watchdog timeout
|
||||||
|
@return watchdog timeout
|
||||||
|
"""
|
||||||
|
req = array.array('I', [0])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True)
|
||||||
|
|
||||||
|
return int(req[0])
|
||||||
|
|
||||||
|
def _gettimeleft(self):
|
||||||
|
"""
|
||||||
|
Get time left before watchdog timer expires
|
||||||
|
@return time left in seconds
|
||||||
|
"""
|
||||||
|
req = array.array('I', [0])
|
||||||
|
fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True)
|
||||||
|
|
||||||
|
return int(req[0])
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
def arm(self, seconds):
|
||||||
|
"""
|
||||||
|
Arm the hardware watchdog with a timeout of <seconds> seconds.
|
||||||
|
If the watchdog is currently armed, calling this function will
|
||||||
|
simply reset the timer to the provided value. If the underlying
|
||||||
|
hardware does not support the value provided in <seconds>, this
|
||||||
|
method should arm the watchdog with the *next greater* available
|
||||||
|
value.
|
||||||
|
Returns:
|
||||||
|
An integer specifying the *actual* number of seconds the watchdog
|
||||||
|
was armed with. On failure returns -1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ret = WDT_COMMON_ERROR
|
||||||
|
if seconds < 0:
|
||||||
|
return ret
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.timeout != seconds:
|
||||||
|
self.timeout = self._settimeout(seconds)
|
||||||
|
if self.armed:
|
||||||
|
self._keepalive()
|
||||||
|
else:
|
||||||
|
self._enable()
|
||||||
|
self.armed = True
|
||||||
|
ret = self.timeout
|
||||||
|
except IOError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def disarm(self):
|
||||||
|
"""
|
||||||
|
Disarm the hardware watchdog
|
||||||
|
Returns:
|
||||||
|
A boolean, True if watchdog is disarmed successfully, False if not
|
||||||
|
"""
|
||||||
|
disarmed = False
|
||||||
|
if self.is_armed():
|
||||||
|
try:
|
||||||
|
self._disable()
|
||||||
|
self.armed = False
|
||||||
|
disarmed = True
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return disarmed
|
||||||
|
|
||||||
|
def is_armed(self):
|
||||||
|
"""
|
||||||
|
Retrieves the armed state of the hardware watchdog.
|
||||||
|
Returns:
|
||||||
|
A boolean, True if watchdog is armed, False if not
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.armed
|
||||||
|
|
||||||
|
def get_remaining_time(self):
|
||||||
|
"""
|
||||||
|
If the watchdog is armed, retrieve the number of seconds remaining on
|
||||||
|
the watchdog timer
|
||||||
|
Returns:
|
||||||
|
An integer specifying the number of seconds remaining on thei
|
||||||
|
watchdog timer. If the watchdog is not armed, returns -1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
timeleft = WDT_COMMON_ERROR
|
||||||
|
|
||||||
|
if self.armed:
|
||||||
|
try:
|
||||||
|
timeleft = self._gettimeleft()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return timeleft
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""
|
||||||
|
Close watchdog
|
||||||
|
"""
|
||||||
|
|
||||||
|
os.close(self.watchdog)
|
Loading…
Reference in New Issue
Block a user