diff --git a/device/accton/x86_64-accton_as5812_54x-r0/installer.conf b/device/accton/x86_64-accton_as5812_54x-r0/installer.conf index 14404194ef..8d06f2acce 100644 --- a/device/accton/x86_64-accton_as5812_54x-r0/installer.conf +++ b/device/accton/x86_64-accton_as5812_54x-r0/installer.conf @@ -1,3 +1,4 @@ CONSOLE_PORT=0x2f8 CONSOLE_DEV=1 CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" diff --git a/device/accton/x86_64-accton_as5812_54x-r0/pcie.yaml b/device/accton/x86_64-accton_as5812_54x-r0/pcie.yaml new file mode 100644 index 0000000000..781d5b7d31 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/pcie.yaml @@ -0,0 +1,88 @@ +- bus: '00' + dev: '00' + fn: '0' + id: 1f0c + name: 'Host bridge: Intel Corporation Atom processor C2000 SoC Transaction Router + (rev 03)' +- bus: '00' + dev: '01' + fn: '0' + id: 1f10 + name: 'PCI bridge: Intel Corporation Atom processor C2000 PCIe Root Port 1 (rev + 03)' +- bus: '00' + dev: '02' + fn: '0' + id: 1f11 + name: 'PCI bridge: Intel Corporation Atom processor C2000 PCIe Root Port 2 (rev + 03)' +- bus: '00' + dev: '03' + fn: '0' + id: 1f12 + name: 'PCI bridge: Intel Corporation Atom processor C2000 PCIe Root Port 3 (rev + 03)' +- bus: '00' + dev: 0e + fn: '0' + id: 1f14 + name: 'Host bridge: Intel Corporation Atom processor C2000 RAS (rev 03)' +- bus: '00' + dev: 0f + fn: '0' + id: 1f16 + name: 'IOMMU: Intel Corporation Atom processor C2000 RCEC (rev 03)' +- bus: '00' + dev: '13' + fn: '0' + id: 1f15 + name: 'System peripheral: Intel Corporation Atom processor C2000 SMBus 2.0 (rev + 03)' +- bus: '00' + dev: '14' + fn: '0' + id: 1f41 + name: 'Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)' +- bus: '00' + dev: '14' + fn: '1' + id: 1f41 + name: 'Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)' +- bus: '00' + dev: '14' + fn: '2' + id: 1f41 + name: 'Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)' +- bus: '00' + dev: '16' + fn: '0' + id: 1f2c + name: 'USB controller: Intel Corporation Atom processor C2000 USB Enhanced Host + Controller (rev 03)' +- bus: '00' + dev: '17' + fn: '0' + id: 1f22 + name: 'SATA controller: Intel Corporation Atom processor C2000 AHCI SATA2 Controller + (rev 03)' +- bus: '00' + dev: '18' + fn: '0' + id: 1f32 + name: 'SATA controller: Intel Corporation Atom processor C2000 AHCI SATA3 Controller + (rev 03)' +- bus: '00' + dev: 1f + fn: '0' + id: 1f38 + name: 'ISA bridge: Intel Corporation Atom processor C2000 PCU (rev 03)' +- bus: '00' + dev: 1f + fn: '3' + id: 1f3c + name: 'SMBus: Intel Corporation Atom processor C2000 PCU SMBus (rev 03)' +- bus: '01' + dev: '00' + fn: '0' + id: b864 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b864 (rev 02)' diff --git a/device/accton/x86_64-accton_as5812_54x-r0/platform.json b/device/accton/x86_64-accton_as5812_54x-r0/platform.json new file mode 100644 index 0000000000..6fbb204e3c --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/platform.json @@ -0,0 +1,908 @@ +{ + "chassis": { + "name": "5812-54X", + "status_led": { + "controllable": true, + "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] + }, + "thermal_manager":false, + "components": [ + { + "name": "MB_CPLD1" + }, + { + "name": "MB_CPLD2" + }, + { + "name": "MB_CPLD3" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "FAN-1F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-1R", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2R", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3R", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-4F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-4R", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-5F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-5R", + "status_led": { + "controllable": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-1F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-1R", + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray2", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-2F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2R", + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray3", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-3F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3R", + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray4", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-4F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-4R", + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray5", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-5F", + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-5R", + "status_led": { + "controllable": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU-1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-1 FAN-1", + "status_led": { + "controllable": false + } + } + ], + "thermals": [ + { + "name": "PSU-1 temp sensor 1", + "controllable": false, + "low-threshold": false, + "high-threshold": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "temperature": true, + "temperature_high_threshold": true + }, + { + "name": "PSU-2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-2 FAN-1", + "status_led": { + "controllable": false + } + } + ], + "thermals": [ + { + "name": "PSU-2 temp sensor 1", + "controllable": false, + "low-threshold": false, + "high-threshold": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "temperature": true, + "temperature_high_threshold": true + } + ], + "thermals": [ + { + "name": "MB_FrontMiddle_temp(0x48)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_RearRight_temp(0x49)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_FrontRight_temp(0x4A)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CPU_Core_0_temp", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CPU_Core_1_temp", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CPU_Core_2_temp", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CPU_Core_3_temp", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "sfps": [ + { + "name": "Ethernet0" + }, + { + "name": "Ethernet1" + }, + { + "name": "Ethernet2" + }, + { + "name": "Ethernet3" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet5" + }, + { + "name": "Ethernet6" + }, + { + "name": "Ethernet7" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet9" + }, + { + "name": "Ethernet10" + }, + { + "name": "Ethernet11" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet13" + }, + { + "name": "Ethernet14" + }, + { + "name": "Ethernet15" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet17" + }, + { + "name": "Ethernet18" + }, + { + "name": "Ethernet19" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet21" + }, + { + "name": "Ethernet22" + }, + { + "name": "Ethernet23" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet25" + }, + { + "name": "Ethernet26" + }, + { + "name": "Ethernet27" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet29" + }, + { + "name": "Ethernet30" + }, + { + "name": "Ethernet31" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet33" + }, + { + "name": "Ethernet34" + }, + { + "name": "Ethernet35" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet37" + }, + { + "name": "Ethernet38" + }, + { + "name": "Ethernet39" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet41" + }, + { + "name": "Ethernet42" + }, + { + "name": "Ethernet43" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet45" + }, + { + "name": "Ethernet46" + }, + { + "name": "Ethernet47" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet56" + }, + { + "name": "Ethernet60" + }, + { + "name": "Ethernet64" + }, + { + "name": "Ethernet68" + } + ] + }, + "interfaces": { + "Ethernet0": { + "index": "1", + "lanes": "13", + "breakout_modes": { + "1x10G[1G]": ["Eth1(Port1)"] + } + }, + + "Ethernet1": { + "index": "2", + "lanes": "14", + "breakout_modes": { + "1x10G[1G]": ["Eth2(Port2)"] + } + }, + + "Ethernet2": { + "index": "3", + "lanes": "15", + "breakout_modes": { + "1x10G[1G]": ["Eth3(Port3)"] + } + }, + + "Ethernet3": { + "index": "4", + "lanes": "16", + "breakout_modes": { + "1x10G[1G]": ["Eth4(Port4)"] + } + }, + + "Ethernet4": { + "index": "5", + "lanes": "21", + "breakout_modes": { + "1x10G[1G]": ["Eth5(Port5)"] + } + }, + + "Ethernet5": { + "index": "6", + "lanes": "22", + "breakout_modes": { + "1x10G[1G]": ["Eth6(Port6)"] + } + }, + + "Ethernet6": { + "index": "7", + "lanes": "23", + "breakout_modes": { + "1x10G[1G]": ["Eth7(Port7)"] + } + }, + + "Ethernet7": { + "index": "8", + "lanes": "24", + "breakout_modes": { + "1x10G[1G]": ["Eth8(Port8)"] + } + }, + + "Ethernet8": { + "index": "9", + "lanes": "25", + "breakout_modes": { + "1x10G[1G]": ["Eth9(Port9)"] + } + }, + + "Ethernet9": { + "index": "10", + "lanes": "26", + "breakout_modes": { + "1x10G[1G]": ["Eth10(Port10)"] + } + }, + + "Ethernet10": { + "index": "11", + "lanes": "27", + "breakout_modes": { + "1x10G[1G]": ["Eth11(Port11)"] + } + }, + + "Ethernet11": { + "index": "12", + "lanes": "28", + "breakout_modes": { + "1x10G[1G]": ["Eth12(Port12)"] + } + }, + + "Ethernet12": { + "index": "13", + "lanes": "29", + "breakout_modes": { + "1x10G[1G]": ["Eth13(Port13)"] + } + }, + + "Ethernet13": { + "index": "14", + "lanes": "30", + "breakout_modes": { + "1x10G[1G]": ["Eth14(Port14)"] + } + }, + + "Ethernet14": { + "index": "15", + "lanes": "31", + "breakout_modes": { + "1x10G[1G]": ["Eth15(Port15)"] + } + }, + + "Ethernet15": { + "index": "16", + "lanes": "32", + "breakout_modes": { + "1x10G[1G]": ["Eth16(Port16)"] + } + }, + + "Ethernet16": { + "index": "17", + "lanes": "45", + "breakout_modes": { + "1x10G[1G]": ["Eth17(Port17)"] + } + }, + + "Ethernet17": { + "index": "18", + "lanes": "46", + "breakout_modes": { + "1x10G[1G]": ["Eth18(Port18)"] + } + }, + + "Ethernet18": { + "index": "19", + "lanes": "47", + "breakout_modes": { + "1x10G[1G]": ["Eth19(Port19)"] + } + }, + + "Ethernet19": { + "index": "20", + "lanes": "48", + "breakout_modes": { + "1x10G[1G]": ["Eth20(Port20)"] + } + }, + + "Ethernet20": { + "index": "21", + "lanes": "49", + "breakout_modes": { + "1x10G[1G]": ["Eth21(Port21)"] + } + }, + + "Ethernet21": { + "index": "22", + "lanes": "50", + "breakout_modes": { + "1x10G[1G]": ["Eth22(Port22)"] + } + }, + + "Ethernet22": { + "index": "23", + "lanes": "51", + "breakout_modes": { + "1x10G[1G]": ["Eth23(Port23)"] + } + }, + + "Ethernet23": { + "index": "24", + "lanes": "52", + "breakout_modes": { + "1x10G[1G]": ["Eth24(Port24)"] + } + }, + + "Ethernet24": { + "index": "25", + "lanes": "53", + "breakout_modes": { + "1x10G[1G]": ["Eth25(Port25)"] + } + }, + + "Ethernet25": { + "index": "26", + "lanes": "54", + "breakout_modes": { + "1x10G[1G]": ["Eth26(Port26)"] + } + }, + + "Ethernet26": { + "index": "27", + "lanes": "55", + "breakout_modes": { + "1x10G[1G]": ["Eth27(Port27)"] + } + }, + + "Ethernet27": { + "index": "28", + "lanes": "56", + "breakout_modes": { + "1x10G[1G]": ["Eth28(Port28)"] + } + }, + + "Ethernet28": { + "index": "29", + "lanes": "57", + "breakout_modes": { + "1x10G[1G]": ["Eth29(Port29)"] + } + }, + + "Ethernet29": { + "index": "30", + "lanes": "58", + "breakout_modes": { + "1x10G[1G]": ["Eth30(Port30)"] + } + }, + + "Ethernet30": { + "index": "31", + "lanes": "59", + "breakout_modes": { + "1x10G[1G]": ["Eth31(Port31)"] + } + }, + + "Ethernet31": { + "index": "32", + "lanes": "60", + "breakout_modes": { + "1x10G[1G]": ["Eth32(Port32)"] + } + }, + + "Ethernet32": { + "index": "33", + "lanes": "61", + "breakout_modes": { + "1x10G[1G]": ["Eth33(Port33)"] + } + }, + + "Ethernet33": { + "index": "34", + "lanes": "62", + "breakout_modes": { + "1x10G[1G]": ["Eth34(Port34)"] + } + }, + + "Ethernet34": { + "index": "35", + "lanes": "63", + "breakout_modes": { + "1x10G[1G]": ["Eth35(Port35)"] + } + }, + + "Ethernet35": { + "index": "36", + "lanes": "64", + "breakout_modes": { + "1x10G[1G]": ["Eth36(Port36)"] + } + }, + + "Ethernet36": { + "index": "37", + "lanes": "65", + "breakout_modes": { + "1x10G[1G]": ["Eth37(Port37)"] + } + }, + + "Ethernet37": { + "index": "38", + "lanes": "66", + "breakout_modes": { + "1x10G[1G]": ["Eth38(Port38)"] + } + }, + + "Ethernet38": { + "index": "39", + "lanes": "67", + "breakout_modes": { + "1x10G[1G]": ["Eth39(Port39)"] + } + }, + + "Ethernet39": { + "index": "40", + "lanes": "68", + "breakout_modes": { + "1x10G[1G]": ["Eth40(Port40)"] + } + }, + + "Ethernet40": { + "index": "41", + "lanes": "69", + "breakout_modes": { + "1x10G[1G]": ["Eth41(Port41)"] + } + }, + + "Ethernet41": { + "index": "42", + "lanes": "70", + "breakout_modes": { + "1x10G[1G]": ["Eth42(Port42)"] + } + }, + + "Ethernet42": { + "index": "43", + "lanes": "71", + "breakout_modes": { + "1x10G[1G]": ["Eth43(Port43)"] + } + }, + + "Ethernet43": { + "index": "44", + "lanes": "72", + "breakout_modes": { + "1x10G[1G]": ["Eth44(Port44)"] + } + }, + + "Ethernet44": { + "index": "45", + "lanes": "73", + "breakout_modes": { + "1x10G[1G]": ["Eth45(Port45)"] + } + }, + + "Ethernet45": { + "index": "46", + "lanes": "74", + "breakout_modes": { + "1x10G[1G]": ["Eth46(Port46)"] + } + }, + + "Ethernet46": { + "index": "47", + "lanes": "75", + "breakout_modes": { + "1x10G[1G]": ["Eth47(Port47)"] + } + }, + + "Ethernet47": { + "index": "48", + "lanes": "76", + "breakout_modes": { + "1x10G[1G]": ["Eth48(Port48)"] + } + }, + + "Ethernet48": { + "index": "49,49,49,49", + "lanes": "97,98,99,100", + "breakout_modes": { + "1x40G": ["Eth49(Port49)"], + "4x10G": ["Eth49/1(Port49)", "Eth49/2(Port49)", "Eth49/3(Port49)", "Eth49/4(Port49)"] + } + }, + + "Ethernet52": { + "index": "50,50,50,50", + "lanes": "101,102,103,104", + "breakout_modes": { + "1x40G": ["Eth50(Port50)"], + "4x10G": ["Eth50/1(Port50)", "Eth50/2(Port50)", "Eth50/3(Port50)", "Eth50/4(Port50)"] + } + }, + + "Ethernet56": { + "index": "51,51,51,51", + "lanes": "81,82,83,84", + "breakout_modes": { + "1x40G": ["Eth51(Port51)"], + "4x10G": ["Eth51/1(Port51)", "Eth51/2(Port51)", "Eth51/3(Port51)", "Eth51/4(Port51)"] + } + }, + + "Ethernet60": { + "index": "52,52,52,52", + "lanes": "105,106,107,108", + "breakout_modes": { + "1x40G": ["Eth52(Port52)"], + "4x10G": ["Eth52/1(Port52)", "Eth52/2(Port52)", "Eth52/3(Port52)", "Eth52/4(Port52)"] + } + }, + + "Ethernet64": { + "index": "53,53,53,53", + "lanes": "109,110,111,112", + "breakout_modes": { + "1x40G": ["Eth53(Port53)"], + "4x10G": ["Eth53/1(Port53)", "Eth53/2(Port53)", "Eth53/3(Port53)", "Eth53/4(Port53)"] + } + }, + + "Ethernet68": { + "index": "54,54,54,54", + "lanes": "77,78,79,80", + "breakout_modes": { + "1x40G": ["Eth54(Port54)"], + "4x10G": ["Eth54/1(Port54)", "Eth54/2(Port54)", "Eth54/3(Port54)", "Eth54/4(Port54)"] + } + } + } +} diff --git a/device/accton/x86_64-accton_as5812_54x-r0/platform_components.json b/device/accton/x86_64-accton_as5812_54x-r0/platform_components.json new file mode 100644 index 0000000000..ce7f8510bf --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/platform_components.json @@ -0,0 +1,12 @@ +{ + "chassis": { + "5812-54X-O-AC-F": { + "component": { + "MB_CPLD1": { }, + "MB_CPLD2": { }, + "MB_CPLD3": { }, + "BIOS": { } + } + } + } +} diff --git a/device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py old mode 100644 new mode 100755 diff --git a/device/accton/x86_64-accton_as5812_54x-r0/plugins/ssd_util.py b/device/accton/x86_64-accton_as5812_54x-r0/plugins/ssd_util.py new file mode 100755 index 0000000000..4b173c5e38 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/plugins/ssd_util.py @@ -0,0 +1,24 @@ +# ssd_util.py +# +# Platform-specific SSD interface for SONiC +## + +try: + from sonic_platform_base.sonic_ssd.ssd_generic import SsdUtil as MainSsdUtil +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +NOT_AVAILABLE = "N/A" + +class SsdUtil(MainSsdUtil): + """Platform-specific SsdUtil class""" + + def __init__(self, diskdev): + super(SsdUtil, self).__init__(diskdev) + + # If it has no vendor tool to read SSD information, + # ssd_util.py will use generic SSD information + # for vendor SSD information. + if self.vendor_ssd_info == NOT_AVAILABLE: + self.vendor_ssd_info = self.ssd_info + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json index 584a14b9d9..44bad64942 100644 --- a/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as5812_54x-r0/pmon_daemon_control.json @@ -1,5 +1,4 @@ { - "skip_ledd": true, - "skip_thermalctld": true + "skip_ledd": true } diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sensors.conf b/device/accton/x86_64-accton_as5812_54x-r0/sensors.conf index 73038a4131..1bbff6badd 100644 --- a/device/accton/x86_64-accton_as5812_54x-r0/sensors.conf +++ b/device/accton/x86_64-accton_as5812_54x-r0/sensors.conf @@ -9,23 +9,23 @@ bus "i2c-62" "i2c-0-mux (chan_id 6)" bus "i2c-63" "i2c-0-mux (chan_id 7)" chip "as5812_54x_fan-*" - label fan1 "Fan 1 Front" - label fan2 "Fan 2 Front" - label fan3 "Fan 3 Front" - label fan4 "Fan 4 Front" - label fan5 "Fan 5 Front" - label fan11 "Fan 1 Rear" - label fan12 "Fan 2 Rear" - label fan13 "Fan 3 Rear" - label fan14 "Fan 4 Rear" - label fan15 "Fan 5 Rear" + label fan1 "FanTray1 Front" + label fan2 "FanTray2 Front" + label fan3 "FanTray3 Front" + label fan4 "FanTray4 Front" + label fan5 "FanTray5 Front" + label fan11 "Fantray1 Rear" + label fan12 "Fantray2 Rear" + label fan13 "Fantray3 Rear" + label fan14 "Fantray4 Rear" + label fan15 "Fantray5 Rear" chip "lm75-i2c-*-48" - label temp1 "Main Board Temperature" + label temp1 "MB_FrontMiddle_temp" chip "lm75-i2c-*-49" - label temp1 "Main Board Temperature" + label temp1 "MB_RearRight_temp" chip "lm75-i2c-*-4a" - label temp1 "Main Board Temperature" + label temp1 "MB_FrontRight_temp" diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/__init__.py new file mode 100644 index 0000000000..73a7720e89 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ] +from . import platform diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/chassis.py new file mode 100644 index 0000000000..0110babfbf --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/chassis.py @@ -0,0 +1,275 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os +import sys + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 5 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 7 +PORT_END = 54 +QSFP_PORT_START = 49 +QSFP_PORT_END = 54 +NUM_COMPONENT = 4 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = ["docker"] + +SYSLED_FNODE= "/sys/class/leds/accton_as5812_54x_led::diag/brightness" + +SYSLED_MODES = { + "0" : "STATUS_LED_COLOR_OFF", + "1" : "STATUS_LED_COLOR_GREEN", + "2" : "STATUS_LED_COLOR_AMBER" +} + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + self.QSFP_PORT_START = QSFP_PORT_START + self.QSFP_PORT_END = QSFP_PORT_END + for index in range(0, PORT_END): + if index in range(self.QSFP_PORT_START-1, self.QSFP_PORT_END): + sfp_module = Sfp(index, 'QSFP') + else: + sfp_module = Sfp(index, 'SFP') + self._sfp_list.append(sfp_module) + + self._sfpevent = SfpEvent(self._sfp_list) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __initialize_watchdog(self): + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + + def __is_host(self): + try: + status, output = getstatusoutput_noshell(HOST_CHK_CMD) + return status == 0 + except Exception: + return False + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._eeprom.get_product_name() + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.get_mac() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.get_eeprom() + + def get_revision(self): + return self._eeprom.get_revision() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_port_or_cage_type(self, port): + from sonic_platform_base.sfp_base import SfpBase + if port in range(1, 49): + return SfpBase.SFP_PORT_TYPE_BIT_SFP | SfpBase.SFP_PORT_TYPE_BIT_SFP_PLUS + else: + return SfpBase.SFP_PORT_TYPE_BIT_QSFP | SfpBase.SFP_PORT_TYPE_BIT_QSFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_QSFP28 + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + 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 this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + + def initizalize_system_led(self): + return True + + def get_status_led(self): + val = self._api_helper.read_txt_file(SYSLED_FNODE) + return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN" + + def set_status_led(self, color): + mode = None + for key, val in SYSLED_MODES.items(): + if val == color: + mode = key + break + if mode is None: + return False + else: + return self._api_helper.write_txt_file(SYSLED_FNODE, mode) + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/component.py new file mode 100644 index 0000000000..4e41595993 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/component.py @@ -0,0 +1,187 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import subprocess + + +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "MB_CPLD1": "0-0060", + "MB_CPLD2": "0-0061", + "MB_CPLD3": "0-0062", +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("MB_CPLD1", "Mainboard CPLD(0x60)"), + ("MB_CPLD2", "Mainboard CPLD(0x61)"), + ("MB_CPLD3", "Mainboard CPLD(0x62)"), + ("BIOS", "Basic Input/Output System") + +] +COMPONENT_DES_LIST = ["CPLD","Basic Input/Output System"] + + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + print('Get exception when read bios') + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + try: + cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version') + cpld_version_raw= self._api_helper.read_txt_file(cpld_path) + cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,10)) + except Exception as e: + print('Get exception when read cpld') + cpld_version[cpld_name] = 'None' + + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + ret = subprocess.call(["tar", "-C", "/tmp", "-xzvf", image_path] ) + + if ret == 0 and os.path.exists("/tmp/afulnx_64") and os.path.exists("/tmp/cpldupd") and os.path.exists("/tmp/run_install.sh") : + ret = 0 + else : + print("Installation failed without fwutil tool") + ret = 1 + if ret == 0 and os.path.exists("/tmp/install.json") : + ret = 0 + input_file = open ('/tmp/install.json') + json_array = json.load(input_file) + for item in json_array: + if self.name == item['id'] : + real_path = item['path'] + print( "Find ", self.name, real_path ) + else : + print("Installation failed without jsonfile") + ret = 1 + if ret == 1 : + return False + else : + #cmd = "{}{}{}{}".format('/tmp/run_install.sh ', self.name, ' ', image_path) + ret = subprocess.call(["/tmp/run_install.sh", self.name, real_path]) + if ret == 0 : + return True + return False + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + 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 this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/eeprom.py new file mode 100644 index 0000000000..3d7999053e --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/eeprom.py @@ -0,0 +1,138 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +NULL = 'N/A' + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)(.+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) + + def get_product_name(self): + return self._eeprom.get('0x21', NULL) + + def get_revision(self): + return self._eeprom.get('0x27', NULL) + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/event.py new file mode 100644 index 0000000000..eb27a24ba6 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/event.py @@ -0,0 +1,111 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger + from .sfp import Sfp +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +# SFP errors that will block eeprom accessing +SFP_BLOCKING_ERRORS = [ + Sfp.SFP_ERROR_BIT_I2C_STUCK, + Sfp.SFP_ERROR_BIT_BAD_EEPROM, + Sfp.SFP_ERROR_BIT_UNSUPPORTED_CABLE, + Sfp.SFP_ERROR_BIT_HIGH_TEMP, + Sfp.SFP_ERROR_BIT_BAD_CABLE + ] + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.port_num-1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.port_num-1 + if (changed_ports & (1 << i)): + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + sfp.refresh_optoe_dev_class() + sfp_state_bits = self.get_sfp_state_bits(sfp, True) + sfp_state_bits = self.check_sfp_blocking_errors(sfp_state_bits) + port_dict[i+1] = str(sfp_state_bits) + + + # Update the cache dict + self._sfp_change_event_data['present'] = bitmap + return True, change_dict + else: + return True, change_dict + + def get_sfp_state_bits(self, sfp, present): + sfp_state_bits = 0 + + if present is True: + sfp_state_bits |= Sfp.SFP_STATUS_BIT_INSERTED + else: + return sfp_state_bits + + status = sfp.validate_eeprom() + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + elif status is not True: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BAD_EEPROM + return sfp_state_bits + + status = sfp.validate_temperature() + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + elif status is not True: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_HIGH_TEMP + return sfp_state_bits + + return sfp_state_bits + + def check_sfp_blocking_errors(self, sfp_state_bits): + for i in SFP_BLOCKING_ERRORS: + if (i & sfp_state_bits) == 0: + continue + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BLOCKING + + return sfp_state_bits + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan.py new file mode 100644 index 0000000000..9f48a5bfd0 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan.py @@ -0,0 +1,299 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +import logging + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +SPEED_TOLERANCE = 15 +CPLD_FAN_PATH = "/sys/bus/platform/devices/as5812_54x_fan/fan" +I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "3c" + }, + 1: { + "num": 58, + "addr": "3f" + }, +} + + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "38" + }, + 1: { + "num": 58, + "addr": "3b" + }, +} + + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", + "FAN-5F", "FAN-5R"] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self._api_helper=APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + #logging.debug('fan_index=%d, fan_tray_index=%d, is_psu_fan=%d',fan_tray_index, fan_index, is_psu_fan) + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] + self.psu_hwmon_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr'] + self.psu_cpld_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + FanBase.__init__(self) + + logging.basicConfig(level=logging.DEBUG) + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + + + if not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_direction') + val=self._api_helper.read_txt_file(dir_str) + if val is not None: + if int(val, 10)==0: + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + else: #For PSU + psu_path = "{}{}".format(self.psu_cpld_path, 'psu_power_good') + val = self._api_helper.read_txt_file(psu_path) + if val is None or int(val, 10)==0: + return self.FAN_DIRECTION_NOT_APPLICABLE + + dir_str = "{}{}".format(self.psu_hwmon_path,'psu_fan_dir') + + val=self._api_helper.read_txt_file(dir_str) + #logging.debug('dir_str=%s, val=%s', dir_str, val) + if val is not None: + if val=='F2B': + direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST + + return direction + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm,10))*100/26688 + if speed > 100: + speed=100 + else: + return 0 + elif self.get_presence(): + speed_path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_duty_cycle_percentage') + speed=self._api_helper.read_txt_file(speed_path) + if speed is None: + return 0 + + return int(speed) + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + return self.get_speed() + + 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 + """ + return SPEED_TOLERANCE + + def set_speed(self, speed): + """ + Sets the fan speed + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + A boolean, True if speed is set successfully, False if not + + """ + + if not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_duty_cycle_percentage') + return self._api_helper.write_txt_file(speed_path, int(speed)) + + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_status() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + True: self.STATUS_LED_COLOR_GREEN, + False: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return fan_name + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + if self.is_psu_fan: + present_path="{}{}".format(self.psu_cpld_path, 'psu_present') + else: + present_path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_speed_rpm') + + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)!=0 + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + psu_path = "{}{}".format(self.psu_cpld_path, 'psu_power_good') + val = self._api_helper.read_txt_file(psu_path) + if val is None or int(val, 10)==0: + return False + + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10)==0 + else: + return False + else: + path = "{}{}{}".format(CPLD_FAN_PATH, self.fan_tray_index+1, '_fault') + val=self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10)==0 + else: + return False + + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..260a052dbc --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,101 @@ +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 0-based in platforms + self.fantrayindex = fantray_index + self.__initialize_fan_drawer() + + + def __initialize_fan_drawer(self): + from sonic_platform.fan import Fan + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex+1) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fantrayindex+1) + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/helper.py new file mode 100644 index 0000000000..d193418b3d --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/helper.py @@ -0,0 +1,322 @@ +import struct +import json +import fcntl +from mmap import * +from sonic_py_common import device_info +from sonic_py_common import logger +from threading import Lock +from typing import cast +from sonic_py_common.general import getstatusoutput_noshell +from sonic_py_common.general import getstatusoutput_noshell_pipe + +HOST_CHK_CMD = ["docker"] +EMPTY_STRING = "" + + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + try: + status, output = getstatusoutput_noshell(HOST_CHK_CMD) + return status == 0 + except Exception: + return False + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + ret = data.strip() + if len(ret) > 0: + return ret + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + +class FileLock: + + def __init__(self, lock_file): + self._lock_file = lock_file + self._thread_lock = Lock() + self.is_locked = False + + def acquire(self): + with self._thread_lock: + if self.is_locked: + return + + fd = os.open(self._lock_file, flags=(os.O_RDWR | os.O_CREAT | os.O_TRUNC)) + fcntl.flock(fd, fcntl.LOCK_EX) + self._lock_file_fd = fd + self.is_locked = True + + def release(self): + with self._thread_lock: + if self.is_locked: + fd = cast(int, self._lock_file_fd) + self._lock_file_fd = None + fcntl.flock(fd, fcntl.LOCK_UN) + os.close(fd) + self.is_locked = False + + def __enter__(self): + self.acquire() + return self + + def __exit__(self, exc_type, exc_val, traceback): + self.release() + + def __del__(self): + self.release() + + + +DEVICE_THRESHOLD_JSON_PATH = "/tmp/device_threshold.json" +HIGH_THRESHOLD_FIELD = 'high_threshold' +LOW_THRESHOLD_FIELD = 'low_threshold' +HIGH_CRIT_THRESHOLD_FIELD = 'high_critical_threshold' +LOW_CRIT_THRESHOLD_FIELD = 'low_critical_threshold' +NOT_AVAILABLE = 'N/A' + +class DeviceThreshold: + + def __init__(self, th_name = NOT_AVAILABLE): + self.flock = FileLock("{}.lock".format(DEVICE_THRESHOLD_JSON_PATH)) + self.name = th_name + self.__log = logger.Logger(log_identifier="DeviceThreshold") + + self.__db_data = {} + try: + with self.flock: + with open(DEVICE_THRESHOLD_JSON_PATH, "r") as db_file: + self.__db_data = json.load(db_file) + except Exception as e: + self.__log.log_warning('{}'.format(str(e))) + + @property + def HIGH_THRESHOLD_FIELD(self): + return HIGH_THRESHOLD_FIELD + + @property + def LOW_THRESHOLD_FIELD(self): + return LOW_THRESHOLD_FIELD + + @property + def HIGH_CRIT_THRESHOLD_FIELD(self): + return HIGH_CRIT_THRESHOLD_FIELD + + @property + def LOW_CRIT_THRESHOLD_FIELD(self): + return LOW_CRIT_THRESHOLD_FIELD + + @property + def NOT_AVAILABLE(self): + return NOT_AVAILABLE + + def __get_data(self, field): + """ + Retrieves data frome JSON file by field + + Args : + field: String + + Returns: + A string if getting is successfully, 'N/A' if not + """ + if self.name not in self.__db_data.keys(): + return NOT_AVAILABLE + + if field not in self.__db_data[self.name].keys(): + return NOT_AVAILABLE + + return self.__db_data[self.name][field] + + def __set_data(self, field, new_val): + """ + Set data to JSON file by field + + Args : + field: String + new_val: String + + Returns: + A boolean, True if setting is set successfully, False if not + """ + if self.name not in self.__db_data.keys(): + self.__db_data[self.name] = {} + + old_val = self.__db_data[self.name].get(field, None) + if old_val is not None and old_val == new_val: + return True + + self.__db_data[self.name][field] = new_val + + try: + with self.flock: + db_data = {} + mode = "w+" + if os.path.exists(DEVICE_THRESHOLD_JSON_PATH): + mode = "r+" + with open(DEVICE_THRESHOLD_JSON_PATH, mode) as db_file: + if mode == "r+": + db_data = json.load(db_file) + + if self.name not in db_data.keys(): + db_data[self.name] = {} + + db_data[self.name][field] = new_val + + if mode == "r+": + db_file.seek(0) + # erase old data + db_file.truncate(0) + # write all data + json.dump(db_data, db_file, indent=4) + except Exception as e: + self.__log.log_error('{}'.format(str(e))) + return False + + return True + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature from JSON file. + + Returns: + string : the high threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(HIGH_THRESHOLD_FIELD) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(HIGH_THRESHOLD_FIELD, temperature) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature from JSON file. + + Returns: + string : the low threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(LOW_THRESHOLD_FIELD) + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(LOW_THRESHOLD_FIELD, temperature) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature from JSON file. + + Returns: + string : the high critical threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(HIGH_CRIT_THRESHOLD_FIELD) + + def set_high_critical_threshold(self, temperature): + """ + Sets the high critical threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(HIGH_CRIT_THRESHOLD_FIELD, temperature) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature from JSON file. + + Returns: + string : the low critical threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(LOW_CRIT_THRESHOLD_FIELD) + + def set_low_critical_threshold(self, temperature): + """ + Sets the low critical threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(LOW_CRIT_THRESHOLD_FIELD, temperature) + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/pcie.py new file mode 100644 index 0000000000..0fbb5dc318 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/pcie.py @@ -0,0 +1,18 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# Base PCIe class +############################################################################# +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Pcie(PcieUtil): + """Edgecore Platform-specific PCIe class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/platform.py new file mode 100644 index 0000000000..2f2c2a447f --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/psu.py new file mode 100644 index 0000000000..c39ea2e016 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/psu.py @@ -0,0 +1,301 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.thermal import Thermal + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/" + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "3c" + }, + 1: { + "num": 58, + "addr": "3f" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": [57, 57], + "addr": ["38", "50"] + }, + 1: { + "num": [58, 58], + "addr": ["3b", "50"] + }, +} + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self.index = psu_index + self._api_helper = APIHelper() + + self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.cpld_path = [] + value = PSU_CPLD_I2C_MAPPING[self.index] + for self.i2c_num, self.i2c_addr in zip(value["num"], value["addr"]): + self.cpld_path.append(I2C_PATH.format(self.i2c_num, self.i2c_addr)) + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index)) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + if self.get_status() is not True: + return 0 + + vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: + return 0 + + def get_revision(self): + if not self.get_status(): + return "N/A" + + rev_path = "{}{}".format(self.hwmon_path, 'psu_revision') + rev_val = self._api_helper.read_txt_file(rev_path) + if rev_val is not None: + return rev_val + else: + return "N/A" + + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + if self.get_status() is not True: + return 0 + + iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + if self.get_status() is not True: + return 0 + + pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() + + 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 + """ + + return False #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status=self.get_status() + if status is None: + return self.STATUS_LED_COLOR_OFF + + return { + 1: self.STATUS_LED_COLOR_GREEN, + 0: self.STATUS_LED_COLOR_RED + }.get(status, self.STATUS_LED_COLOR_OFF) + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return self._thermal_list[0].get_high_threshold() + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + return 14.72 + + 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 7.68 + + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + for cpld_path in self.cpld_path: + presence_path="{}{}".format(cpld_path, 'psu_present') + val=self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + for cpld_path in self.cpld_path: + power_path="{}{}".format(cpld_path, 'psu_power_good') + val=self._api_helper.read_txt_file(power_path) + if val is not None: + return int(val, 10) == 1 + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + for cpld_path in self.cpld_path: + model_path="{}{}".format(cpld_path, 'psu_model_name') + model=self._api_helper.read_txt_file(model_path) + + if model is not None: + return model + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + for cpld_path in self.cpld_path: + serial_path="{}{}".format(cpld_path, 'psu_serial_number') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is not None: + return serial + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_maximun_supplied_power(self): + """ + Retrieves maximun supplied power by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + pout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_p_out_max') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/sfp.py new file mode 100644 index 0000000000..e7554be936 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/sfp.py @@ -0,0 +1,700 @@ +############################################################################# +# Edgecore +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import sys +import time +import struct + +from ctypes import create_string_buffer + +try: + import natsort + from sonic_py_common.logger import Logger + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions + +CPLD2_I2C_PATH = "/sys/bus/i2c/devices/0-0061/" +CPLD3_I2C_PATH = "/sys/bus/i2c/devices/0-0062/" + +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 + +QSFP_CONTROL_WIDTH = 8 +QSFP_CONTROL_OFFSET = 86 + + +QSFP_POWEROVERRIDE_OFFSET = 93 + + + +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/{0}-0050/eeprom' +OPTOE_DEV_CLASS_PATH = '/sys/bus/i2c/devices/{0}-0050/dev_class' + +logger = Logger() +class Sfp(SfpOptoeBase): + """Platform-specific Sfp class""" + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + PLATFORM = "x86_64-accton_as5812_54x-r0" + HWSKU = "Accton-AS5812-54X" + + PORT_START = 1 + PORT_END = 54 + QSFP_PORT_START = 49 + QSFP_PORT_END = 54 + + UPDATE_DONE = "Done" + EEPROM_DATA_NOT_READY = "eeprom not ready" + UNKNOWN_SFP_TYPE_ID = "unknow sfp ID" + + + + SFP_TYPE_CODE_LIST = [ + 0x03, # SFP/SFP+/SFP28 + 0x0b # DWDM-SFP/SFP+ + ] + QSFP_TYPE_CODE_LIST = [ + 0x0c, # QSFP + 0x0d, # QSFP+ or later + 0x11, # QSFP28 or later + 0xe1 # QSFP28 EDFA + ] + QSFP_DD_TYPE_CODE_LIST = [ + 0x18, # QSFP-DD Double Density 8X Pluggable Transceiver + 0x1E # QSFP+ or later with CMIS + ] + OSFP_TYPE_CODE_LIST = [ + 0x19 # OSFP + ] + + + + SFP_TYPE = "SFP" + QSFP_TYPE = "QSFP" + OSFP_TYPE = "OSFP" + QSFP_DD_TYPE = "QSFP_DD" + + NULL_VAL = 'N/A' + + _port_to_i2c_mapping = { + 1: 2, + 2: 3, + 3: 4, + 4: 5, + 5: 6, + 6: 7, + 7: 8, + 8: 9, + 9: 10, + 10:11 , + 11:12, + 12:13, + 13:14, + 14:15, + 15:16, + 16:17, + 17:18, + 18:19, + 19:20, + 20:21, + 21:22, + 22:23, + 23:24, + 24:25, + 25:26, + 26:27, + 27:28, + 28:29, + 29:30, + 30:31, + 31:32, + 32:33, + 33:34, + 34:35, + 35:36, + 36:37, + 37:38, + 38:39, + 39:40, + 40:41, + 41:42, + 42:43, + 43:44, + 44:45, + 45:46, + 46:47, + 47:48, + 48:49, + 49:50, + 50:52, + 51:54, + 52:51, + 53:53, + 54:55, + + } + + + CPLD2_PORT_START = 1 + CPLD2_PORT_END = 24 + CPLD3_PORT_START = 25 + CPLD3_PORT_END = 54 + PRS_PATH = "/sys/devices/platform/dx010_cpld/qsfp_modprs" + + def __init__(self, sfp_index=0, sfp_name=None): + SfpOptoeBase.__init__(self) + self._api_helper=APIHelper() + self.port_num = sfp_index + 1 + self.index = self.port_num + self._name = sfp_name + + + if self.port_num < self.QSFP_PORT_START: + self.sfp_type = self.SFP_TYPE + else: + self.sfp_type = self.QSFP_TYPE + self.update_sfp_type() + self.refresh_optoe_dev_class() + + def __write_txt_file(self, file_path, value): + try: + reg_file = open(file_path, "w") + except IOError as e: + logger.log_error("Error: unable to open file: %s" % str(e)) + return False + + reg_file.write(str(value)) + reg_file.close() + + return True + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self._api_helper.is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_eeprom_path(self): + port_eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num]) + return port_eeprom_path + + def read_eeprom(self, offset, num_bytes): + port_eeprom_path = self.get_eeprom_path() + #Try to solved IOError + tries = 15 + for i in range(tries): + try: + eeprom = open(port_eeprom_path, mode='rb', buffering=0) + except (IOError): + if i < tries - 1: + time.sleep(0.02) + continue + else: + return None + break + try: + eeprom.seek(offset) + eeprom_raw = bytearray(eeprom.read(num_bytes)) + eeprom.close() + return eeprom_raw + except (OSError, IOError): + return None + + def refresh_optoe_dev_class(self): + if self.get_presence(): + for retry in range(5): + ret = self.update_sfp_type() + if ret == self.EEPROM_DATA_NOT_READY: + time.sleep(1) + else: + break + if ret != self.UPDATE_DONE: + logger.log_error("Error: port {}: update sfp type fail due to {}".format(self.port_num, ret)) + return False + + devclass_path = OPTOE_DEV_CLASS_PATH.format(self._port_to_i2c_mapping[self.port_num]) + devclass = self._api_helper.read_txt_file(devclass_path) + if devclass is None: + return False + + if self.sfp_type == self.QSFP_TYPE: + if devclass == '1': + return True + return self._api_helper.write_txt_file(devclass_path, 1) + elif self.sfp_type == self.SFP_TYPE: + if devclass == '2': + return True + return self._api_helper.write_txt_file(devclass_path, 2) + elif self.sfp_type == self.QSFP_DD_TYPE: + if devclass == '3': + return True + return self._api_helper.write_txt_file(devclass_path, 3) + else: + return False + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + if not self.get_presence(): + return False + if self.QSFP_PORT_START <= self.port_num <= self.QSFP_PORT_END: + reset_path = "{}{}{}".format(CPLD3_I2C_PATH, '/module_reset_', self.port_num) + else: + return False + + val = self._api_helper.read_txt_file(reset_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + if self.port_num > self.PORT_END: + # SFP doesn't support this feature + return False + + if not self.get_presence(): + return False + + if self.sfp_type == self.SFP_TYPE: + # SFP doesn't support this feature + return False + else: + power_set=self.get_power_set() + power_override = self.get_power_override() + return power_set and power_override + + def get_power_set(self): + + if self.sfp_type == self.SFP_TYPE: + # SFP doesn't support this feature + return False + else: + api = self.get_xcvr_api() + return api.get_power_set() if api is not None else None + + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + if not self.get_presence(): + return False + + if self.QSFP_PORT_START <= self.port_num <= self.QSFP_PORT_END: + reset_path = "{}{}{}".format(CPLD3_I2C_PATH, 'module_reset_', self.port_num) + else: + return False + + ret = self.__write_txt_file(reset_path, 1) #sysfs 1: enable reset + if ret is not True: + return ret + + time.sleep(0.2) + ret = self.__write_txt_file(reset_path, 0) #sysfs 0: disable reset + time.sleep(0.2) + + return ret + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if self.sfp_type == self.QSFP_TYPE: + api = self.get_xcvr_api() + return api.tx_disable(tx_disable) if api is not None else None + elif self.sfp_type == self.SFP_TYPE: + if self.port_num <= self.CPLD2_PORT_END : + disable_path = "{}{}{}".format(CPLD2_I2C_PATH, 'module_tx_disable_', self.port_num) + else : + disable_path = "{}{}{}".format(CPLD3_I2C_PATH, 'module_tx_disable_', self.port_num) + + tx_disable_value = 1 if tx_disable else 0 + ret = self._api_helper.write_txt_file(disable_path, tx_disable_value) #sysfs 1: disable tx + if ret is not True: + return ret + + return False + + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if self.sfp_type == self.SFP_TYPE: + return False # SFP doesn't support this feature + elif self.port_num > self.PORT_END: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + + api = self.get_xcvr_api() + if api is None: + return False + if api.get_lpmode_support() == False: + logger.log_notice("The transceiver of port {} doesn't support to set low power mode.". format(self.port_num)) + return True + if lpmode: + ret = api.set_power_override(True, True) + else: + ret = api.set_power_override(True, False) + return ret + + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + if self.sfp_type == self.SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + api = self.get_xcvr_api() + return api.set_power_override(power_override, power_set) if api is not None else None + + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + logical_port_list = sfputil_helper.logical + logical_port_list = natsort.natsorted(logical_port_list) + name = logical_port_list[self.index - 1] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + if self.port_num <= self.CPLD2_PORT_END: + present_path = "{}{}{}".format(CPLD2_I2C_PATH, '/module_present_', self.port_num) + else: + present_path = "{}{}{}".format(CPLD3_I2C_PATH, '/module_present_', self.port_num) + + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)==1 + else: + return False + + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() and not self.get_reset_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.port_num + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True + + def update_sfp_type(self): + """ + Updates the sfp type + + """ + ret = self.UPDATE_DONE + eeprom_raw = [] + eeprom_raw = self.read_eeprom(0, 1) + if eeprom_raw and hasattr(self,'sfp_type'): + if eeprom_raw[0] in self.SFP_TYPE_CODE_LIST: + self.sfp_type = self.SFP_TYPE + elif eeprom_raw[0] in self.QSFP_TYPE_CODE_LIST: + self.sfp_type = self.QSFP_TYPE + elif eeprom_raw[0] in self.QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = self.QSFP_DD_TYPE + elif eeprom_raw[0] in self.OSFP_TYPE_CODE_LIST: + self.sfp_type = self.OSFP_TYPE + else: + ret = self.UNKNOWN_SFP_TYPE_ID + else: + ret = self.EEPROM_DATA_NOT_READY + + return ret + + def validate_eeprom_sfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(0, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + checksum_test = 0 + eeprom_raw = self.read_eeprom(384, 96) + if eeprom_raw is None: + return None + + for i in range(0, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + return True + + def validate_eeprom_qsfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(128, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + return True + + def validate_eeprom_cmis(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(128, 95) + if eeprom_raw is None: + return None + + for i in range(0, 94): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[94]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + checksum_test = 0 + eeprom_raw = self.read_eeprom(258, 126) + if eeprom_raw is None: + return None + + for i in range(0, 125): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[125]: + return False + + checksum_test = 0 + eeprom_raw = self.read_eeprom(384, 128) + if eeprom_raw is None: + return None + + for i in range(0, 127): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[127]: + return False + + # CMIS_5.0 starts to support the checksum of page 04h + cmis_rev = float(api.get_cmis_rev()) + if cmis_rev >= 5.0: + checksum_test = 0 + eeprom_raw = self.read_eeprom(640, 128) + if eeprom_raw is None: + return None + + for i in range(0, 127): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[127]: + return False + + return True + + def validate_eeprom(self): + id_byte_raw = self.read_eeprom(0, 1) + if id_byte_raw is None: + return None + + id = id_byte_raw[0] + if id in self.QSFP_TYPE_CODE_LIST: + return self.validate_eeprom_qsfp() + elif id in self.SFP_TYPE_CODE_LIST: + return self.validate_eeprom_sfp() + elif id in self.QSFP_DD_TYPE_CODE_LIST: + return self.validate_eeprom_cmis() + else: + return False + + def validate_temperature(self): + temperature = self.get_temperature() + threshold_dict = self.get_transceiver_threshold_info() + if temperature is None: + return None + + if threshold_dict is None: + return None + + if isinstance(temperature, float) is not True: + return True + + if isinstance(threshold_dict['temphighalarm'], float) is not True: + return True + + return threshold_dict['temphighalarm'] > temperature + + 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 + + err_stat = self.SFP_STATUS_BIT_INSERTED + + status = self.validate_eeprom() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_BAD_EEPROM) + + status = self.validate_temperature() + if status is False: + err_stat = (err_stat | self.SFP_ERROR_BIT_HIGH_TEMP) + + if err_stat is self.SFP_STATUS_BIT_INSERTED: + return self.SFP_STATUS_OK + else: + err_desc = '' + cnt = 0 + for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT: + if (err_stat & key) != 0: + if cnt > 0: + err_desc = err_desc + "|" + cnt = cnt + 1 + err_desc = err_desc + self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT[key] + + return err_desc diff --git a/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/thermal.py new file mode 100644 index 0000000000..2808603266 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/sonic_platform/thermal.py @@ -0,0 +1,402 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import os.path +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase + from .helper import DeviceThreshold +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "3c" + }, + 1: { + "num": 58, + "addr": "3f" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 57, + "addr": "38" + }, + 1: { + "num": 58, + "addr": "3b" + }, +} + +THERMAL_NAME_LIST = ["MB_FrontMiddle_temp(0x48)", "MB_RearRight_temp(0x49)", + "MB_FrontRight_temp(0x4A)", "CPU_Core_0_temp", + "CPU_Core_1_temp", "CPU_Core_2_temp", + "CPU_Core_3_temp"] + +PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 1"] + +SYSFS_PATH = "/sys/bus/i2c/devices" +CPU_SYSFS_PATH = "/sys/devices/platform" + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index=0, is_psu=False, psu_index=0): + self.index = thermal_index + self.is_psu = is_psu + self.psu_index = psu_index + self.min_temperature = None + self.max_temperature = None + + + if self.is_psu: + psu_i2c_bus = PSU_HWMON_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_HWMON_I2C_MAPPING[psu_index]["addr"] + self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus, + psu_i2c_addr) + psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"] + self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr) + + self.conf = DeviceThreshold(self.get_name()) + # Default thresholds + self.default_threshold = { + THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '80.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '80.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '80.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '98.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '98.0', + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + THERMAL_NAME_LIST[4] : { + self.conf.HIGH_THRESHOLD_FIELD : '98.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '98.0', + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + THERMAL_NAME_LIST[5] : { + self.conf.HIGH_THRESHOLD_FIELD : '98.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '98.0', + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + THERMAL_NAME_LIST[6] : { + self.conf.HIGH_THRESHOLD_FIELD : '98.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '98.0', + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + PSU_THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '80.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + }, + PSU_THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '80.0', + self.conf.LOW_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.HIGH_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE, + self.conf.LOW_CRIT_THRESHOLD_FIELD : self.conf.NOT_AVAILABLE + } + } + + + # Set hwmon path + i2c_path = { + 0: {"hwmon_path":"61-0048/hwmon/hwmon*/", "ss_index":1}, + 1: {"hwmon_path":"62-0049/hwmon/hwmon*/", "ss_index":1}, + 2: {"hwmon_path":"63-004a/hwmon/hwmon*/", "ss_index":1}, + 3: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":2}, + 4: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":3}, + 5: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":4}, + 6: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":5} + }.get(self.index, None) + + self.is_cpu = False + if self.index in range(3,7): + self.is_cpu = True + self.hwmon_path = "{}/{}".format(CPU_SYSFS_PATH, i2c_path["hwmon_path"]) + else: + self.hwmon_path = "{}/{}".format(SYSFS_PATH, i2c_path["hwmon_path"]) + self.ss_key = THERMAL_NAME_LIST[self.index] + self.ss_index = i2c_path["ss_index"] + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data =fd.readline().rstrip() + if len(data) > 0: + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + if not self.is_psu: + temp_file_path = os.path.join(self.hwmon_path, temp_file) + else: + temp_file_path = temp_file + raw_temp = self.__read_txt_file(temp_file_path) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + def __set_threshold(self, file_name, temperature): + if self.is_psu: + return True + temp_file_path = os.path.join(self.hwmon_path, file_name) + for filename in glob.glob(temp_file_path): + try: + with open(filename, 'w') as fd: + fd.write(str(temperature)) + return True + except IOError as e: + print("IOError") + return False + + + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + if not self.is_psu: + temp_file = "temp{}_input".format(self.ss_index) + else: + temp_file = self.psu_hwmon_path + "psu_temp1_input" + + current = self.__get_temp(temp_file) + if self.min_temperature is None or current < self.min_temperature: + self.min_temperature = current + + if self.max_temperature is None or current > self.max_temperature: + self.max_temperature = current + + return current + return self.__get_temp(temp_file) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + value = self.conf.get_high_critical_threshold() + if value != self.conf.NOT_AVAILABLE: + return float(value) + + default_value = self.default_threshold[self.get_name()][self.conf.HIGH_CRIT_THRESHOLD_FIELD] + if default_value != self.conf.NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def set_high_critical_threshold(self, temperature): + """ + Sets the critical high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + + Returns: + A boolean, True if threshold is set successfully, False if not + """ + try: + value = float(temperature) + except: + return False + + try: + self.conf.set_high_critical_threshold(str(value)) + except: + return False + + return True + + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + value = self.conf.get_high_threshold() + if value != self.conf.NOT_AVAILABLE: + return float(value) + + default_value = self.default_threshold[self.get_name()][self.conf.HIGH_THRESHOLD_FIELD] + if default_value != self.conf.NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + try: + value = float(temperature) + except: + return False + + try: + self.conf.set_high_threshold(str(value)) + except: + return False + + return True + + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + if self.is_psu: + return PSU_THERMAL_NAME_LIST[self.psu_index] + else: + return THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + if self.is_cpu: + return True + + if self.is_psu: + val = self.__read_txt_file(self.cpld_path + "psu_present") + if val is not None: + return int(val, 10) == 1 + else: + return False + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_txt = self.__read_txt_file(temp_file_path) + if raw_txt is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_cpu: + return True + + if self.is_psu: + temp_file = self.psu_hwmon_path + "psu_temp_fault" + return self.get_presence() and (not int( + self.__read_txt_file(temp_file))) + + file_str = "temp{}_input".format(self.ss_index) + file_path = os.path.join(self.hwmon_path, file_str) + raw_txt = self.__read_txt_file(file_path) + if raw_txt is None: + return False + else: + return int(raw_txt) != 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_minimum_recorded(self): + """ Retrieves the minimum recorded temperature of thermal + Returns: A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.min_temperature is None: + self.get_temperature() + + return self.min_temperature + + def get_maximum_recorded(self): + """ Retrieves the maximum recorded temperature of thermal + Returns: A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.max_temperature is None: + self.get_temperature() + + return self.max_temperature + diff --git a/device/accton/x86_64-accton_as5812_54x-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as5812_54x-r0/system_health_monitoring_config.json new file mode 100644 index 0000000000..846d576f68 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/system_health_monitoring_config.json @@ -0,0 +1,15 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN" + } +} diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py index 95a4558622..fdbe2171b4 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py @@ -135,7 +135,7 @@ def _get_fan_node_val(self, fan_num, node_num): return None try: - val_file.close() + val_file.close() except: self.logger.debug('GET. unable to close file. device_path:%s', device_path) return None @@ -166,7 +166,7 @@ def _set_fan_node_val(self, fan_num, node_num, val): val_file.write(content) try: - val_file.close() + val_file.close() except: self.logger.debug('GET. unable to close file. device_path:%s', device_path) return None diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py index 7799bb3d53..8388384585 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py @@ -84,7 +84,7 @@ def _get_thermal_node_val(self, thermal_num): return None try: - val_file.close() + val_file.close() except: self.logger.debug('GET. unable to close file. device_path:%s', device_path) return None diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_fan.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_fan.c old mode 100644 new mode 100755 diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c index 2c6b5f492a..9d8222c3bc 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c @@ -34,20 +34,22 @@ #include #include #include +#define __STDC_WANT_LIB_EXT1__ 1 +#include #define PSU_STATUS_I2C_ADDR 0x60 #define PSU_STATUS_I2C_REG_OFFSET 0x2 - +#define MAX_MODEL_NAME 13 +#define MAX_SERIAL_NUMBER 15 #define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1))) #define IS_PRESENT(id, value) (!(value & BIT(id*4))) static ssize_t show_index(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); static int as5812_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); extern int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg); -static int as5812_54x_psu_model_name_get(struct device *dev); /* Addresses scanned */ @@ -62,7 +64,8 @@ struct as5812_54x_psu_data { unsigned long last_updated; /* In jiffies */ u8 index; /* PSU index */ u8 status; /* Status(present/power_good) register read from CPLD */ - char model_name[14]; /* Model name, read from eeprom */ + char model_name[MAX_MODEL_NAME + 1]; /* Model name, read from eeprom */ + char serial_number[MAX_SERIAL_NUMBER + 1]; /* serial number, read from eeprom */ }; static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev); @@ -71,21 +74,25 @@ enum as5812_54x_psu_sysfs_attributes { PSU_INDEX, PSU_PRESENT, PSU_MODEL_NAME, - PSU_POWER_GOOD + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER, + }; /* sysfs attributes for hwmon */ static SENSOR_DEVICE_ATTR(psu_index, S_IRUGO, show_index, NULL, PSU_INDEX); static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); -static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); static struct attribute *as5812_54x_psu_attributes[] = { &sensor_dev_attr_psu_index.dev_attr.attr, &sensor_dev_attr_psu_present.dev_attr.attr, &sensor_dev_attr_psu_model_name.dev_attr.attr, &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, NULL }; @@ -106,7 +113,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, u8 status = 0; if (!data->valid) { - return sprintf(buf, "0\n"); + return -EIO; } if (attr->index == PSU_PRESENT) { @@ -119,24 +126,29 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", status); } -static ssize_t show_model_name(struct device *dev, struct device_attribute *da, +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct as5812_54x_psu_data *data = as5812_54x_psu_update_device(dev); + const char *ptr = NULL; if (!data->valid) { - return 0; - } - - if (!IS_PRESENT(data->index, data->status)) { - return 0; + return -EIO; } - if (as5812_54x_psu_model_name_get(dev) < 0) { - return -ENXIO; + switch (attr->index) { + case PSU_MODEL_NAME: + ptr = data->model_name; + break; + case PSU_SERIAL_NUMBER: + ptr = data->serial_number; + break; + default: + return -EINVAL; } - return sprintf(buf, "%s\n", data->model_name); + return sprintf(buf, "%s\n", ptr); } static const struct attribute_group as5812_54x_psu_group = { @@ -254,7 +266,8 @@ enum psu_type { PSU_CPR_6011_2M11, /* AC110V - F2B */ PSU_CPR_6011_2M21, /* AC110V - B2F */ PSU_UM400D_01G, /* DC48V - F2B */ - PSU_UM400D01_01G /* DC48V - B2F */ + PSU_UM400D01_01G, /* DC48V - B2F */ + UNKNOWN_PSU }; struct model_name_info { @@ -275,46 +288,21 @@ struct model_name_info models[] = { {PSU_UM400D01_01G, 0x50, 12, "um400d01-01G"}, }; -static int as5812_54x_psu_model_name_get(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct as5812_54x_psu_data *data = i2c_get_clientdata(client); - int i, status; - - for (i = 0; i < ARRAY_SIZE(models); i++) { - memset(data->model_name, 0, sizeof(data->model_name)); - - status = as5812_54x_psu_read_block(client, models[i].offset, - data->model_name, models[i].length); - if (status < 0) { - data->model_name[0] = '\0'; - dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", - client->addr, models[i].offset); - return status; - } - else { - data->model_name[models[i].length] = '\0'; - } - - if (i == PSU_YM_2401_JCR || i == PSU_YM_2401_JDR) { - /* Skip the meaningless data byte 8*/ - data->model_name[8] = data->model_name[9]; - data->model_name[9] = data->model_name[10]; - data->model_name[10] = '\0'; - } - - /* Determine if the model name is known, if not, read next index - */ - if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) { - return 0; - } - else { - data->model_name[0] = '\0'; - } - } +struct serial_number_info { + u8 offset; + u8 length; +}; - return -ENODATA; -} +struct serial_number_info serials[] = { + [PSU_YM_2401_JCR] = {0x47, 15}, + [PSU_YM_2401_JDR] = {0x47, 15}, + [PSU_CPR_4011_4M11] = {0x47, 15}, + [PSU_CPR_4011_4M21] = {0x47, 15}, + [PSU_CPR_6011_2M11] = {0x47, 15}, + [PSU_CPR_6011_2M21] = {0x47, 15}, + [PSU_UM400D_01G] = {0x40, 15}, + [PSU_UM400D01_01G] = {0x40, 15}, +}; static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev) { @@ -326,6 +314,7 @@ static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *d if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { int status = -1; + int i, power_good = 0; dev_dbg(&client->dev, "Starting as5812_54x update\n"); data->valid = 0; @@ -342,6 +331,83 @@ static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *d data->status = status; } + data->model_name[0] = '\0'; + data->serial_number[0] = '\0'; + power_good = IS_POWER_GOOD(data->index, data->status); + + if (power_good) { + enum psu_type type = UNKNOWN_PSU; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + if ((models[i].length+1) > ARRAY_SIZE(data->model_name)) { + dev_dbg(&client->dev, + "invalid models[%d].length(%d), should not exceed the size of data->model_name(%ld)\n", + i, models[i].length, ARRAY_SIZE(data->model_name)); + continue; + } + + #ifdef __STDC_LIB_EXT1__ + memset_s(data->model_name, sizeof(data->model_name), 0, sizeof(data->model_name)); + #else + memset(data->model_name, 0, sizeof(data->model_name)); + #endif + status = as5812_54x_psu_read_block(client, models[i].offset, + data->model_name, models[i].length); + if (status < 0) { + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + continue; + } + else { + data->model_name[models[i].length] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) { + type = models[i].type; + break; + } + } + + if (type == PSU_YM_2401_JCR || type == PSU_YM_2401_JDR) { + /* Skip the meaningless data byte 8*/ + data->model_name[8] = data->model_name[9]; + data->model_name[9] = data->model_name[10]; + data->model_name[10] = '\0'; + } + + if (type < ARRAY_SIZE(serials)) { + if ((serials[type].length+1) > ARRAY_SIZE(data->serial_number)) { + dev_dbg(&client->dev, + "invalid serials[%d].length(%d), should not exceed the size of data->serial_number(%ld)\n", + type, serials[type].length, ARRAY_SIZE(data->serial_number)); + goto exit; + } + + #ifdef __STDC_LIB_EXT1__ + memset_s(data->serial_number, sizeof(data->serial_number), 0, sizeof(data->serial_number)); + #else + memset(data->serial_number, 0, sizeof(data->serial_number)); + #endif + status = as5812_54x_psu_read_block(client, serials[type].offset, + data->serial_number, serials[type].length); + + if (status < 0) { + dev_dbg(&client->dev, "unable to read serial from (0x%x) offset(0x%x)\n", + client->addr, serials[type].offset); + goto exit; + } + else { + data->serial_number[serials[type].length] = '\0'; + } + } + else { + dev_dbg(&client->dev, "invalid PSU type(%d)\n", type); + goto exit; + } + } + data->last_updated = jiffies; data->valid = 1; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c index 30bea914d5..bb377128cb 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c @@ -58,11 +58,14 @@ struct cpr_4011_4mxx_data { u8 fan_fault; /* Register value */ u16 fan_duty_cycle[2]; /* Register value */ u16 fan_speed[2]; /* Register value */ + u8 revision[6]; /* Register value*/ + u16 mfr_p_out_max; }; static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_revision(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value); static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev); @@ -78,6 +81,8 @@ enum cpr_4011_4mxx_sysfs_attributes { PSU_FAN1_FAULT, PSU_FAN1_DUTY_CYCLE, PSU_FAN1_SPEED, + PSU_REVISION, + PSU_MFR_P_OUT_MAX }; /* sysfs attributes for hwmon @@ -92,6 +97,8 @@ static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_ static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_revision, S_IRUGO, show_revision, NULL, PSU_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_p_out_max, S_IRUGO, show_linear, NULL, PSU_MFR_P_OUT_MAX); static struct attribute *cpr_4011_4mxx_attributes[] = { &sensor_dev_attr_psu_v_in.dev_attr.attr, @@ -104,6 +111,8 @@ static struct attribute *cpr_4011_4mxx_attributes[] = { &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_p_out_max.dev_attr.attr, NULL }; @@ -177,6 +186,9 @@ static ssize_t show_linear(struct device *dev, struct device_attribute *da, multiplier = 1; value = data->fan_speed[0]; break; + case PSU_MFR_P_OUT_MAX: + value = data->mfr_p_out_max; + break; default: break; } @@ -213,6 +225,15 @@ static ssize_t show_vout(struct device *dev, struct device_attribute *da, sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); } +static ssize_t show_revision(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); + + return sprintf(buf, "%s\n", data->revision); +} + + static const struct attribute_group cpr_4011_4mxx_group = { .attrs = cpr_4011_4mxx_attributes, }; @@ -343,7 +364,8 @@ static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev {0x3b, &(data->fan_duty_cycle[0])}, {0x3c, &(data->fan_duty_cycle[1])}, {0x90, &(data->fan_speed[0])}, - {0x91, &(data->fan_speed[1])}}; + {0x91, &(data->fan_speed[1])}, + {0xa7, &data->mfr_p_out_max}}; dev_dbg(&client->dev, "Starting cpr_4011_4mxx update\n"); @@ -373,6 +395,19 @@ static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev } } + /* Read revision (0xf0~0xf5)*/ + for (i=0; i< 5; i++) { + status = cpr_4011_4mxx_read_byte(client, 0xf0+i); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + 0xf0+i, status); + } + else { + data->revision[i] = status; + } + } + data->revision[5]='\0'; + data->last_updated = jiffies; data->valid = 1; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c old mode 100644 new mode 100755 index 1578d75bdd..c56a79800d --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c @@ -1021,10 +1021,10 @@ static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, /* Update tx_disable status */ if (on) { - status |= mask; + status &= ~mask; // 0: reset } else { - status &= ~mask; + status |= mask; // 1: normal } status = as5812_54x_cpld_write_internal(client, reg, status); diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service index 91c9adb01c..34bfe092d6 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service @@ -1,6 +1,6 @@ [Unit] Description=Accton AS5812-54X Platform Monitoring service -Before=pmon.service +Before=pmon.service system-health.service After=sysinit.target DefaultDependencies=no diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/sonic_platform_setup.py new file mode 100644 index 0000000000..9a5c95c414 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/sonic_platform_setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as5812_54x-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Jostar Yang', + maintainer_email='jostar_yang@edge-core.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py index f0fada6456..314d1e8201 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py @@ -53,6 +53,8 @@ class accton_as5812_monitor(object): def __init__(self, log_console, log_file): """Needs a logger and a logger level.""" + self.thermal = ThermalUtil() + self.fan = FanUtil() formatter = logging.Formatter('%(name)s %(message)s') sys_handler = logging.handlers.SysLogHandler(address = '/dev/log') sys_handler.setFormatter(formatter) @@ -94,8 +96,8 @@ def manage_fans(self): FAN_LEV4_SPEED_PERC = 40 - thermal = ThermalUtil() - fan = FanUtil() + thermal = self.thermal + fan = self.fan temp1 = thermal.get_thermal_1_val() if temp1 is None: diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py index 05ebcb4206..809066632b 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2016 Accton Networks, Inc. # @@ -24,9 +24,6 @@ command: install : install drivers and generate related sysfs nodes clean : uninstall drivers and remove related sysfs nodes - show : show all systen status - sff : dump SFP eeprom - set : change board setting with fan|led|sfp """ import os @@ -34,7 +31,6 @@ import getopt import sys import logging -import re import time PROJECT_NAME = 'as5812_54x' @@ -46,38 +42,12 @@ DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':3, 'psu':2, 'sfp':54} -led_prefix ='/sys/devices/platform/as5812_54x_led/leds/accton_'+PROJECT_NAME+'_led::' -fan_prefix ='/sys/devices/platform/as5812_54x_' -hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'], - 'fan1': ['fan'], - 'fan2': ['fan'], - 'fan3': ['fan'], - 'fan4': ['fan'], - 'fan5': ['fan'], - } -hwmon_nodes = {'led': ['brightness'] , - 'fan1': ['fan1_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'], - 'fan2': ['fan2_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'], - 'fan3': ['fan3_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'], - 'fan4': ['fan4_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'], - 'fan5': ['fan5_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'], - } -hwmon_prefix ={'led': led_prefix, - 'fan1': fan_prefix, - 'fan2': fan_prefix, - 'fan3': fan_prefix, - 'fan4': fan_prefix, - 'fan5': fan_prefix, - } - i2c_prefix = '/sys/bus/i2c/devices/' +''' i2c_bus = {'thermal': ['61-0048','62-0049', '63-004a'] , 'psu': ['57-0050','58-0053'], 'sfp': ['-0050']} -i2c_nodes = { - 'thermal': ['hwmon/hwmon*/temp1_input'] , - 'psu': ['psu_present ', 'psu_power_good'] , - 'sfp': ['sfp_is_present ', 'sfp_tx_disable']} +''' QSFP_START = 48 @@ -105,7 +75,7 @@ # PSU-2 'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device', 'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device', -'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device', +'echo as5812_54x_psu2 0x50 > /sys/bus/i2c/devices/i2c-58/new_device', 'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device', 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device', @@ -129,7 +99,7 @@ # PSU-2 'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device', 'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device', -'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device', +'echo as5812_54x_psu2 0x50 > /sys/bus/i2c/devices/i2c-58/new_device', 'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device', 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device', @@ -140,6 +110,9 @@ ] FORCE = 0 +LED_MODE_OFF = 0 +LED_MODE_AMBER = 2 # Default value for LOC LED +LED_LOC_PATH = "/sys/class/leds/accton_as5812_54x_led::loc/brightness" logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) logging.basicConfig(level=logging.INFO) @@ -147,8 +120,8 @@ if DEBUG == True: print(sys.argv[0]) print('ARGV :', sys.argv[1:]) - - + + def main(): global DEBUG global args @@ -181,22 +154,10 @@ def main(): do_install() elif arg == 'clean': do_uninstall() - elif arg == 'show': - device_traversal() - elif arg == 'sff': - if len(args)!=2: - show_eeprom_help() - elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: - show_eeprom_help() - else: - show_eeprom(args[1]) - return - elif arg == 'set': - if len(args)<3: - show_set_help() - else: - set_device(args[1:]) - return + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() else: show_help() @@ -207,19 +168,6 @@ def show_help(): print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}) sys.exit(0) -def show_set_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(cmd +" [led|sfp|fan]") - print(" use \""+ cmd + " led 0-4 \" to set led color") - print(" use \""+ cmd + " fan 0-100\" to set fan duty percetage") - print(" use \""+ cmd + " sfp 1-48 {0|1}\" to set sfp# tx_disable") - sys.exit(0) - -def show_eeprom_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(" use \""+ cmd + " 1-54 \" to dump sfp# eeprom") - sys.exit(0) - def my_log(txt): if DEBUG == True: print("[ACCTON DBG]: "+txt) @@ -253,6 +201,8 @@ def driver_inserted(): 'depmod -ae', 'modprobe i2c_dev', 'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe i2c_i801', +'modprobe i2c_ismt', 'modprobe optoe', 'modprobe i2c-mux-accton_as5812_54x_cpld', 'modprobe cpr_4011_4mxx', @@ -268,6 +218,9 @@ def driver_install(): if status: if FORCE == 0: return status + + print("Done driver_install") + return 0 def driver_uninstall(): @@ -349,6 +302,8 @@ def device_install(): print(output) if FORCE == 0: return status + + print("Done device_install") return @@ -389,6 +344,63 @@ def system_ready(): return False return True + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def set_loc_led(color): + global FORCE + + if os.path.exists(LED_LOC_PATH): + cmd = 'echo {} > {}'.format(color, LED_LOC_PATH) + try: + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + except Exception as e: + print({}.format(e)) + else: + print('{} does not exist.'.format(LED_LOC_PATH)) + + return + def do_install(): print("Checking system....") if driver_inserted() == False: @@ -407,6 +419,11 @@ def do_install(): return status else: print(PROJECT_NAME.upper()+" devices detected....") + + set_loc_led(LED_MODE_OFF) + + do_sonic_platform_install() + return def do_uninstall(): @@ -428,93 +445,10 @@ def do_uninstall(): if status: if FORCE == 0: return status + do_sonic_platform_clean() return -def devices_info(): - global DEVICE_NO - global ALL_DEVICE - global i2c_bus, hwmon_types - for key in DEVICE_NO: - ALL_DEVICE[key]= {} - for i in range(0,DEVICE_NO[key]): - ALL_DEVICE[key][key+str(i+1)] = [] - - for key in i2c_bus: - buses = i2c_bus[key] - nodes = i2c_nodes[key] - for i in range(0,len(buses)): - for j in range(0,len(nodes)): - if 'fan' == key: - for k in range(0,DEVICE_NO[key]): - node = key+str(k+1) - path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - elif 'sfp' == key: - for k in range(0,DEVICE_NO[key]): - node = key+str(k+1) - path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - else: - node = key+str(i+1) - path = i2c_prefix+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - - for key in hwmon_types: - itypes = hwmon_types[key] - nodes = hwmon_nodes[key] - for i in range(0,len(itypes)): - for j in range(0,len(nodes)): - node = key+"_"+itypes[i] - path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][ key+str(i+1)].append(path) - - #show dict all in the order - if DEBUG == True: - for i in sorted(ALL_DEVICE.keys()): - print((i+": ")) - for j in sorted(ALL_DEVICE[i].keys()): - print((" "+j)) - for k in (ALL_DEVICE[i][j]): - print((" "+" "+k)) - return - -def show_eeprom(index): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] - node = node.replace(node.split("/")[-1], 'eeprom') - # check if got hexdump command in current environment - ret, log = log_os_system("which hexdump", 0) - ret, log2 = log_os_system("which busybox hexdump", 0) - if len(log): - hex_cmd = 'hexdump' - elif len(log2): - hex_cmd = ' busybox hexdump' - else: - log = 'Failed : no hexdump cmd!!' - logging.info(log) - print(log) - return 1 - - print(node + ":") - ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) - if ret==0: - print(log) - else: - print("**********device no found**********") - return - - def get_cpld_path(index): order = get_i2c_order() if order !=0 : @@ -546,124 +480,6 @@ def get_path_sfp_presence(port_index): dev = cpld_p+"module_present_"+str(port_index) return True, dev - -def set_device(args): - global DEVICE_NO - global ALL_DEVICE - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - - if args[0]=='led': - if int(args[1])>4: - show_set_help() - return - #print ALL_DEVICE['led'] - for i in range(0,len(ALL_DEVICE['led'])): - for k in (ALL_DEVICE['led']['led'+str(i+1)]): - ret, log = log_os_system("echo "+args[1]+" >"+k, 1) - if ret: - return ret - elif args[0]=='fan': - if int(args[1])>100: - show_set_help() - return - #print ALL_DEVICE['fan'] - #fan1~6 is all fine, all fan share same setting - node = ALL_DEVICE['fan1'] ['fan11'][0] - node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage') - ret, log = log_os_system("cat "+ node, 1) - if ret==0: - print(("Previous fan duty: " + log.strip() +"%")) - ret, log = log_os_system("echo "+args[1]+" >"+node, 1) - if ret==0: - print(("Current fan duty: " + args[1] +"%")) - return ret - elif args[0]=='sfp': - #if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: - #There no tx_disable for QSFP port - if int(args[1]) > QSFP_START or int(args[1])==0: - show_set_help() - return - if len(args)<2: - show_set_help() - return - - if int(args[2])>1: - show_set_help() - return - - port_index = int(args[1]) - ret, dev = get_path_sfp_tx_dis(port_index) - if ret == False: - return False - else: - ret, log = log_os_system("echo "+args[2]+" >"+ dev, 1) - return ret - return - -#get digits inside a string. -#Ex: 31 for "sfp31" -def get_value(input): - digit = re.findall('\d+', input) - return int(digit[0]) - -def print_1_device_traversal(i, j, k): - ret, log = log_os_system("cat "+k, 0) - func = k.split("/")[-1].strip() - func = re.sub(j+'_','',func,1) - func = re.sub(i.lower()+'_','',func,1) - if ret==0: - return func+"="+log+" " - else: - return func+"="+"X"+" " - -def device_traversal(): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - for i in sorted(ALL_DEVICE.keys()): - print("============================================") - print((i.upper()+": ")) - print("============================================") - - for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value): - print(" "+j+":", end=' ') - if i == 'sfp': - port_index = int(list(filter(str.isdigit, j))) - for k in (ALL_DEVICE[i][j]): - if k.find('tx_disable')!= -1: - ret, k = get_path_sfp_tx_dis(port_index) - if ret == False: - continue - log = print_1_device_traversal(i, j, k) - print(log, end=' ') - if k.find('present')!= -1: - ret, k = get_path_sfp_presence(port_index) - if ret == False: - continue - log = print_1_device_traversal(i, j, k) - print(log, end=' ') - - else: - for k in (ALL_DEVICE[i][j]): - log = print_1_device_traversal(i, j, k) - print(log, end=' ') - print() - print("----------------------------------------------------------------") - - - print() - return - def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0) ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0)