From faecf384177a4769a86b058e20a2affcef468093 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar T <53558409+santhosh-kt@users.noreply.github.com> Date: Fri, 17 Jun 2022 05:20:11 +0530 Subject: [PATCH] [DellEMC] S5212F and S5224F 2.0 API changes (#10315) Why I did it S5212F - Platform API 2.0 changes S5224F - Platform API 2.0 changes How I did it Implemented the functional API's needed for Platform API 2.0 Added media_settings.json, pcie.yaml, platform.json, system_health_monitoring_config.json files. How to verify it Used the API 2.0 test suite to validate the test cases. --- .../media_settings.json | 313 ++++++++++++++ .../x86_64-dellemc_s5212f_c3538-r0/pcie.yaml | 36 ++ .../platform.json | 342 +++++++++++++++ .../plugins/eeprom.py | 7 +- .../plugins/psuutil.py | 52 ++- .../plugins/sfputil.py | 207 ++++----- .../system_health_monitoring_config.json | 11 + .../x86_64-dellemc_s5224f_c3538-r0/pcie.yaml | 41 ++ .../platform.json | 397 ++++++++++++++++++ .../plugins/pcie.yaml | 21 - .../plugins/sfputil.py | 15 +- .../system_health_monitoring_config.json | 11 + .../s5212f/sonic_platform/chassis.py | 152 ++++++- .../s5212f/sonic_platform/component.py | 95 ++++- .../s5212f/sonic_platform/eeprom.py | 44 +- .../s5212f/sonic_platform/fan.py | 71 +++- .../s5212f/sonic_platform/fan_drawer.py | 75 ++++ .../s5212f/sonic_platform/psu.py | 132 +++++- .../s5212f/sonic_platform/sfp.py | 52 +++ .../s5212f/sonic_platform/thermal.py | 41 +- .../s5212f/sonic_platform/watchdog.py | 15 +- .../s5224f/sonic_platform/chassis.py | 145 ++++++- .../s5224f/sonic_platform/component.py | 90 +++- .../s5224f/sonic_platform/eeprom.py | 9 +- .../s5224f/sonic_platform/fan.py | 63 ++- .../s5224f/sonic_platform/fan_drawer.py | 89 ++++ .../s5224f/sonic_platform/psu.py | 130 +++++- .../s5224f/sonic_platform/sfp.py | 52 +++ .../s5224f/sonic_platform/thermal.py | 21 +- .../s5224f/sonic_platform/watchdog.py | 11 +- 30 files changed, 2471 insertions(+), 269 deletions(-) create mode 100644 device/dell/x86_64-dellemc_s5212f_c3538-r0/media_settings.json create mode 100644 device/dell/x86_64-dellemc_s5212f_c3538-r0/pcie.yaml create mode 100644 device/dell/x86_64-dellemc_s5212f_c3538-r0/platform.json create mode 100644 device/dell/x86_64-dellemc_s5212f_c3538-r0/system_health_monitoring_config.json create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/pcie.yaml create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/platform.json delete mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml create mode 100644 device/dell/x86_64-dellemc_s5224f_c3538-r0/system_health_monitoring_config.json diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/media_settings.json b/device/dell/x86_64-dellemc_s5212f_c3538-r0/media_settings.json new file mode 100644 index 0000000000..f91cb63ac8 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/media_settings.json @@ -0,0 +1,313 @@ +{ + "GLOBAL_MEDIA_SETTINGS": { + "1-12": { + "(.*-C6Y7M)|(.*-V250M)|(.*-05CWK6)|(.*-53HVN)|(.*-358VV)|(.*-MV799)|(.*-59970000.)|(.*-P4YPY)|(.*-TCPM2)|(.*-JNPF8)|(.*-27GG5)|(.*-P8T4W)|(.*-JR54Y)|(.*-L56[SQ]F0..-SD-R)|(.*-61676000.)|(.*-74752.*)|(SFP\\+-CR-.*)": { + "preemphasis": { + "lane0": "0x19410a" + } + }, + "(.*-58KM3)|(.*-2JVDD)|(.*-26FN3)|(SFP28-CR-((0\\.5)|(1\\.0)|(0\\.0)|(N/A)))": { + "preemphasis": { + "lane0": "0x16440a" + } + }, + + "(.*-D0R73)|(.*-YFNDD)|(SFP28-CR-2\\.0)": { + "preemphasis": { + "lane0": "0x15430c" + } + }, + + "(.*-VXFJY)|(.*-7R9N9)|(SFP28-CR-3\\.0)": { + "preemphasis": { + "lane0": "0x17400d" + } + }, + + "(.*-9X8JP)|(SFP28-CR-.*)": { + "preemphasis": { + "lane0": "0x173f0e" + } + } + }, + + "13-15": { + "(.*-035KG)|(.*-P7C7N)|(QSFP28-CR-((0\\.5)|(1\\.0)|(0\\.0)|(N/A)))": { + "preemphasis": { + "lane0": "0x16440a", + "lane1": "0x16440a", + "lane2": "0x16440a", + "lane3": "0x16440a" + } + }, + + ".*-76V43|(QSFP28-CR-2\\.0)": { + "preemphasis": { + "lane0": "0x15430c", + "lane1": "0x15430c", + "lane2": "0x15430c", + "lane3": "0x15430c" + } + }, + + ".*-3CC35|(QSFP28-CR-3\\.0)": { + "preemphasis": { + "lane0": "0x15430c", + "lane1": "0x15430c", + "lane2": "0x15430c", + "lane3": "0x15430c" + } + }, + + ".*-FN4FC|(QSFP28-CR-.*)": { + "preemphasis": { + "lane0": "0x10460e", + "lane1": "0x10460e", + "lane2": "0x10460e", + "lane3": "0x10460e" + } + } + } + }, + + "PORT_MEDIA_SETTINGS": { + "1": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "2": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x14460a" + } + } + }, + + "3": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x063602" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "4": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x16440a" + } + } + }, + + "5": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x063602" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "6": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "7": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x063602" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "8": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x16440a" + } + } + }, + + "9": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x063602" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "10": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "11": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + "preemphasis": { + "lane0": "0x063602" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x15450a" + } + } + }, + + "12": { + "(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": { + + "preemphasis": { + "lane0": "0x073702" + } + }, + + "(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": { + "preemphasis": { + "lane0": "0x16440a" + } + } + }, + + "13": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x134809", + "lane1": "0x134809", + "lane2": "0x134809", + "lane3": "0x134809" + } + }, + + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x134809", + "lane1": "0x134809", + "lane2": "0x134809", + "lane3": "0x134809" + } + } + }, + + "14": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x134809", + "lane1": "0x134809", + "lane2": "0x134809", + "lane3": "0x134809" + } + }, + + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x134809", + "lane1": "0x134809", + "lane2": "0x134809", + "lane3": "0x134809" + } + } + }, + + "15": { + "(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": { + "preemphasis": { + "lane0": "0x13470a", + "lane1": "0x13470a", + "lane2": "0x13470a", + "lane3": "0x13470a" + } + }, + + "QSFP\\+-.*": { + "preemphasis": { + "lane0": "0x13470a", + "lane1": "0x13470a", + "lane2": "0x13470a", + "lane3": "0x13470a" + } + } + } + } +} diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/pcie.yaml b/device/dell/x86_64-dellemc_s5212f_c3538-r0/pcie.yaml new file mode 100644 index 0000000000..10a596d512 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/pcie.yaml @@ -0,0 +1,36 @@ +- bus: '00' + dev: '09' + fn: '0' + id: '19a4' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #0 (rev 11)' +- bus: '00' + dev: '0b' + fn: '0' + id: '19a6' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #2 (rev 11)' +- bus: '00' + dev: '0c' + fn: '0' + id: '19a7' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #3 (rev 11)' +- bus: '02' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '01' + dev: '00' + fn: '0' + id: 'b771' + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b771 (rev 01)' +- bus: '03' + dev: '00' + fn: '0' + id: '7021' + name: 'Non-VGA unclassified device: Xilinx Corporation Device 7021' +- bus: '00' + dev: '14' + fn: '0' + id: '19c2' + name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)' diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/platform.json b/device/dell/x86_64-dellemc_s5212f_c3538-r0/platform.json new file mode 100644 index 0000000000..47a0722823 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/platform.json @@ -0,0 +1,342 @@ +{ + "chassis": { + "name": "S5212F-ON", + "status_led": { + "controllable": true, + "colors": ["blinking_green", "green", "amber", "blinking_amber"] + }, + "thermal_manager": false, + "components": [ + { + "name": "BIOS" + }, + { + "name": "FPGA" + }, + { + "name": "BMC" + }, + { + "name": "System CPLD" + }, + { + "name": "Slave CPLD 1" + } + ], + "fans": [ + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray1-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray1-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray2-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray3", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray3-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray4", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray4-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU1 Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "PSU2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU2 Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + } + ], + "thermals": [ + { + "name": "CPU On-board", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "ASIC On-board", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "System Front Left", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "System Front Middle", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "System Front Right", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "Inlet Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + } + ], + "modules": [], + "sfps": [ + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "QSFP28 or later" + }, + { + "name": "QSFP28 or later" + }, + { + "name": "QSFP28 or later" + } + ] + }, + "interfaces": {} +} diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/eeprom.py b/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/eeprom.py index a09ce7f3ef..336bf3a9bf 100644 --- a/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/eeprom.py +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/eeprom.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ############################################################################# -# DellEMC S5248f +# DellEMC S5212f # # Platform and model specific eeprom subclass, inherits from the base class, # and provides the followings: @@ -9,10 +9,11 @@ # - specific encoder/decoder if there is special need ############################################################################# +import os.path + try: - import os.path from sonic_eeprom import eeprom_tlvinfo -except ImportError, e: +except ImportError as e: raise ImportError (str(e) + "- required module not found") diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/psuutil.py b/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/psuutil.py index ede68a2290..9a71f7b911 100644 --- a/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/psuutil.py +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/psuutil.py @@ -3,6 +3,19 @@ # Platform-specific PSU status interface for SONiC # +import logging +import sys +import subprocess + +S5212F_MAX_PSUS = 2 +IPMI_PSU_DATA = "docker exec -it pmon ipmitool sdr list" +IPMI_PSU_DATA_DOCKER = "ipmitool sdr list" +PSU_PRESENCE = "PSU{0}_stat" +# Use this for older firmware +# PSU_PRESENCE="PSU{0}_prsnt" +ipmi_sdr_list = "" + + try: from sonic_psu.psu_base import PsuBase except ImportError as e: @@ -17,7 +30,38 @@ class PsuUtil(PsuBase): def isDockerEnv(self): num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker") - return (num_docker > 0) + if num_docker > 0: + return True + else: + return False + + # Fetch a BMC register + def get_pmc_register(self, reg_name): + + global ipmi_sdr_list + ipmi_cmd = IPMI_PSU_DATA + dockerenv = self.isDockerEnv() + if dockerenv == True: + ipmi_cmd = IPMI_PSU_DATA_DOCKER + + status, ipmi_sdr_list = subprocess.getstatusoutput(ipmi_cmd) + + if status: + logging.error('Failed to execute:' + ipmi_sdr_list) + sys.exit(0) + + for item in ipmi_sdr_list.split("\n"): + if reg_name in item: + output = item.strip() + + if not output: + print('\nFailed to fetch: ' + reg_name + ' sensor ') + sys.exit(0) + + output = output.split('|')[1] + + logging.basicConfig(level=logging.DEBUG) + return output def get_num_psus(self): """ @@ -37,7 +81,8 @@ class PsuUtil(PsuBase): """ # Until psu_status is implemented this is hardcoded temporarily - return 1 + status = 1 + return status def get_psu_presence(self, index): """ @@ -46,5 +91,6 @@ class PsuUtil(PsuBase): :param index: An integer, index of the PSU of which to query status :return: Boolean, True if PSU is plugged, False if not """ - return 1 + cmd_status, psu_status = subprocess.getstatusoutput('ipmitool raw 0x04 0x2d ' + hex(0x30 + index) + " | awk '{print substr($0,9,1)}'") + return 1 if psu_status == '1' else 0 diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/sfputil.py index ee52d90111..0b93eb87f9 100644 --- a/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/plugins/sfputil.py @@ -45,7 +45,7 @@ SFP_MODULE_THRESHOLD_WIDTH = 56 XCVR_DOM_CAPABILITY_OFFSET = 92 XCVR_DOM_CAPABILITY_WIDTH = 1 -XCVR_EEPROM_TYPE_SFP = 1 + class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -147,10 +147,10 @@ class SfpUtil(SfpUtilBase): return False # Port offset starts with 0x4004 - port_offset = 16388 + ((port_num-1) * 16) + port_offset = 16388 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error if (reg_value == "" ): @@ -161,7 +161,6 @@ class SfpUtil(SfpUtilBase): if (port_num > 12): mask = (1 << 4) - # ModPrsL is active low if reg_value & mask == 0: return True @@ -174,17 +173,17 @@ class SfpUtil(SfpUtilBase): if port_num < self.port_start or port_num > self.port_end: return False - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num-1) * 16) + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error if (reg_value == "" ): return False - # Mask off 4th bit for presence + # Mask off 6th bit for lpmode status mask = (1 << 6) # LPMode is active high @@ -199,62 +198,68 @@ class SfpUtil(SfpUtilBase): if port_num < self.port_start or port_num > self.port_end: return False - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num-1) * 16) + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error if (reg_value == "" ): return False - # Mask off 4th bit for presence + # Mask off 6th bit for lpmode status mask = (1 << 6) - # LPMode is active high; set or clear the bit accordingly + # LPMode is active high; set or clear the bit accordingly if lpmode is True: reg_value = reg_value | mask else: reg_value = reg_value & ~mask # Convert our register value back to a hex string and write back - self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + if status != reg_value: + print ("Error: Set LP mode status %d", status) return True def reset(self, port_num): - # Check for invalid port_num + # Check for invalid port_num if port_num < self.port_start or port_num > self.port_end: return False - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num-1) * 16) + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error if (reg_value == "" ): return False - # Mask off 4th bit for presence - mask = (1 << 6) + # Mask off 4th bit for reset status + mask = (1 << 4) # ResetL is active low reg_value = reg_value & ~mask - # Convert our register value back to a hex string and write back - self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + if status != reg_value: + print ("Error: pci_set_value reset status %d", status) # Sleep 1 second to allow it to settle time.sleep(1) reg_value = reg_value | mask - # Convert our register value back to a hex string and write back - self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + if status != reg_value: + print ("Error: pci_set_value reset status %d", status) return True @@ -276,7 +281,6 @@ class SfpUtil(SfpUtilBase): time.sleep(0.5) - def get_transceiver_dom_info_dict(self, port_num): transceiver_dom_info_dict = {} @@ -288,8 +292,8 @@ class SfpUtil(SfpUtilBase): ] transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') - if port_num in self.qsfp_ports: - offset = 0 + if port_num in self.qsfp_ports: + offset = 0 offset_xcvr = 128 file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) if not self._sfp_eeprom_present(file_path, 0): @@ -320,7 +324,7 @@ class SfpUtil(SfpUtilBase): return transceiver_dom_info_dict dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) - if dom_temperature_raw is not None: + if dom_temperature_raw is not None: dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) else: return transceiver_dom_info_dict @@ -352,11 +356,11 @@ class SfpUtil(SfpUtilBase): else: return transceiver_dom_info_dict - transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx1power'] = 'N/A' transceiver_dom_info_dict['tx2power'] = 'N/A' transceiver_dom_info_dict['tx3power'] = 'N/A' transceiver_dom_info_dict['tx4power'] = 'N/A' - try: + try: sysfsfile_eeprom.close() except IOError: print("Error: closing sysfs file %s" % file_path) @@ -374,7 +378,7 @@ class SfpUtil(SfpUtilBase): transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] else: - offset = 256 + offset = 256 file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) if not self._sfp_eeprom_present(file_path, 0): return None @@ -387,10 +391,10 @@ class SfpUtil(SfpUtilBase): sfpd_obj = sff8472Dom(None,1) if sfpd_obj is None: - return transceiver_dom_info_dict + return None dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET), - SFP_TEMPE_WIDTH) + SFP_TEMPE_WIDTH) if dom_temperature_raw is not None: dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) @@ -432,7 +436,7 @@ class SfpUtil(SfpUtilBase): transceiver_dom_info_dict['tx3power'] = 'N/A' transceiver_dom_info_dict['tx4power'] = 'N/A' - return transceiver_dom_info_dict + return transceiver_dom_info_dict def get_transceiver_dom_threshold_info_dict(self, port_num): transceiver_dom_threshold_info_dict = {} @@ -450,115 +454,116 @@ class SfpUtil(SfpUtilBase): transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') if port_num in self.qsfp_ports: - file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): return None - try: + try: sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0) - except IOError: + except IOError: print("Error: reading sysfs file %s" % file_path) return None - sfpd_obj = sff8436Dom() - if sfpd_obj is None: + sfpd_obj = sff8436Dom() + if sfpd_obj is None: return transceiver_dom_threshold_info_dict # Dom Threshold data starts from offset 384 # Revert offset back to 0 once data is retrieved - offset = 384 - dom_module_threshold_raw = self._read_eeprom_specific_bytes( + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( sysfsfile_eeprom, (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) - if dom_module_threshold_raw is not None: + if dom_module_threshold_raw is not None: dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) - else: + else: return transceiver_dom_threshold_info_dict - dom_channel_threshold_raw = self._read_eeprom_specific_bytes( + dom_channel_threshold_raw = self._read_eeprom_specific_bytes( sysfsfile_eeprom, (offset + QSFP_CHANNL_THRESHOLD_OFFSET), QSFP_CHANNL_THRESHOLD_WIDTH) - if dom_channel_threshold_raw is not None: + if dom_channel_threshold_raw is not None: dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) - else: + else: return transceiver_dom_threshold_info_dict - try: + try: sysfsfile_eeprom.close() - except IOError: + except IOError: print("Error: closing sysfs file %s" % file_path) return None # Threshold Data - transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] - transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] - transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] - transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] - transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] - transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] - transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] - transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] - transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] - transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] else: - offset = 256 - file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): + offset = 256 + file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): return None - try: + try: sysfsfile_eeprom = io.open(file_path,"rb",0) - except IOError: + except IOError: print("Error: reading sysfs file %s" % file_path) return None - sfpd_obj = sff8472Dom(None,1) - if sfpd_obj is None: + sfpd_obj = sff8472Dom(None,1) + if sfpd_obj is None: return transceiver_dom_threshold_info_dict - dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, + dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) - if dom_module_threshold_raw is not None: + if dom_module_threshold_raw is not None: dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) - else: + else: return transceiver_dom_threshold_info_dict - try: + try: sysfsfile_eeprom.close() - except IOError: + except IOError: print("Error: closing sysfs file %s" % file_path) return None #Threshold Data - transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] - transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] - transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] - transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] - transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] - transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] - transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] - transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] - transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] - transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] - transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] return transceiver_dom_threshold_info_dict + diff --git a/device/dell/x86_64-dellemc_s5212f_c3538-r0/system_health_monitoring_config.json b/device/dell/x86_64-dellemc_s5212f_c3538-r0/system_health_monitoring_config.json new file mode 100644 index 0000000000..2fdb993a64 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5212f_c3538-r0/system_health_monitoring_config.json @@ -0,0 +1,11 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": ["fan.speed"], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "amber", + "normal": "green", + "booting": "blinking_green" + } +} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/pcie.yaml b/device/dell/x86_64-dellemc_s5224f_c3538-r0/pcie.yaml new file mode 100644 index 0000000000..de32210818 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/pcie.yaml @@ -0,0 +1,41 @@ +- bus: '00' + dev: '09' + fn: '0' + id: '19a4' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #0 (rev 11)' +- bus: '00' + dev: '0b' + fn: '0' + id: '19a6' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #2 (rev 11)' +- bus: '00' + dev: '0c' + fn: '0' + id: '19a7' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #3 (rev 11)' +- bus: '00' + dev: '0e' + fn: '0' + id: '19a8' + name: 'Intel Corporation Atom Processor C3000 Series PCI Express Root Port #4 (rev 11)' +- bus: '03' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '02' + dev: '00' + fn: '0' + id: b771 + name: 'Ethernet controller: Broadcom Limited Device b771 (rev 01)' +- bus: '04' + dev: '00' + fn: '0' + id: '7021' + name: 'Non-VGA unclassified device: Xilinx Corporation Device 7021' +- bus: '00' + dev: '14' + fn: '0' + id: 19c2 + name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)' diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/platform.json b/device/dell/x86_64-dellemc_s5224f_c3538-r0/platform.json new file mode 100644 index 0000000000..54823f6c31 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/platform.json @@ -0,0 +1,397 @@ +{ + "chassis": { + "name": "S5224F-ON", + "status_led": { + "controllable": true, + "colors": ["blinking_green", "green", "amber", "blinking_amber"] + }, + "thermal_manager": false, + "components": [ + { + "name": "BIOS" + }, + { + "name": "FPGA" + }, + { + "name": "BMC" + }, + { + "name": "System CPLD" + }, + { + "name": "Slave CPLD 1" + } + ], + "fans": [ + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray1-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray1-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray2-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray3", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray3-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray4", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray4-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan2", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU1 Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "PSU2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU2 Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + } + ], + "thermals": [ + { + "name": "CPU On-board", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "ASIC On-board", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "System Front Left", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "System Front Middle", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "System Front Right", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "Inlet Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PSU1 Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PSU2 Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + } + ], + "modules": [], + "sfps": [ + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "QSFP28 or later" + }, + { + "name": "QSFP28 or later" + }, + { + "name": "QSFP28 or later" + }, + { + "name": "QSFP28 or later" + } + ] + }, + "interfaces": {} +} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml deleted file mode 100644 index c9c41d889e..0000000000 --- a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/pcie.yaml +++ /dev/null @@ -1,21 +0,0 @@ -- bus: '03' - dev: '00' - fn: '0' - id: '1533' - name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev - 03)' -- bus: '02' - dev: '00' - fn: '0' - id: b771 - name: 'Ethernet controller: Broadcom Limited Device b771 (rev 01)' -- bus: '04' - dev: '00' - fn: '0' - id: '7021' - name: 'Non-VGA unclassified device: Xilinx Corporation Device 7021' -- bus: '00' - dev: '14' - fn: '0' - id: 19c2 - name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)' diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py index b0fb250b0b..b6e787f508 100644 --- a/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/plugins/sfputil.py @@ -48,7 +48,6 @@ XCVR_DOM_CAPABILITY_OFFSET = 92 XCVR_DOM_CAPABILITY_WIDTH = 1 - class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -166,7 +165,7 @@ class SfpUtil(SfpUtilBase): if (reg_value == "" ): return False - # Mask off 4th bit for presence + # Mask off 6th bit for lpmode status mask = (1 << 6) # LPMode is active high @@ -191,7 +190,7 @@ class SfpUtil(SfpUtilBase): if (reg_value == "" ): return False - # Mask off 4th bit for presence + # Mask off 6th bit for lpmode status mask = (1 << 6) # LPMode is active high; set or clear the bit accordingly @@ -223,8 +222,8 @@ class SfpUtil(SfpUtilBase): if (reg_value == "" ): return False - # Mask off 4th bit for presence - mask = (1 << 6) + # Mask off 4th bit for reset status + mask = (1 << 4) # ResetL is active low reg_value = reg_value & ~mask @@ -375,8 +374,10 @@ class SfpUtil(SfpUtilBase): sfpd_obj = sff8472Dom(None,1) if sfpd_obj is None: return None + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET), - SFP_TEMPE_WIDTH) + SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) else: @@ -417,7 +418,7 @@ class SfpUtil(SfpUtilBase): transceiver_dom_info_dict['tx3power'] = 'N/A' transceiver_dom_info_dict['tx4power'] = 'N/A' - return transceiver_dom_info_dict + return transceiver_dom_info_dict def get_transceiver_dom_threshold_info_dict(self, port_num): transceiver_dom_threshold_info_dict = {} diff --git a/device/dell/x86_64-dellemc_s5224f_c3538-r0/system_health_monitoring_config.json b/device/dell/x86_64-dellemc_s5224f_c3538-r0/system_health_monitoring_config.json new file mode 100644 index 0000000000..2fdb993a64 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5224f_c3538-r0/system_health_monitoring_config.json @@ -0,0 +1,11 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": ["fan.speed"], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "amber", + "normal": "green", + "booting": "blinking_green" + } +} diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/chassis.py index 629f4e73f7..eb99821ae8 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/chassis.py @@ -20,7 +20,7 @@ try: from sonic_platform.thermal import Thermal from sonic_platform.fan_drawer import FanDrawer from sonic_platform.watchdog import Watchdog - from sonic_platform.fan import Fan + from sonic_platform.hwaccess import pci_get_value, pci_set_value except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -29,6 +29,9 @@ MAX_S5212F_FANTRAY =4 MAX_S5212F_FAN = 2 MAX_S5212F_PSU = 2 MAX_S5212F_THERMAL = 6 +SYSTEM_LED_REG = 0x24 +SYSTEM_BEACON_LED_SET = 0x8 +SYSTEM_BEACON_LED_CLEAR = 0xFFFFFFF7 media_part_num_list = set([ \ "8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC", @@ -53,14 +56,32 @@ class Chassis(ChassisBase): REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" OIR_FD_PATH = "/sys/bus/pci/devices/0000:03:00.0/port_msi" + pci_res = "/sys/bus/pci/devices/0000:03:00.0/resource0" oir_fd = -1 epoll = -1 + sysled_offset = 0x0024 + SYSLED_COLOR_TO_REG = { + "blinking_green": 0x0, + "green" : 0x10, + "amber" : 0x20, + "blinking_amber": 0x30 + } + + REG_TO_SYSLED_COLOR = { + 0x0 : "blinking_green", + 0x10 : "green", + 0x20 : "amber", + 0x30 : "blinking_amber" + } + _global_port_pres_dict = {} def __init__(self): ChassisBase.__init__(self) + self.STATUS_LED_COLOR_BLUE_BLINK = "blinking blue" + self.STATUS_LED_COLOR_OFF = "off" # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 @@ -79,6 +100,9 @@ class Chassis(ChassisBase): self._sfp_list.append(sfp_node) self._eeprom = Eeprom() + self._watchdog = Watchdog() + self._num_sfps = self.PORT_END + self._num_fans = MAX_S5212F_FAN * MAX_S5212F_FANTRAY for i in range(MAX_S5212F_THERMAL): thermal = Thermal(i) @@ -92,12 +116,6 @@ class Chassis(ChassisBase): psu = Psu(i) self._psu_list.append(psu) - - for i in range(MAX_S5212F_FANTRAY): - for j in range(MAX_S5212F_FAN): - fan = Fan(i,j) - self._fan_list.append(fan) - for i in range(MAX_S5212F_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) @@ -105,13 +123,15 @@ class Chassis(ChassisBase): for port_num in range(self.PORT_START, (self.PORT_END + 1)): # sfp get uses zero-indexing, but port numbers start from 1 - presence = self.get_sfp(port_num).get_presence() + presence = self.get_sfp(port_num-1).get_presence() if presence: self._global_port_pres_dict[port_num] = '1' else: self._global_port_pres_dict[port_num] = '0' - self._watchdog = Watchdog() + self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK + self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF + def __del__(self): if self.oir_fd != -1: @@ -180,12 +200,12 @@ class Chassis(ChassisBase): port_dict[port_num] = '0' if(len(port_dict) > 0): - return True, change_dict + return True, change_dict if timeout: now_ms = time.time() * 1000 if (now_ms - start_ms >= timeout): - return True, change_dict + return True, change_dict def get_sfp(self, index): @@ -286,6 +306,34 @@ class Chassis(ChassisBase): values. """ return self._eeprom.system_eeprom_info() + + def get_eeprom(self): + """ + Retrieves the Sys Eeprom instance for the chassis. + Returns : + The instance of the Sys Eeprom + """ + return self._eeprom + + def get_num_fans(self): + """ + Retrives the number of Fans on the chassis. + Returns : + An integer represents the number of Fans on the chassis. + """ + return self._num_fans + + def get_num_sfps(self): + """ + Retrives the numnber of Media on the chassis. + Returns: + An integer represences the number of SFPs on the chassis. + """ + return self._num_sfps + + def initizalize_system_led(self): + self.sys_ledcolor = "green" + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -325,3 +373,85 @@ class Chassis(ChassisBase): def get_qualified_media_list(self): return media_part_num_list + + def set_locator_led(self, color): + """ + Sets the state of the Chassis Locator LED + Args: + color: A string representing the color with which to set the Chassis Locator LED + Returns: + bool: True if the Chassis Locator LED state is set successfully, False if not + """ + resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" + val = pci_get_value(resource, SYSTEM_LED_REG) + if self.LOCATOR_LED_ON == color: + val = int(val) | SYSTEM_BEACON_LED_SET + elif self.LOCATOR_LED_OFF == color: + val = int(val) & SYSTEM_BEACON_LED_CLEAR + else: + return False + pci_set_value(resource, val, SYSTEM_LED_REG) + return True + + def get_locator_led(self): + """ + Gets the state of the Chassis Locator LED + Returns: + LOCATOR_LED_ON or LOCATOR_LED_OFF + """ + resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" + val = pci_get_value(resource, SYSTEM_LED_REG) + val = int(val) & SYSTEM_BEACON_LED_SET + if not val: + return self.LOCATOR_LED_OFF + else: + return self.LOCATOR_LED_ON + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def set_status_led(self, color): + """ + Sets the state of the system LED + Args: + color: A string representing the color with which to set the + system LED + Returns: + bool: True if system LED state is set successfully, False if not + """ + if color not in list(self.SYSLED_COLOR_TO_REG.keys()): + return False + + val = pci_get_value(self.pci_res, self.sysled_offset) + val = (val & 0xFFCF) | self.SYSLED_COLOR_TO_REG[color] + + pci_set_value(self.pci_res, val, self.sysled_offset) + self.sys_ledcolor = color + return True + + def get_status_led(self): + """ + Gets the state of the system LED + Returns: + A string, one of the valid LED color strings which could be + vendor specified. + """ + val = pci_get_value(self.pci_res, self.sysled_offset) + if val != -1: + val = val & 0x30 + return self.REG_TO_SYSLED_COLOR.get(val) + return self.sys_ledcolor diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/component.py index a1bba0c9d3..fba5128356 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/component.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/component.py @@ -9,26 +9,28 @@ # ######################################################################## + try: import subprocess from sonic_platform_base.component_base import ComponentBase import sonic_platform.hwaccess as hwaccess - + except ImportError as e: raise ImportError(str(e) + "- required module not found") def get_bios_version(): - return subprocess.check_output(['dmidecode', '-s', 'system-version']).strip() + return subprocess.check_output(['dmidecode', '-s', + 'system-version']).decode('utf-8').strip() def get_fpga_version(): val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:03:00.0/resource0', 0) return '{}.{}'.format((val >> 8) & 0xff, val & 0xff) - + def get_bmc_version(): return subprocess.check_output( ['cat', '/sys/class/ipmi/ipmi0/device/bmc/firmware_revision'] - ).strip() + ).decode('utf-8').strip() def get_cpld_version(bus, i2caddr): return '{}.{}'.format(hwaccess.i2c_get(bus, i2caddr, 1), @@ -102,6 +104,55 @@ class Component(ComponentBase): """ return self.version + def get_presence(self): + """ + Retrieves the presence of the component + Returns: + bool: True if present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the part number of the component + Returns: + string: Part number of component + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the component + Returns: + string: Serial number of component + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the component + Returns: + bool: True if component is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether component is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + def install_firmware(self, image_path): """ Installs firmware to the component @@ -111,3 +162,39 @@ class Component(ComponentBase): A boolean, True if install was successful, False if not """ return False + + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + Note: the firmware version will be read from image + Args: + image_path: A string, path to firmware image + Returns: + A string containing the available firmware version of the component + """ + return "N/A" + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + Args: + image_path: A string, path to firmware image + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return "None" + + def update_firmware(self, image_path): + """ + Updates firmware of the component + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + Args: + image_path: A string, path to firmware image + Raises: + RuntimeError: update failed + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/eeprom.py index d8293704e6..ba7ef95d8e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/eeprom.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/eeprom.py @@ -32,34 +32,34 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): self.eeprom_tlv_dict = dict() try: self.eeprom_data = self.read_eeprom() - except: + except Exception: self.eeprom_data = "N/A" raise RuntimeError("Eeprom is not Programmed") - else: - eeprom = self.eeprom_data - if not self.is_valid_tlvinfo_header(eeprom): - return + eeprom = self.eeprom_data - total_length = eeprom[9] << 8 | eeprom[10] - tlv_index = self._TLV_INFO_HDR_LEN - tlv_end = self._TLV_INFO_HDR_LEN + total_length + if not self.is_valid_tlvinfo_header(eeprom): + return - while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: - if not self.is_valid_tlv(eeprom[tlv_index:]): - break + total_length = (eeprom[9] << 8) | eeprom[10] + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length - tlv = eeprom[tlv_index:tlv_index + 2 - + eeprom[tlv_index + 1]] - code = "0x%02X" % tlv[0] + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break - name, value = self.decoder(None, tlv) + tlv = eeprom[tlv_index:tlv_index + 2 + + eeprom[tlv_index + 1]] + code = "0x%02X" % tlv[0] - self.eeprom_tlv_dict[code] = value - if eeprom[tlv_index] == self._TLV_CODE_CRC_32: - break + name, value = self.decoder(None, tlv) - tlv_index += eeprom[tlv_index+1] + 2 + self.eeprom_tlv_dict[code] = value + if eeprom[tlv_index] == self._TLV_CODE_CRC_32: + break + + tlv_index += eeprom[tlv_index+1] + 2 def serial_number_str(self): """ @@ -80,7 +80,7 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): if not is_valid or t[1] != 6: return super(TlvInfoDecoder, self).switchaddrstr(e) - return ":".join([binascii.b2a_hex(T) for T in t[2]]) + return ":".join(["{:02x}".format(T) for T in t[2]]).upper() def modelstr(self): """ @@ -133,7 +133,3 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): found in the system EEPROM. """ return self.eeprom_tlv_dict - - - - diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan.py index 3b3e5e3e58..95ad6b95c0 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DellEMC SS5212F +# DellEMC S5212F # # Module contains an implementation of SONiC Platform Base API and # provides the Fans' information which are available in the platform. @@ -46,8 +46,8 @@ class Fan(FanBase): 2: {"Prsnt": 0x5b, "State": 0x5b, "Speed": 0x20}, 3: {"Prsnt": 0x58, "State": 0x58, "Speed": 0x25}, 4: {"Prsnt": 0x5c, "State": 0x5c, "Speed": 0x21}, - 5: {"Prsnt": 0x59, "State": 0x59, "Speed": 0x26}, - 6: {"Prsnt": 0x5d, "State": 0x5d, "Speed": 0x22}, + 5: {"Prsnt": 0x57, "State": 0x59, "Speed": 0x26}, + 6: {"Prsnt": 0x59, "State": 0x5d, "Speed": 0x22}, 7: {"Prsnt": 0x5a, "State": 0x5a, "Speed": 0x27}, 8: {"Prsnt": 0x5e, "State": 0x5e, "Speed": 0x23} } PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x2e}, @@ -119,7 +119,11 @@ class Fan(FanBase): Returns: bool: True if fan is present, False if not """ - return True + if self.is_psu_fan: + return self.dependency.get_presence() + else: + # In S5212F, Fans are fixed + return True def get_status(self): """ @@ -130,8 +134,12 @@ class Fan(FanBase): status = False is_valid, state = self.state_sensor.get_reading() if is_valid: - if (state == 0x00): - status = True + if self.is_psu_fan: + if not state > 1: + status = True + else: + if state == 0x00: + status = True return status def get_direction(self): @@ -160,13 +168,13 @@ class Fan(FanBase): int: percentage of the max fan speed """ speed = None - if not self.is_psu_fan : + if not self.is_psu_fan: if self.max_speed == 0: self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1] self.max_speed = self.max_speed[1] << 8 | self.max_speed[0] is_valid, fan_speed = self.speed_sensor.get_reading() if is_valid and self.max_speed > 0: - speed = (100 * fan_speed)/self.max_speed + speed = (100 * fan_speed)//self.max_speed return speed def get_speed_rpm(self): @@ -178,4 +186,49 @@ class Fan(FanBase): fan_speed = None if not self.is_psu_fan : is_valid, fan_speed = self.speed_sensor.get_reading() - return fan_speed + return fan_speed if is_valid else None + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fanindex + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + if self.get_presence(): + # The tolerance value is fixed as 20% for all the DellEMC platforms + tolerance = 20 + else: + tolerance = 0 + + return tolerance + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by HW + # Return True to avoid thermalctld alarm + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan_drawer.py index 3f3c18fe0a..e846f7b8be 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan_drawer.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/fan_drawer.py @@ -35,3 +35,78 @@ class FanDrawer(FanDrawerBase): string: The name of the device """ return "FanTray{}".format(self.fantrayindex) + + + def get_presence(self): + """ + Retrives the presence of the fan drawer + Returns: + bool: True if fan_tray is present, False if not + """ + return self.get_fan(0).get_presence() + + def get_model(self): + """ + Retrieves the part number of the fan drawer + Returns: + string: Part number of fan drawer + """ + return "NA" + + def get_serial(self): + """ + Retrieves the serial number of the fan drawer + Returns: + string: Serial number of the fan drawer + """ + return "NA" + + def get_status(self): + """ + Retrieves the operational status of the fan drawer + Returns: + bool: True if fan drawer is operating properly, False if not + """ + status = True + for fan in self.get_all_fans(): + status &= fan.get_status() + return status + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fantrayindex + + def is_replaceable(self): + """ + Indicate whether this fan drawer is replaceable. + Returns: + bool: True if it is replaceable, False if not + """ + return False + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by BMC + # Return True to avoid thermalctld alarm + return True + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by Fan Drawer + Returns: + A float, with value of the maximum consumable power of the + component. + """ + return 0.0 diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/psu.py index 9ef5625dea..36aaec8b1d 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/psu.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ######################################################################## -# DellEMC S5212F +# DellEMC S5212F # # Module contains an implementation of SONiC Platform Base API and # provides the PSUs' information which are available in the platform @@ -83,6 +83,15 @@ class Psu(PsuBase): return presence + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celcius up to + nearest thousandth of one degree celcius, e.g. 30.125 + """ + return 0.0 + def get_model(self): """ Retrieves the part number of the PSU @@ -101,6 +110,26 @@ class Psu(PsuBase): """ return self.fru.get_board_serial() + def get_revision(self): + """ + Retrives thehardware revision of the device + Returns: + String: revision value of device + """ + serial = self.fru.get_board_serial() + if serial != "NA" and len(serial) == 23: + return serial[-3:] + else: + return "NA" + + def is_replaceable(self): + """ + Indicate whether this PSU is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + def get_status(self): """ Retrieves the operational status of the PSU @@ -124,7 +153,7 @@ class Psu(PsuBase): A float number, the output voltage in volts, e.g. 12.1 """ - return None + return 0.0 def get_current(self): """ @@ -134,7 +163,7 @@ class Psu(PsuBase): A float number, electric current in amperes, e.g. 15.4 """ - return None + return 0.0 def get_power(self): """ @@ -144,7 +173,37 @@ class Psu(PsuBase): A float number, the power in watts, e.g. 302.6 """ - return None + return 0.0 + + def get_input_voltage(self): + """ + Retrieves current PSU voltage input + + Returns: + A float number, the input voltage in volts, + e.g. 12.1 + """ + return 0.0 + + def get_input_current(self): + """ + Retrieves present electric current supplied to PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + return 0.0 + + def get_input_power(self): + """ + Retrieves current energy supplied to PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + return 0.0 def get_powergood_status(self): """ @@ -162,6 +221,15 @@ class Psu(PsuBase): return status + def get_mfr_id(self): + """ + Retrives the Manufacturer Id of PSU + + Returns: + A string, the manunfacturer id. + """ + return self.fru.get_board_mfr_id() + def get_type(self): """ Retrives the Power Type of PSU @@ -169,12 +237,54 @@ class Psu(PsuBase): Returns : A string, PSU power type """ - board_info = self.fru.get_board_part_number() - if board_info is not None : - board_part_no = board_info[0:6] - if board_part_no in switch_sku: - return switch_sku[board_part_no][0] + board_product = self.fru.get_board_product() + if board_product is not None : + info = board_product.split(',') + if 'AC' in info : return 'AC' + if 'DC' in info : return 'DC' return None - def get_mfr_id(self): - return self.fru.get_board_mfr_id() + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + return 0.0 + + def get_voltage_high_threshold(self): + """ + Returns PSU high threshold in Volts + """ + return 0.0 + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return float(750) + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + # Hardware not supported + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/sfp.py index 0b62c81bcb..6b8b6c9287 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/sfp.py @@ -19,6 +19,10 @@ try: except ImportError as e: raise ImportError(str(e) + "- required module not found") +QSFP_INFO_OFFSET = 128 +SFP_INFO_OFFSET = 0 +QSFP_DD_PAGE0 = 0 + SFP_TYPE_LIST = [ '0x3' # SFP/SFP+/SFP28 and later ] @@ -39,6 +43,7 @@ class Sfp(SfpOptoeBase): def __init__(self, index, sfp_type, eeprom_path): SfpOptoeBase.__init__(self) + self.port_type = sfp_type self.sfp_type = sfp_type self.port_type = sfp_type self.index = index @@ -92,6 +97,23 @@ class Sfp(SfpOptoeBase): self.set_media_type() self.reinit_sfp_driver() + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + def get_presence(self): """ Retrieves the presence of the sfp @@ -313,3 +335,33 @@ class Sfp(SfpOptoeBase): except IOError as e: print("Error: Unable to open file: %s" % str(e)) return False + + def get_error_description(self): + """ + Retrives the error descriptions of the SFP module + Returns: + String that represents the current error descriptions of vendor specific errors + In case there are multiple errors, they should be joined by '|', + like: "Bad EEPROM|Unsupported cable" + """ + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + else: + if not os.path.isfile(self.eeprom_path): + return "EEPROM driver is not attached" + + if self.sfp_type == 'SFP': + offset = SFP_INFO_OFFSET + elif self.sfp_type == 'QSFP': + offset = QSFP_INFO_OFFSET + elif self.sfp_type == 'QSFP_DD': + offset = QSFP_DD_PAGE0 + + try: + with open(self.eeprom_path, mode="rb", buffering=0) as eeprom: + eeprom.seek(offset) + eeprom.read(1) + except OSError as e: + return "EEPROM read failed ({})".format(e.strerror) + + return self.SFP_STATUS_OK diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/thermal.py index b1dc553d49..280d31c31e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/thermal.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/thermal.py @@ -21,12 +21,12 @@ class Thermal(ThermalBase): # [ Sensor-Name, Sensor-ID ] SENSOR_MAPPING = [ - ['Port Mid', 0x1], - ['NPU Near', 0x2], - ['Port Left', 0x3], - ['Port Right', 0x4], - ['Inlet Airflow Sensor', 0x5], - ['CPU', 0xe], + ['CPU On-board', 0xe], + ['ASIC On-board', 0x2], + ['System Front Left', 0x3], + ['System Front Middle', 0x1], + ['System Front Right', 0x4], + ['Inlet Airflow Sensor', 0x5] ] def __init__(self, thermal_index): @@ -92,7 +92,7 @@ class Thermal(ThermalBase): if not is_valid: temperature = 0 - return "{:.3f}".format(temperature) + return float(temperature) def get_high_threshold(self): """ @@ -105,9 +105,9 @@ class Thermal(ThermalBase): """ is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") if not is_valid: - high_threshold = 0 + return 0.0 - return "{:.3f}".format(high_threshold) + return float(high_threshold) def get_high_critical_threshold(self): """ @@ -120,9 +120,9 @@ class Thermal(ThermalBase): """ is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") if not is_valid: - high_crit_threshold = 0 + return 0.0 - return "{:.3f}".format(high_crit_threshold) + return float(high_crit_threshold) def get_low_threshold(self): """ @@ -137,7 +137,7 @@ class Thermal(ThermalBase): if not is_valid: low_threshold = 0 - return "{:.3f}".format(low_threshold) + return float(low_threshold) def set_high_threshold(self, temperature): """ @@ -166,3 +166,20 @@ class Thermal(ThermalBase): """ # Thermal threshold values are pre-defined based on HW. return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this Thermal is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/watchdog.py index fd3ace8923..317a78e98f 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/watchdog.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5212f/sonic_platform/watchdog.py @@ -13,7 +13,7 @@ try: import ctypes import subprocess import syslog - import sonic_platform.component as Component + import sonic_platform.component as Component from sonic_platform_base.watchdog_base import WatchdogBase except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -48,7 +48,7 @@ class Watchdog(WatchdogBase): stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() - result = stdout.rstrip('\n') + result = stdout.rstrip('\n'.encode()) except OSError: result = None @@ -95,7 +95,7 @@ class Watchdog(WatchdogBase): """ timer_offset = -1 for key,timer_seconds in enumerate(self.TIMERS): - if seconds <= timer_seconds: + if seconds > 0 and seconds <= timer_seconds: timer_offset = key seconds = timer_seconds break @@ -126,18 +126,15 @@ class Watchdog(WatchdogBase): # Last bit = WD Timer punch self._set_reg_val(reg_val & 0xFE) - self.armed_time = self._get_time() - self.timeout = seconds - return seconds else: # Setting 4th bit to enable WD # 4th bit = Enable WD reg_val = self._get_reg_val() self._set_reg_val(reg_val | 0x8) - self.armed_time = self._get_time() - self.timeout = seconds - return seconds + self.armed_time = self._get_time() + self.timeout = seconds + return seconds def disarm(self): """ diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py index 1f85dd80b2..02ebfbc3b7 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/chassis.py @@ -9,6 +9,7 @@ ############################################################################# try: + import os import time import sys from sonic_platform_base.chassis_base import ChassisBase @@ -17,9 +18,8 @@ try: from sonic_platform.component import Component from sonic_platform.psu import Psu from sonic_platform.thermal import Thermal - from sonic_platform.watchdog import Watchdog - from sonic_platform.fan import Fan from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.watchdog import Watchdog from sonic_platform.hwaccess import pci_get_value, pci_set_value except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -56,11 +56,32 @@ class Chassis(ChassisBase): REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi" + pci_res = "/sys/bus/pci/devices/0000:04:00.0/resource0" + + oir_fd = -1 + epoll = -1 + + sysled_offset = 0x0024 + SYSLED_COLOR_TO_REG = { + "blinking_green": 0x0, + "green" : 0x10, + "amber" : 0x20, + "blinking_amber": 0x30 + } + + REG_TO_SYSLED_COLOR = { + 0x0 : "blinking_green", + 0x10 : "green", + 0x20 : "amber", + 0x30 : "blinking_amber" + } _global_port_pres_dict = {} def __init__(self): ChassisBase.__init__(self) + self.STATUS_LED_COLOR_BLUE_BLINK = "blinking blue" + self.STATUS_LED_COLOR_OFF = "off" # sfp.py will read eeprom contents and retrive the eeprom data. # We pass the eeprom path from chassis.py self.PORT_START = 1 @@ -97,11 +118,6 @@ class Chassis(ChassisBase): psu = Psu(i) self._psu_list.append(psu) - for i in range(MAX_S5224F_FANTRAY): - for j in range(MAX_S5224F_FAN): - fan = Fan(i,j) - self._fan_list.append(fan) - for i in range(MAX_S5224F_FANTRAY): fandrawer = FanDrawer(i) self._fan_drawer_list.append(fandrawer) @@ -115,6 +131,52 @@ class Chassis(ChassisBase): else: self._global_port_pres_dict[port_num] = '0' + self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK + self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF + + + def __del__(self): + if self.oir_fd != -1: + self.epoll.unregister(self.oir_fd.fileno()) + self.epoll.close() + self.oir_fd.close() + +# not needed /delete after validation + + def _get_register(self, reg_file): + retval = 'ERR' + if (not os.path.isfile(reg_file)): + print(reg_file, 'not found !') + return retval + + try: + with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd: + retval = fd.read() + except Exception: + pass + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + +# not needed /delete after validation + + def _check_interrupts(self, port_dict): + retval = 0 + is_port_dict_updated = False + for port_num in range(self.PORT_START, (self.PORT_END + 1)): + # sfp get uses zero-indexing, but port numbers start from 1 + sfp = self.get_sfp(port_num-1) + presence = sfp.get_presence() + if(presence and (self._global_port_pres_dict[port_num] == '0')): + is_port_dict_updated = True + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and (self._global_port_pres_dict[port_num] == '1')): + is_port_dict_updated = True + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + return retval, is_port_dict_updated + # check for this event change for sfp / do we need to handle timeout/sleep def get_change_event(self, timeout=0): @@ -167,8 +229,8 @@ class Chassis(ChassisBase): # The index will start from 0 sfp = self._sfp_list[index-1] except IndexError: - sys.stderr.write("SFP index {} out of range (1-{})\n".format( - index, len(self._sfp_list))) + sys.stderr.write("SFP index {} out of range (0-{})\n".format( + index, len(self._sfp_list)-1)) return sfp def get_name(self): @@ -203,6 +265,14 @@ class Chassis(ChassisBase): """ return self._eeprom.serial_str() + def get_revision(self): + """ + Retrieves the revision number of the chassis (Service tag) + Returns: + string: Revision number of chassis + """ + return self._eeprom.revision_str() + def get_status(self): """ Retrieves the operational status of the chassis @@ -263,6 +333,9 @@ class Chassis(ChassisBase): """ return self._num_sfps + def initizalize_system_led(self): + self.sys_ledcolor = "green" + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -276,7 +349,7 @@ class Chassis(ChassisBase): try: with open(self.REBOOT_CAUSE_PATH) as fd: reboot_cause = int(fd.read(), 16) - except EnvironmentError: + except Exception: return (self.REBOOT_CAUSE_NON_HARDWARE, None) if reboot_cause & 0x1: @@ -306,13 +379,10 @@ class Chassis(ChassisBase): def set_locator_led(self, color): """ Sets the state of the Chassis Locator LED - Args: color: A string representing the color with which to set the Chassis Locator LED - Returns: bool: True if the Chassis Locator LED state is set successfully, False if not - """ resource = "/sys/bus/pci/devices/0000:04:00.0/resource0" val = pci_get_value(resource, SYSTEM_LED_REG) @@ -328,7 +398,6 @@ class Chassis(ChassisBase): def get_locator_led(self): """ Gets the state of the Chassis Locator LED - Returns: LOCATOR_LED_ON or LOCATOR_LED_OFF """ @@ -340,3 +409,51 @@ class Chassis(ChassisBase): else: return self.LOCATOR_LED_ON + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def set_status_led(self, color): + """ + Sets the state of the system LED + Args: + color: A string representing the color with which to set the + system LED + Returns: + bool: True if system LED state is set successfully, False if not + """ + if color not in list(self.SYSLED_COLOR_TO_REG.keys()): + return False + + val = pci_get_value(self.pci_res, self.sysled_offset) + val = (val & 0xFFCF) | self.SYSLED_COLOR_TO_REG[color] + + pci_set_value(self.pci_res, val, self.sysled_offset) + self.sys_ledcolor = color + return True + + def get_status_led(self): + """ + Gets the state of the system LED + Returns: + A string, one of the valid LED color strings which could be + vendor specified. + """ + val = pci_get_value(self.pci_res, self.sysled_offset) + if val != -1: + val = val & 0x30 + return self.REG_TO_SYSLED_COLOR.get(val) + return self.sys_ledcolor diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py index 282a323f25..b0dabc1398 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/component.py @@ -19,7 +19,8 @@ except ImportError as e: def get_bios_version(): - return subprocess.check_output(['dmidecode', '-s', 'system-version']).strip() + return subprocess.check_output(['dmidecode', '-s', + 'system-version']).decode('utf-8').strip() def get_fpga_version(): val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:03:00.0/resource0', 0) @@ -28,7 +29,7 @@ def get_fpga_version(): def get_bmc_version(): return subprocess.check_output( ['cat', '/sys/class/ipmi/ipmi0/device/bmc/firmware_revision'] - ).strip() + ).decode('utf-8').strip() def get_cpld_version(bus, i2caddr): return '{}.{}'.format(hwaccess.i2c_get(bus, i2caddr, 1), @@ -111,3 +112,88 @@ class Component(ComponentBase): A boolean, True if install was successful, False if not """ return False + + def get_presence(self): + """ + Retrieves the presence of the component + Returns: + bool: True if present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the part number of the component + Returns: + string: Part number of component + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the component + Returns: + string: Serial number of component + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the component + Returns: + bool: True if component is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether component is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + Note: the firmware version will be read from image + Args: + image_path: A string, path to firmware image + Returns: + A string containing the available firmware version of the component + """ + return "N/A" + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + Args: + image_path: A string, path to firmware image + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return "None" + + def update_firmware(self, image_path): + """ + Updates firmware of the component + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + Args: + image_path: A string, path to firmware image + Raises: + RuntimeError: update failed + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py index 953423bbb6..591f5e1787 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/eeprom.py @@ -11,6 +11,7 @@ try: import os.path from sonic_eeprom import eeprom_tlvinfo + import binascii except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -48,7 +49,7 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): break tlv = eeprom[tlv_index:tlv_index + 2 - + eeprom[tlv_index + 1]] + + eeprom[tlv_index + 1]] code = "0x%02X" % tlv[0] name, value = self.decoder(None, tlv) @@ -69,14 +70,14 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): return "N/A" return results[2].decode('ascii') - def base_mac_addr(self, e): + def base_mac_addr(self, e=None): """ Returns the base mac address found in the system EEPROM """ (is_valid, t) = self.get_tlv_field( self.eeprom_data, self._TLV_CODE_MAC_BASE) if not is_valid or t[1] != 6: - return super(eeprom_tlvinfo.TlvInfoDecoder, self).switchaddrstr(t) + return super(TlvInfoDecoder, self).switchaddrstr(e) return ":".join(["{:02x}".format(T) for T in t[2]]).upper() @@ -122,7 +123,7 @@ class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): if not is_valid: return "N/A" - return results[2].decode('ascii') + return (binascii.b2a_hex(results[2])).decode('ascii') def system_eeprom_info(self): """ diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py index bf248a0384..57e163469a 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan.py @@ -91,10 +91,7 @@ class Fan(FanBase): Returns: String: Part number of FAN """ - if self.is_psu_fan: - return None - else: - return self.fru.get_board_part_number() + return self.fru.get_board_part_number() def get_serial(self): """ @@ -102,10 +99,7 @@ class Fan(FanBase): Returns: String: Serial number of FAN """ - if self.is_psu_fan: - return None - else: - return self.fru.get_board_serial() + return self.fru.get_board_serial() def get_presence(self): """ @@ -132,8 +126,12 @@ class Fan(FanBase): status = False is_valid, state = self.state_sensor.get_reading() if is_valid: - if not state > 1: - status = True + if self.is_psu_fan: + if not state > 1: + status = True + else: + if state == 0x00: + status = True return status def get_direction(self): @@ -183,3 +181,48 @@ class Fan(FanBase): fan_speed = 0 is_valid, fan_speed = self.speed_sensor.get_reading() return fan_speed if is_valid else None + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fanindex + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + if self.get_presence(): + # The tolerance value is fixed as 20% for all the DellEMC platforms + tolerance = 20 + else: + tolerance = 0 + + return tolerance + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by HW + # Return True to avoid thermalctld alarm + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py index 2233a9c73a..c11d5a7cf8 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/fan_drawer.py @@ -11,6 +11,7 @@ try: from sonic_platform_base.fan_drawer_base import FanDrawerBase from sonic_platform.fan import Fan + from sonic_platform.ipmihelper import IpmiFru except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -20,6 +21,8 @@ S5224F_FANS_PER_FANTRAY = 2 class FanDrawer(FanDrawerBase): """DellEMC Platform-specific Fan class""" + FAN_FRU_MAPPING = { 1: 3, 2: 4, 3: 5, 4: 6 } + def __init__(self, fantray_index): FanDrawerBase.__init__(self) @@ -27,6 +30,7 @@ class FanDrawer(FanDrawerBase): self.fantrayindex = fantray_index + 1 for i in range(S5224F_FANS_PER_FANTRAY): self._fan_list.append(Fan(fantray_index, i)) + self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) def get_name(self): """ @@ -35,3 +39,88 @@ class FanDrawer(FanDrawerBase): string: The name of the device """ return "FanTray{}".format(self.fantrayindex) + + + def get_presence(self): + """ + Retrives the presence of the fan drawer + Returns: + bool: True if fan_tray is present, False if not + """ + return self.get_fan(0).get_presence() + + def get_model(self): + """ + Retrieves the part number of the fan drawer + Returns: + string: Part number of fan drawer + """ + return self.fru.get_board_part_number() + + def get_serial(self): + """ + Retrieves the serial number of the fan drawer + Returns: + string: Serial number of the fan drawer + """ + return self.fru.get_board_serial() + + def get_status(self): + """ + Retrieves the operational status of the fan drawer + Returns: + bool: True if fan drawer is operating properly, False if not + """ + status = True + for fan in self.get_all_fans(): + status &= fan.get_status() + return status + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fantrayindex + + def is_replaceable(self): + """ + Indicate whether this fan drawer is replaceable. + Returns: + bool: True if it is replaceable, False if not + """ + return True + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by BMC + # Return True to avoid thermalctld alarm + return True + + def get_status_led(self, color): + """ + Gets the state of the fan drawer LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + # Fan tray status LED controlled by BMC + # Return True to avoid thermalctld alarm + return True + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by Fan Drawer + Returns: + A float, with value of the maximum consumable power of the + component. + """ + return 0.0 diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py index 5e4dafc9b9..3d7cc30a79 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/psu.py @@ -24,11 +24,11 @@ class Psu(PsuBase): SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39, "Power": 0x37, "Voltage": 0x38, "InCurrent": 0x36, "InPower": 0x34, - "InVoltage": 0x35 }, + "InVoltage": 0x35, "Temperature": 0xc }, 2: { "State": 0x32, "Current": 0x3F, "Power": 0x3D, "Voltage": 0x3E, "InCurrent": 0x3C, "InPower": 0x3A, - "InVoltage": 0x3B } } + "InVoltage": 0x3B, "Temperature": 0xd } } # ( PSU-ID: FRU-ID } FRU_MAPPING = { 1: 1, 2: 2 } @@ -44,6 +44,7 @@ class Psu(PsuBase): self.input_voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InVoltage"]) self.input_current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InCurrent"]) self.input_power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InPower"]) + self.temp_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Temperature"]) self.fru = IpmiFru(self.FRU_MAPPING[self.index]) self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, @@ -68,11 +69,36 @@ class Psu(PsuBase): presence = False is_valid, state = self.state_sensor.get_reading() if is_valid: - if (state & 0b1): + if (state == 0x01): presence = True return presence + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celcius up to + nearest thousandth of one degree celcius, e.g. 30.125 + """ + is_valid, temperature = self.temp_sensor.get_reading() + if not is_valid: + temperature = 0 + + return float(temperature) + + def get_temperature_high_threshold(self): + """ + Returns the high temperature threshold for PSU in Celsius + """ + + is_valid, high_threshold = self.temp_sensor.get_threshold("UpperCritical") + if not is_valid: + high_threshold = 105 + high_threshold = "{:.2f}".format(high_threshold) + + return float(high_threshold) + def get_model(self): """ Retrieves the part number of the PSU @@ -91,6 +117,26 @@ class Psu(PsuBase): """ return self.fru.get_board_serial() + def get_revision(self): + """ + Retrives thehardware revision of the device + Returns: + String: revision value of device + """ + serial = self.fru.get_board_serial() + if serial != "NA" and len(serial) == 23: + return serial[-3:] + else: + return "NA" + + def is_replaceable(self): + """ + Indicate whether this PSU is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + def get_status(self): """ Retrieves the operational status of the PSU @@ -116,9 +162,33 @@ class Psu(PsuBase): """ is_valid, voltage = self.voltage_sensor.get_reading() if not is_valid: - return None + return 0.0 - return "{:.1f}".format(voltage) + return float(voltage) + + def get_voltage_low_threshold(self): + """ + Returns PSU low threshold in Volts + """ + + is_valid, low_threshold = self.voltage_sensor.get_threshold("LowerCritical") + if not is_valid: + low_threshold = 11.6 + low_threshold = "{:.2f}".format(low_threshold) + + return float(low_threshold) + + def get_voltage_high_threshold(self): + """ + Returns PSU high threshold in Volts + """ + + is_valid, high_threshold = self.voltage_sensor.get_threshold("UpperCritical") + if not is_valid: + high_threshold = 12.8 + high_threshold = "{:.2f}".format(high_threshold) + + return float(high_threshold) def get_current(self): """ @@ -130,9 +200,9 @@ class Psu(PsuBase): """ is_valid, current = self.current_sensor.get_reading() if not is_valid: - return None + return 0.0 - return "{:.1f}".format(current) + return float(current) def get_power(self): """ @@ -144,9 +214,9 @@ class Psu(PsuBase): """ is_valid, power = self.power_sensor.get_reading() if not is_valid: - return None + return 0.0 - return "{:.1f}".format(power) + return float(power) def get_input_voltage(self): """ @@ -158,9 +228,9 @@ class Psu(PsuBase): """ is_valid, input_voltage = self.input_voltage_sensor.get_reading() if not is_valid: - return None + return 0.0 - return "{:.1f}".format(input_voltage) + return float(input_voltage) def get_input_current(self): """ @@ -172,9 +242,9 @@ class Psu(PsuBase): """ is_valid, input_current = self.input_current_sensor.get_reading() if not is_valid: - return None + return 0.0 - return "{:.1f}".format(input_current) + return float(input_current) def get_input_power(self): """ @@ -188,7 +258,7 @@ class Psu(PsuBase): if not is_valid: return None - return "{:.1f}".format(input_power) + return float(input_power) def get_powergood_status(self): """ @@ -201,7 +271,7 @@ class Psu(PsuBase): status = False is_valid, state = self.state_sensor.get_reading() if is_valid: - if (state == 0x01): + if (state == 0x01): status = True return status @@ -228,3 +298,33 @@ class Psu(PsuBase): if 'AC' in info : return 'AC' if 'DC' in info : return 'DC' return None + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return float(750) + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + # Hardware not supported + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py index e3c3ce02ab..65eca49261 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/sfp.py @@ -19,6 +19,10 @@ try: except ImportError as e: raise ImportError(str(e) + "- required module not found") +QSFP_INFO_OFFSET = 128 +SFP_INFO_OFFSET = 0 +QSFP_DD_PAGE0 = 0 + SFP_TYPE_LIST = [ '0x3' # SFP/SFP+/SFP28 and later ] @@ -39,6 +43,7 @@ class Sfp(SfpOptoeBase): def __init__(self, index, sfp_type, eeprom_path): SfpOptoeBase.__init__(self) + self.port_type = sfp_type self.sfp_type = sfp_type self.port_type = sfp_type self.index = index @@ -92,6 +97,23 @@ class Sfp(SfpOptoeBase): self.set_media_type() self.reinit_sfp_driver() + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + def get_presence(self): """ Retrieves the presence of the sfp @@ -313,3 +335,33 @@ class Sfp(SfpOptoeBase): except IOError as e: print("Error: Unable to open file: %s" % str(e)) return False + + def get_error_description(self): + """ + Retrives the error descriptions of the SFP module + Returns: + String that represents the current error descriptions of vendor specific errors + In case there are multiple errors, they should be joined by '|', + like: "Bad EEPROM|Unsupported cable" + """ + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + else: + if not os.path.isfile(self.eeprom_path): + return "EEPROM driver is not attached" + + if self.sfp_type == 'SFP': + offset = SFP_INFO_OFFSET + elif self.sfp_type == 'QSFP': + offset = QSFP_INFO_OFFSET + elif self.sfp_type == 'QSFP_DD': + offset = QSFP_DD_PAGE0 + + try: + with open(self.eeprom_path, mode="rb", buffering=0) as eeprom: + eeprom.seek(offset) + eeprom.read(1) + except OSError as e: + return "EEPROM read failed ({})".format(e.strerror) + + return self.SFP_STATUS_OK diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py index 6634a6982e..f6c0960265 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/thermal.py @@ -107,7 +107,7 @@ class Thermal(ThermalBase): """ is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") if not is_valid: - return super(Thermal, self).get_high_threshold() + return 0.0 return float(high_threshold) @@ -122,7 +122,7 @@ class Thermal(ThermalBase): """ is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") if not is_valid: - return super(Thermal, self).get_high_critical_threshold() + return 0.0 return float(high_crit_threshold) @@ -168,3 +168,20 @@ class Thermal(ThermalBase): """ # Thermal threshold values are pre-defined based on HW. return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this Thermal is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py index b7e9654656..47c0725949 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py +++ b/platform/broadcom/sonic-platform-modules-dell/s5224f/sonic_platform/watchdog.py @@ -95,7 +95,7 @@ class Watchdog(WatchdogBase): """ timer_offset = -1 for key,timer_seconds in enumerate(self.TIMERS): - if seconds <= timer_seconds: + if seconds > 0 and seconds <= timer_seconds: timer_offset = key seconds = timer_seconds break @@ -126,18 +126,15 @@ class Watchdog(WatchdogBase): # Last bit = WD Timer punch self._set_reg_val(reg_val & 0xFE) - self.armed_time = self._get_time() - self.timeout = seconds - return seconds else: # Setting 4th bit to enable WD # 4th bit = Enable WD reg_val = self._get_reg_val() self._set_reg_val(reg_val | 0x8) - self.armed_time = self._get_time() - self.timeout = seconds - return seconds + self.armed_time = self._get_time() + self.timeout = seconds + return seconds def disarm(self): """