From 4f9219f617b779fba10c92d5f2e4223a932c4097 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Mon, 17 Jan 2022 16:45:10 +0800 Subject: [PATCH 1/4] [Minipack] Support API2.0 and fix drv in kernel5.10 Signed-off-by: Jostar Yang --- .../Accton-MINIPACK/port_config.ini | 256 +- .../pmon_daemon_control.json | 2 +- .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 241 ++ .../sonic_platform/component.py | 156 ++ .../sonic_platform/eeprom.py | 134 + .../sonic_platform/event.py | 78 + .../sonic_platform/fan.py | 235 ++ .../sonic_platform/fan_drawer.py | 90 + .../sonic_platform/helper.py | 117 + .../sonic_platform/platform.py | 21 + .../sonic_platform/psu.py | 234 ++ .../sonic_platform/sfp.py | 2210 +++++++++++++++++ .../sonic_platform/thermal.py | 155 ++ .../system_health_monitoring_config.json | 14 + .../debian/rules | 4 + .../sonic-platform-accton-minipack.install | 3 + .../minipack/classes/fpgautil.py | 587 +++++ .../minipack/fpga_setup.py | 18 + .../minipack/lib/fbfpgaiomodule.c | 12 +- .../minipack/modules/minipack_psensor.c | 199 +- .../service/minipack-platform-init.service | 4 +- .../service/minipack-setup-qsfp-oom.service | 32 +- .../minipack/sonic_platform_setup.py | 34 + .../minipack/utils/accton_minipack_util.py | 306 +-- .../minipack/utils/setup_qsfp_eeprom.py | 93 +- 26 files changed, 4794 insertions(+), 443 deletions(-) create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/__init__.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/chassis.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/helper.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/platform.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/psu.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py create mode 100644 device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py create mode 100644 device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json create mode 100644 platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install create mode 100644 platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/minipack/fpga_setup.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/minipack/sonic_platform_setup.py diff --git a/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini b/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini index cc8e7cbad5fd..d339515a1b0e 100755 --- a/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini +++ b/device/accton/x86_64-accton_minipack-r0/Accton-MINIPACK/port_config.ini @@ -1,129 +1,129 @@ # name lanes alias index -Ethernet1 5,6 onehundredGigE1 0 -Ethernet2 7,8 onehundredGigE2 1 -Ethernet3 1,2 onehundredGigE3 2 -Ethernet4 3,4 onehundredGigE4 3 -Ethernet5 37,38 onehundredGigE5 4 -Ethernet6 39,40 onehundredGigE6 5 -Ethernet7 33,34 onehundredGigE7 6 -Ethernet8 35,36 onehundredGigE8 7 -Ethernet9 69,70 onehundredGigE9 8 -Ethernet10 71,72 onehundredGigE10 9 -Ethernet11 65,66 onehundredGigE11 10 -Ethernet12 67,68 onehundredGigE12 11 -Ethernet13 101,102 onehundredGigE13 12 -Ethernet14 103,104 onehundredGigE14 13 -Ethernet15 97,98 onehundredGigE15 14 -Ethernet16 99,100 onehundredGigE16 15 -Ethernet17 13,14 onehundredGigE17 16 -Ethernet18 15,16 onehundredGigE18 17 -Ethernet19 9,10 onehundredGigE19 18 -Ethernet20 11,12 onehundredGigE20 19 -Ethernet21 45,46 onehundredGigE21 20 -Ethernet22 47,48 onehundredGigE22 21 -Ethernet23 41,42 onehundredGigE23 22 -Ethernet24 43,44 onehundredGigE24 23 -Ethernet25 77,78 onehundredGigE25 24 -Ethernet26 79,80 onehundredGigE26 25 -Ethernet27 73,74 onehundredGigE27 26 -Ethernet28 75,76 onehundredGigE28 27 -Ethernet29 109,110 onehundredGigE29 28 -Ethernet30 111,112 onehundredGigE30 29 -Ethernet31 105,106 onehundredGigE31 30 -Ethernet32 107,108 onehundredGigE32 31 -Ethernet33 21,22 onehundredGigE33 32 -Ethernet34 23,24 onehundredGigE34 33 -Ethernet35 17,18 onehundredGigE35 34 -Ethernet36 19,20 onehundredGigE36 35 -Ethernet37 53,54 onehundredGigE37 36 -Ethernet38 55,56 onehundredGigE38 37 -Ethernet39 49,50 onehundredGigE39 38 -Ethernet40 51,52 onehundredGigE40 39 -Ethernet41 85,86 onehundredGigE41 40 -Ethernet42 87,88 onehundredGigE42 41 -Ethernet43 81,82 onehundredGigE43 42 -Ethernet44 83,84 onehundredGigE44 43 -Ethernet45 117,118 onehundredGigE45 44 -Ethernet46 119,120 onehundredGigE46 45 -Ethernet47 113,114 onehundredGigE47 46 -Ethernet48 115,116 onehundredGigE48 47 -Ethernet49 29,30 onehundredGigE49 48 -Ethernet50 31,32 onehundredGigE50 49 -Ethernet51 25,26 onehundredGigE51 50 -Ethernet52 27,28 onehundredGigE52 51 -Ethernet53 61,62 onehundredGigE53 52 -Ethernet54 63,64 onehundredGigE54 53 -Ethernet55 57,58 onehundredGigE55 54 -Ethernet56 59,60 onehundredGigE56 55 -Ethernet57 93,94 onehundredGigE57 56 -Ethernet58 95,96 onehundredGigE58 57 -Ethernet59 89,90 onehundredGigE59 58 -Ethernet60 91,92 onehundredGigE60 59 -Ethernet61 125,126 onehundredGigE61 60 -Ethernet62 127,128 onehundredGigE62 61 -Ethernet63 121,122 onehundredGigE63 62 -Ethernet64 123,124 onehundredGigE64 63 -Ethernet65 133,134 onehundredGigE65 64 -Ethernet66 135,136 onehundredGigE66 65 -Ethernet67 129,130 onehundredGigE67 66 -Ethernet68 131,132 onehundredGigE68 67 -Ethernet69 165,166 onehundredGigE69 68 -Ethernet70 167,168 onehundredGigE70 69 -Ethernet71 161,162 onehundredGigE71 70 -Ethernet72 163,164 onehundredGigE72 71 -Ethernet73 197,198 onehundredGigE73 72 -Ethernet74 199,200 onehundredGigE74 73 -Ethernet75 193,194 onehundredGigE75 74 -Ethernet76 195,196 onehundredGigE76 75 -Ethernet77 229,230 onehundredGigE77 76 -Ethernet78 231,232 onehundredGigE78 77 -Ethernet79 225,226 onehundredGigE79 78 -Ethernet80 227,228 onehundredGigE80 79 -Ethernet81 141,142 onehundredGigE81 80 -Ethernet82 143,144 onehundredGigE82 81 -Ethernet83 137,138 onehundredGigE83 82 -Ethernet84 139,140 onehundredGigE84 83 -Ethernet85 173,174 onehundredGigE85 84 -Ethernet86 175,176 onehundredGigE86 85 -Ethernet87 169,170 onehundredGigE87 86 -Ethernet88 171,172 onehundredGigE88 87 -Ethernet89 205,206 onehundredGigE89 88 -Ethernet90 207,208 onehundredGigE90 89 -Ethernet91 201,202 onehundredGigE91 90 -Ethernet92 203,204 onehundredGigE92 91 -Ethernet93 237,238 onehundredGigE93 92 -Ethernet94 239,240 onehundredGigE94 93 -Ethernet95 233,234 onehundredGigE95 94 -Ethernet96 235,236 onehundredGigE96 95 -Ethernet97 149,150 onehundredGigE97 96 -Ethernet98 151,152 onehundredGigE98 97 -Ethernet99 145,146 onehundredGigE99 98 -Ethernet100 147,148 onehundredGigE100 99 -Ethernet101 181,182 onehundredGigE101 100 -Ethernet102 183,184 onehundredGigE102 101 -Ethernet103 177,178 onehundredGigE103 102 -Ethernet104 179,180 onehundredGigE104 103 -Ethernet105 213,214 onehundredGigE105 104 -Ethernet106 215,216 onehundredGigE106 105 -Ethernet107 209,210 onehundredGigE107 106 -Ethernet108 211,212 onehundredGigE108 107 -Ethernet109 245,246 onehundredGigE109 108 -Ethernet110 247,248 onehundredGigE110 109 -Ethernet111 241,242 onehundredGigE111 110 -Ethernet112 243,244 onehundredGigE112 111 -Ethernet113 157,158 onehundredGigE113 112 -Ethernet114 159,160 onehundredGigE114 113 -Ethernet115 153,154 onehundredGigE115 114 -Ethernet116 155,156 onehundredGigE116 115 -Ethernet117 189,190 onehundredGigE117 116 -Ethernet118 191,192 onehundredGigE118 117 -Ethernet119 185,186 onehundredGigE119 118 -Ethernet120 187,188 onehundredGigE120 119 -Ethernet121 221,222 onehundredGigE121 120 -Ethernet122 223,224 onehundredGigE122 121 -Ethernet123 217,218 onehundredGigE123 122 -Ethernet124 219,220 onehundredGigE124 123 -Ethernet125 253,254 onehundredGigE125 124 -Ethernet126 255,256 onehundredGigE126 125 -Ethernet127 249,250 onehundredGigE127 126 -Ethernet128 251,252 onehundredGigE128 127 +Ethernet1 5,6 onehundredGigE1 1 +Ethernet2 7,8 onehundredGigE2 2 +Ethernet3 1,2 onehundredGigE3 3 +Ethernet4 3,4 onehundredGigE4 4 +Ethernet5 37,38 onehundredGigE5 5 +Ethernet6 39,40 onehundredGigE6 6 +Ethernet7 33,34 onehundredGigE7 7 +Ethernet8 35,36 onehundredGigE8 8 +Ethernet9 69,70 onehundredGigE9 9 +Ethernet10 71,72 onehundredGigE10 10 +Ethernet11 65,66 onehundredGigE11 11 +Ethernet12 67,68 onehundredGigE12 12 +Ethernet13 101,102 onehundredGigE13 13 +Ethernet14 103,104 onehundredGigE14 14 +Ethernet15 97,98 onehundredGigE15 15 +Ethernet16 99,100 onehundredGigE16 16 +Ethernet17 13,14 onehundredGigE17 17 +Ethernet18 15,16 onehundredGigE18 18 +Ethernet19 9,10 onehundredGigE19 19 +Ethernet20 11,12 onehundredGigE20 20 +Ethernet21 45,46 onehundredGigE21 21 +Ethernet22 47,48 onehundredGigE22 22 +Ethernet23 41,42 onehundredGigE23 23 +Ethernet24 43,44 onehundredGigE24 24 +Ethernet25 77,78 onehundredGigE25 25 +Ethernet26 79,80 onehundredGigE26 26 +Ethernet27 73,74 onehundredGigE27 27 +Ethernet28 75,76 onehundredGigE28 28 +Ethernet29 109,110 onehundredGigE29 29 +Ethernet30 111,112 onehundredGigE30 30 +Ethernet31 105,106 onehundredGigE31 31 +Ethernet32 107,108 onehundredGigE32 32 +Ethernet33 21,22 onehundredGigE33 33 +Ethernet34 23,24 onehundredGigE34 34 +Ethernet35 17,18 onehundredGigE35 35 +Ethernet36 19,20 onehundredGigE36 36 +Ethernet37 53,54 onehundredGigE37 37 +Ethernet38 55,56 onehundredGigE38 38 +Ethernet39 49,50 onehundredGigE39 39 +Ethernet40 51,52 onehundredGigE40 40 +Ethernet41 85,86 onehundredGigE41 41 +Ethernet42 87,88 onehundredGigE42 42 +Ethernet43 81,82 onehundredGigE43 43 +Ethernet44 83,84 onehundredGigE44 44 +Ethernet45 117,118 onehundredGigE45 45 +Ethernet46 119,120 onehundredGigE46 46 +Ethernet47 113,114 onehundredGigE47 47 +Ethernet48 115,116 onehundredGigE48 48 +Ethernet49 29,30 onehundredGigE49 49 +Ethernet50 31,32 onehundredGigE50 50 +Ethernet51 25,26 onehundredGigE51 51 +Ethernet52 27,28 onehundredGigE52 52 +Ethernet53 61,62 onehundredGigE53 53 +Ethernet54 63,64 onehundredGigE54 54 +Ethernet55 57,58 onehundredGigE55 55 +Ethernet56 59,60 onehundredGigE56 56 +Ethernet57 93,94 onehundredGigE57 57 +Ethernet58 95,96 onehundredGigE58 58 +Ethernet59 89,90 onehundredGigE59 59 +Ethernet60 91,92 onehundredGigE60 60 +Ethernet61 125,126 onehundredGigE61 61 +Ethernet62 127,128 onehundredGigE62 62 +Ethernet63 121,122 onehundredGigE63 63 +Ethernet64 123,124 onehundredGigE64 64 +Ethernet65 133,134 onehundredGigE65 65 +Ethernet66 135,136 onehundredGigE66 66 +Ethernet67 129,130 onehundredGigE67 67 +Ethernet68 131,132 onehundredGigE68 68 +Ethernet69 165,166 onehundredGigE69 69 +Ethernet70 167,168 onehundredGigE70 70 +Ethernet71 161,162 onehundredGigE71 71 +Ethernet72 163,164 onehundredGigE72 72 +Ethernet73 197,198 onehundredGigE73 73 +Ethernet74 199,200 onehundredGigE74 74 +Ethernet75 193,194 onehundredGigE75 75 +Ethernet76 195,196 onehundredGigE76 76 +Ethernet77 229,230 onehundredGigE77 77 +Ethernet78 231,232 onehundredGigE78 78 +Ethernet79 225,226 onehundredGigE79 79 +Ethernet80 227,228 onehundredGigE80 80 +Ethernet81 141,142 onehundredGigE81 81 +Ethernet82 143,144 onehundredGigE82 82 +Ethernet83 137,138 onehundredGigE83 83 +Ethernet84 139,140 onehundredGigE84 84 +Ethernet85 173,174 onehundredGigE85 85 +Ethernet86 175,176 onehundredGigE86 86 +Ethernet87 169,170 onehundredGigE87 87 +Ethernet88 171,172 onehundredGigE88 88 +Ethernet89 205,206 onehundredGigE89 89 +Ethernet90 207,208 onehundredGigE90 90 +Ethernet91 201,202 onehundredGigE91 91 +Ethernet92 203,204 onehundredGigE92 92 +Ethernet93 237,238 onehundredGigE93 93 +Ethernet94 239,240 onehundredGigE94 94 +Ethernet95 233,234 onehundredGigE95 95 +Ethernet96 235,236 onehundredGigE96 96 +Ethernet97 149,150 onehundredGigE97 97 +Ethernet98 151,152 onehundredGigE98 98 +Ethernet99 145,146 onehundredGigE99 99 +Ethernet100 147,148 onehundredGigE100 100 +Ethernet101 181,182 onehundredGigE101 101 +Ethernet102 183,184 onehundredGigE102 102 +Ethernet103 177,178 onehundredGigE103 103 +Ethernet104 179,180 onehundredGigE104 104 +Ethernet105 213,214 onehundredGigE105 105 +Ethernet106 215,216 onehundredGigE106 106 +Ethernet107 209,210 onehundredGigE107 107 +Ethernet108 211,212 onehundredGigE108 108 +Ethernet109 245,246 onehundredGigE109 109 +Ethernet110 247,248 onehundredGigE110 110 +Ethernet111 241,242 onehundredGigE111 111 +Ethernet112 243,244 onehundredGigE112 112 +Ethernet113 157,158 onehundredGigE113 113 +Ethernet114 159,160 onehundredGigE114 114 +Ethernet115 153,154 onehundredGigE115 115 +Ethernet116 155,156 onehundredGigE116 116 +Ethernet117 189,190 onehundredGigE117 117 +Ethernet118 191,192 onehundredGigE118 118 +Ethernet119 185,186 onehundredGigE119 119 +Ethernet120 187,188 onehundredGigE120 120 +Ethernet121 221,222 onehundredGigE121 121 +Ethernet122 223,224 onehundredGigE122 122 +Ethernet123 217,218 onehundredGigE123 123 +Ethernet124 219,220 onehundredGigE124 124 +Ethernet125 253,254 onehundredGigE125 125 +Ethernet126 255,256 onehundredGigE126 126 +Ethernet127 249,250 onehundredGigE127 127 +Ethernet128 251,252 onehundredGigE128 128 diff --git a/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json index 584a14b9d942..a3b204e20d8d 100644 --- a/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_minipack-r0/pmon_daemon_control.json @@ -1,5 +1,5 @@ { "skip_ledd": true, - "skip_thermalctld": true + "skip_pcied": true } diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..73a7720e8979 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-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_minipack-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..bf4c80513995 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/chassis.py @@ -0,0 +1,241 @@ +############################################################################# +# 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 = 8 +NUM_FAN = 2 +NUM_PSU = 4 +NUM_THERMAL = 8 +PORT_END = 128 +NUM_COMPONENT = 1 +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 = "which systemctl > /dev/null 2>&1" + +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 + from minipack.fpgautil import FpgaUtil + import fbfpgaio + pim = FpgaUtil() + pim.init_pim_fpga() + + for index in range(0, PORT_END): + sfp_module = Sfp(index, 'QSFP') + 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): + return os.system(HOST_CHK_CMD) == 0 + + 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_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_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): + return "ControlledByBMC" + + def set_status_led(self, color): + return True + diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py new file mode 100644 index 000000000000..59ebe7f31cbf --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/component.py @@ -0,0 +1,156 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +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") + +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("BIOS", "Basic Input/Output System") + +] +COMPONENT_DES_LIST = ["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 __run_command(self, command): + # Run bash command and print output to stdout + try: + process = subprocess.Popen( + shlex.split(command), stdout=subprocess.PIPE) + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + rc = process.poll() + if rc != 0: + return False + except Exception: + return False + return True + + 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_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() + else: + fw_version = "None" + + 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 + """ + raise NotImplementedError + + 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_minipack-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..180be75454d5 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py @@ -0,0 +1,134 @@ +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, 0x200, '', 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]+)([\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) diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py new file mode 100644 index 000000000000..722b7c04a1c6 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/event.py @@ -0,0 +1,78 @@ +try: + import time + from .helper import APIHelper + from sonic_py_common.logger import Logger + from minipack.fpgautil import FpgaUtil +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +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): + pim = FpgaUtil() + start_time = time.time() + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print("get_transceiver_change_event:Invalid timeout value", timeout) + return False, {} + + end_time = start_time + timeout + if start_time > end_time: + print('get_transceiver_change_event:' + 'time wrap / invalid timeout value', timeout) + + return False, {} # Time wrap or possibly incorrect timeout + + while timeout >= 0: + change_status = 0 + check_dict = pim.get_qsfp_interrupt() + present = 0 + for key, value in check_dict.items(): + if value == 1: + present = pim.get_qsfp_presence(key) + change_status = 1 + if present: + port_dict[key+1] = '1' + else: + port_dict[key+1] = '0' + + if change_status: + return True, change_dict + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, change_dict + print("get_evt_change_event: Should not reach here.") + return False, {} \ No newline at end of file diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..407caf635898 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan.py @@ -0,0 +1,235 @@ +############################################################################# +# 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 +DEVICE_PATH ="/sys/bus/platform/devices/minipack_psensor/" + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", + "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R", + "FAN-7F", "FAN-7R", "FAN-8F", "FAN-8R",] + +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.psu_index=psu_index + self.is_psu_fan = is_psu_fan + self.hwmon_path = DEVICE_PATH + + 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: + direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_INTAKE + 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.hwmon_path, "psu", self.psu_index+1, '_fan_speed') + 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(): # 50%==3000 + speed_path = "{}{}{}{}".format(self.hwmon_path, "fan", self.fan_tray_index+1, '_input') + speed_input=self._api_helper.read_txt_file(speed_path) + if speed_input is None: + return 0 + else: + speed=int(speed_input, 10)*100/6000 + if speed > 100: + speed=100 + + 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 + + """ + 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_presence() + 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_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.hwmon_path, 'psu', self.psu_index+1, '_fan_speed') + else: + present_path = "{}{}{}{}".format(self.hwmon_path, "fan", self.fan_tray_index+1, '_input') + val=self._api_helper.read_txt_file(present_path) + if val is not None and int(val, 10)!=0: + 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_psu_fan: + psu_fan_path="{}{}{}{}".format(self.hwmon_path, "psu", self.psu_index+1, '_fan_speed') + + 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(self.hwmon_path, "fan", self.fan_tray_index+1, '_input') + 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_minipack-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..17d339ee55f6 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,90 @@ +######################################################################## +# +# 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 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_minipack-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/helper.py new file mode 100644 index 000000000000..ce4499848f85 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/helper.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +import os +import struct +import subprocess +from mmap import * +from sonic_py_common import device_info + +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" +EMPTY_STRING = "" + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + 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 run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + return data.strip() + 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 + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format(str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..2f2c2a447fcf --- /dev/null +++ b/device/accton/x86_64-accton_minipack-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_minipack-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..640735cdf467 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/psu.py @@ -0,0 +1,234 @@ +############################################################################# +# 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") + + +DEVICE_PATH ="/sys/bus/platform/devices/minipack_psensor/" + +PSU_NAME_LIST = ["PSU-1", "PSU-2", "PSU-3", "PSU-4"] +PSU_NUM_FAN = [1, 1, 1, 1] + +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.hwmon_path = DEVICE_PATH + 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 + """ + vout_path = "{}{}{}{}".format(self.hwmon_path, 'in', (self.index+1)*2, '_input' ) + 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_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + iout_path = "{}{}{}{}".format(self.hwmon_path, 'curr', (self.index+1)*2, '_input' ) + 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 + """ + pout_path = "{}{}{}{}".format(self.hwmon_path, 'power', (self.index+1)*2, '_input' ) + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000000 + 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', self.index+1, '_temp_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 False #Not supported + + 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.00 + + 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 10.00 + + + 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 + """ + val=self.get_serial() + if val 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 + """ + power_path="{}{}{}{}".format(self.hwmon_path, 'power', (self.index+1)*2, '_input' ) + val=self._api_helper.read_txt_file(power_path) + if val is not None and int(val)!=0: + return True + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}{}{}".format(self.hwmon_path, 'psu' , (self.index+1) ,'_model_name') + model=self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}{}{}".format(self.hwmon_path, 'psu' , self.index+1 ,'_serial_num') + serial=self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial + + 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 diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py new file mode 100644 index 000000000000..7c767f24395b --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py @@ -0,0 +1,2210 @@ +############################################################################# +# 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: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper + from minipack.fpgautil import FpgaUtil + import fbfpgaio +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# definitions of the offset for values in OSFP info eeprom +OSFP_TYPE_OFFSET = 0 +OSFP_VENDOR_NAME_OFFSET = 129 +OSFP_VENDOR_PN_OFFSET = 148 +OSFP_HW_REV_OFFSET = 164 +OSFP_VENDOR_SN_OFFSET = 166 + +# definitions of the offset for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + + +sfp_cable_length_tup = ( + 'LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)' +) + +sfp_compliance_code_tup = ( + '10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes', 'FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia', 'FibreChannelSpeed' +) + +qsfp_compliance_code_tup = ( + '10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed' +) + +info_dict_keys = [ + 'type', 'hardware_rev', 'serial', 'manufacturer', + 'model', 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', + 'vendor_oui', 'application_advertisement', 'type_abbrv_name' +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +dom_info_dict_keys = [ + 'rx_los', 'tx_fault', 'reset_status', 'lp_mode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', + 'rx5power', 'rx6power', 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', 'tx3power', 'tx4power', + 'tx5power', 'tx6power', 'tx7power', 'tx8power'] + +threshold_dict_keys = [ + 'temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' + +#from port0_eeprom to port127_eeprom +I2C_EEPROM_PATH = "/usr/local/bin/minipack_qsfp/port{0}_eeprom" + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + # Path to sysfs + 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_minipack-r0" + HWSKU = "Accton-MINIPACK" + + def __init__(self, sfp_index=0, sfp_name=None): + self._api_helper=APIHelper() + self._index = sfp_index + self.port_num = self._index + 1 + self._name = sfp_name + self._eeprom_path = self._get_eeprom_path() + #pim = FpgaUtil() + #pim.init_pim_fpga() + #self._dom_capability_detect() + + SfpBase.__init__(self) + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + 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.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def _get_eeprom_path(self): + #print("Check _get_eeprom_path") + port_eeprom_path = I2C_EEPROM_PATH.format(self.port_num-1) + return port_eeprom_path + + def _dom_capability_detect(self): + self._detect_sfp_type() + + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == QSFP_TYPE: + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, + # through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), + XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, + QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int( + qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self._read_eeprom_specific_bytes( + QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params( + qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability[ + 'data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator( + qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.qsfp_page3_available = False + + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = ( + int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ================================================================================ + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' + + # If some port is not inserted module when xcvrd do _init_(), it will not get port_type from eeprom. + # So its defaut type is QSFP. But user can insert QSFP-DD to the port later + # So we need to check port before access port eeporm. + self._dom_capability_detect() + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_vendor_oui_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str( + sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_interface_bulk_raw[start: end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_interface_bulk_raw[start: end], 0) + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes( + offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance( + sfp_ext_specification_compliance_raw[0: 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data[ + 'data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + transceiver_dom_info_dict = dict.fromkeys( + dom_info_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_data_raw[start: end], 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + dom_data_raw = self._read_eeprom_specific_bytes( + (QSFP_DD_CHANNL_MON_OFFSET), QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str( + dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = str( + dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = str( + dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = str( + dom_channel_monitor_data['data']['TX4Power']['value']) + transceiver_dom_info_dict['tx5power'] = str( + dom_channel_monitor_data['data']['TX5Power']['value']) + transceiver_dom_info_dict['tx6power'] = str( + dom_channel_monitor_data['data']['TX6Power']['value']) + transceiver_dom_info_dict['tx7power'] = str( + dom_channel_monitor_data['data']['TX7Power']['value']) + transceiver_dom_info_dict['tx8power'] = str( + dom_channel_monitor_data['data']['TX8Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str( + dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = str( + dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = str( + dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = str( + dom_channel_monitor_data['data']['RX4Power']['value']) + transceiver_dom_info_dict['rx5power'] = str( + dom_channel_monitor_data['data']['RX5Power']['value']) + transceiver_dom_info_dict['rx6power'] = str( + dom_channel_monitor_data['data']['RX6Power']['value']) + transceiver_dom_info_dict['rx7power'] = str( + dom_channel_monitor_data['data']['RX7Power']['value']) + transceiver_dom_info_dict['rx8power'] = str( + dom_channel_monitor_data['data']['RX8Power']['value']) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str( + dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str( + dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str( + dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str( + dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str( + dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw[start: end], 0) + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disabled_channel'] = self.get_tx_disable_channel( + ) + + for key in transceiver_dom_info_dict: + val = transceiver_dom_info_dict[key] + transceiver_dom_info_dict[key] = self._convert_string_to_num( + val) if type(val) is str else val + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = dict.fromkeys( + threshold_dict_keys, NULL_VAL) + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values( + dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold( + dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + 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 True #FPGA SPEC:It is set to 1 if the corresponding QSFP is not present + + pim=FpgaUtil() + val=pim.get_reset(self.port_num-1) + if val is not None: + return val==1 + else: + return False + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + rx_los_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + rx_los_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return [False] + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + tx_fault_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + tx_fault_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return [False] + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 + else: # SFP_TYPE + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return [False] + return tx_disable_list + + 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 + """ + pim = FpgaUtil() + return pim.get_low_power_mode(self.port_num-1)==1 + + def get_power_set(self): + + if self.sfp_type == SFP_TYPE: + # SFP doesn't support this feature + return False + else: + power_set = False + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + power_set = ( + 'On' == dom_control_data['data']['PowerSet']['value']) + + return power_set + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes( + dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']['value']) + else: + return False + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return default + else: + return default + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return tx_power_list + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_power_list + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return default + else: + return default + return tx_power_list + + 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 + + pim = FpgaUtil() + time.sleep(0.2) + pim.reset(self.port_num-1) + time.sleep(0.2) + return True + + 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 == QSFP_TYPE: + sysfsfile_eeprom = None + try: + tx_disable_value = 0xf if tx_disable else 0x0 + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + elif self.sfp_type == SFP_TYPE: + disable_path = "{}{}{}".format(self.i2c_cpld_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 tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + + 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 + """ + pim = FpgaUtil() + pim.set_low_power_mode(self.port_num-1, lpmode) + return True + + 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 == SFP_TYPE: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + try: + power_override_bit = (1 << 0) if power_override else 0 + power_set_bit = (1 << 1) if power_set else (1 << 3) + + buffer = create_string_buffer(1) + if sys.version_info[0] >= 3: + buffer[0] = (power_override_bit | power_set_bit) + else: + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + port_eeprom_path = I2C_EEPROM_PATH.format(self.port_num-1) + with open(port_eeprom_path, "r+b") as fd: + fd.seek(QSFP_POWEROVERRIDE_OFFSET) + fd.write(buffer[0]) + time.sleep(0.01) + except Exception as e: + print ('Error: unable to open file: ', str(e)) + return False + return True + + ############################################################## + ###################### 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()) + name = sfputil_helper.logical[self._index] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + #print("Check get_presence, self.port_num=%d" %(self.port_num)) + #self._dom_capability_detect() + pim = FpgaUtil() + + status = pim.get_qsfp_presence(self.port_num-1) + #print("Port=%d , presence=%d"%(self.port_num, status)) + if status is not None: + return status==1 + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + return transceiver_dom_info_dict.get("model", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + return transceiver_dom_info_dict.get("serial", "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 self.get_presence() and not self.get_reset_status() + + def get_cc_base(self): + if self.sfp_type == SFP_TYPE: + get_data = self._read_eeprom_specific_bytes( + 0, 63) if self.get_presence() else None + if get_data is None: + return False + + get_sum=0 + for i in range(0, 63): + get_sum=get_sum + int(get_data[i], 16) + + ccb= get_sum & 0xff + + ccb_data = self._read_eeprom_specific_bytes( + XCVR_CC_BASE_OFFSET, 2) if self.get_presence() else None + + + if int(ccb_data[0], 16) == ccb: + return True + else: + return False + elif self.sfp_type == QSFP_TYPE or self.sfp_type == QSFP_DD_TYPE: + offset=128 + get_data = self._read_eeprom_specific_bytes( + offset, 63) if self.get_presence() else None + if get_data is None: + return False + + get_sum=0 + for i in range(0, 63): + get_sum=get_sum + int(get_data[i], 16) + + ccb= get_sum & 0xff + + ccb_data = self._read_eeprom_specific_bytes( + offset + XCVR_CC_BASE_OFFSET, 2) if self.get_presence() else None + + + if int(ccb_data[0], 16) == ccb: + return True + else: + return False + + return False + + 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 diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py new file mode 100644 index 000000000000..317a2aab1cc2 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/thermal.py @@ -0,0 +1,155 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +DEVICE_PATH ="/sys/bus/platform/devices/minipack_psensor/" + +THERMAL_NAME_LIST = ["Temp sensor 1", "Temp sensor 2", + "Temp sensor 3", "Temp sensor 4", + "Temp sensor 5", "Temp sensor 6", + "Temp sensor 7", "Temp sensor 8",] + +PSU_THERMAL_NAME_LIST = ["PSU-1 temp sensor 1", "PSU-2 temp sensor 1", + "PSU-3 temp sensor 1", "PSU-4 temp sensor 1"] + +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.hwmon_path = DEVICE_PATH + self._api_helper = APIHelper() + + self.ss_key = THERMAL_NAME_LIST[self.index] + self.ss_index = 1 + + 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() + return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): + + raw_temp=self._api_helper.read_txt_file(temp_file) + if raw_temp is not None: + return float(raw_temp)/1000 + else: + return 0 + + def __set_threshold(self, file_name, temperature): + + 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_path = "{}{}{}{}".format(self.hwmon_path, 'temp', self.index+1, '_input') + else: + temp_path = "{}{}{}{}".format(self.hwmon_path, 'psu', self.psu_index+1, '_temp_input') + + return self.__get_temp(temp_path) + + 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 + """ + return 80 + + 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 + """ + return False + + 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 + """ + return self.get_temperature()!=0 + + 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_temperature()!=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 diff --git a/device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json new file mode 100644 index 000000000000..a1099b81c978 --- /dev/null +++ b/device/accton/x86_64-accton_minipack-r0/system_health_monitoring_config.json @@ -0,0 +1,14 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "ControlledByBMC", + "normal": "ControlledByBMC", + "booting": "ControlledByBMC" + } +} diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index 8cd7611bb6e3..7a490e03638b 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -45,6 +45,10 @@ build: $(PYTHON3) sonic_platform_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ echo "Finished makig whl package for $$mod"; \ fi; \ + if [ -f fpga_setup.py ]; then\ + $(PYTHON3) fpga_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ + mv $(MOD_SRC_DIR)/$${mod}/minipack_platform_fpga-1.0-cp3*.whl $(MOD_SRC_DIR)/$${mod}/minipack_platform_fpga-1.0-py3-none-any.whl; \ + fi;\ cd $(MOD_SRC_DIR); \ done) diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install new file mode 100644 index 000000000000..b0534a7b8398 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-minipack.install @@ -0,0 +1,3 @@ +minipack/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_minipack-r0 +minipack/minipack_platform_fpga-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_minipack-r0 + diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py new file mode 100644 index 000000000000..fce1b0ca6d20 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py @@ -0,0 +1,587 @@ +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/29/2019: Jostar create for minipack +# ----------------------------------------------------------- +try: + import time # this is only being used as part of the example + import fbfpgaio + import sys + +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +# pimutil.py +# +# Platform-specific PIM interface for SONiC +# + +iob = { + "revision": 0x0, + "scratchpad": 0x4, + "interrupt_status": 0x2C, + "pim_status": 0x40, + "pim_present_intr_mask": 0x44, +} + +dom_base = [ + 0xFFFFFFFF, # Padding + 0x40000, + 0x48000, + 0x50000, + 0x58000, + 0x60000, + 0x68000, + 0x70000, + 0x78000, +] + + +dom = { + "revision": 0x0, + "system_led": 0xC, + "intr_status": 0x2C, + "qsfp_present": 0x48, + "qsfp_present_intr": 0x50, + "qsfp_present_intr_mask": 0x58, + "qsfp_intr": 0x60, + "qsfp_intr_mask": 0x68, + "qsfp_reset": 0x70, + "qsfp_lp_mode": 0x78, + "device_power_bad_status": 0x90, + "port_led_color_profile": { + 0: 0x300, + 1: 0x300, + 2: 0x304, + 3: 0x304, + 4: 0x308, + 5: 0x308, + 6: 0x30C, + 7: 0x30C, + }, + "port_led_control": { + 1: 0x310, + 2: 0x314, + 3: 0x318, + 4: 0x31C, + 5: 0x320, + 6: 0x324, + 7: 0x328, + 8: 0x32C, + 9: 0x330, + 10: 0x334, + 11: 0x338, + 12: 0x33C, + 13: 0x340, + 14: 0x344, + 15: 0x348, + 16: 0x34C, + }, + "dom_control_config": 0x410, + "dom_global_status": 0x414, + "dom_data": 0x4000, + + + "mdio": { + "config": 0x0200, + "command": 0x0204, + "write": 0x0208, + "read": 0x020C, + "status": 0x0210, + "intr_mask": 0x0214, + "source_sel": 0x0218, + }, # mdio +} + +mdio_read_cmd = 0x1 +mdio_write_cmd = 0x0 +mdio_device_type = 0x1F + + +#fbfpgaio=cdll.LoadLibrary('./fbfpgaio.so') + +def init_resources(): + fbfpgaio.hw_init() + return + +def release_resources(): + fbfpgaio.hw_release() + return + +def fpga_io(offset, data=None): + if data is None: + return fbfpgaio.hw_io(offset) + else: + fbfpgaio.hw_io(offset, data) + return + +def pim_io(pim, offset, data=None): + global dom_base + target_offset = dom_base[pim]+offset + if data is None: + retval = fpga_io(target_offset) + #print ("0x%04X" % retval) # idebug + return retval + else: + retval = fpga_io(target_offset, data) + return retval + + +def show_pim_present(): + pim_status = fpga_io(iob["pim_status"]) + + header = "PIM # " + status_str = " " + for shift in range(0,8): + status = pim_status & (0x10000 << shift) #[23:16] from pim_0 to pim_7 + header += " %d " % (shift+1) + if status: + status_str += (" | ") + else: + status_str += (" X ") + print(header) + print(status_str) + +def show_qsfp_present_status(pim_num): + status = fpga_io(dom_base[pim_num]+dom["qsfp_present"]) + interrupt = fpga_io(dom_base[pim_num]+dom["qsfp_present_intr"]) + mask = fpga_io(dom_base[pim_num]+dom["qsfp_present_intr_mask"]) + + print + print(" (0x48) (0x50) (0x58)") + print(" 0x%08X 0x%08X 0x%08X" %(status, interrupt, mask)) + print(" Status Interrupt Mask") + for row in range(8): + output_str = str() + status_left = bool(status & (0x1 << row*2)) + status_right = bool(status & (0x2 << row*2)) + interrupt_left = bool(interrupt & (0x1 << row*2)) + interrupt_right = bool(interrupt & (0x2 << row*2)) + mask_left = bool(mask & (0x1 << row*2)) + mask_right = bool(mask & (0x2 << row*2)) + print("%2d: %d %d %d %d %d %d" % \ + (row*2+1, status_left, status_right, \ + interrupt_left, interrupt_right, \ + mask_left, mask_right)) + print + + + +#pim_index start from 0 to 7 +#port_index start from 0 to 127. Each 16-port is to one pim card. +class FpgaUtil(object): + + PORT_START = 0 + PORT_END = 127 + PIM_START = 0 + PIM_END = 7 + + def __init__(self): + self.value=1 + + def __del__(self): + self.value=0 + + def init_pim_fpga(self): + init_resources() + + def release_pim_fpga(self): + release_resources() + + def get_pim_by_port(self, port_num): + if port_num < self.PORT_START or port_num > self.PORT_END: + return False + pim_num=port_num//16 + return True, pim_num+1 + + def get_onepimport_by_port(self, port_num): + if port_num < self.PORT_START or port_num > self.PORT_END: + return False + if port_num < 16: + return True, port_num + else: + return True, port_num%16 + + def get_pim_presence(self, pim_num): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False + pim_status = fpga_io(iob["pim_status"]) + status = pim_status & (0x10000 << pim_num) + if status: + return 1 #present + else: + return 0 #not present + + #return code=0:100G. return code=1:400G + def get_pim_board_id(self, pim_num): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False + board_id = fpga_io(dom_base[pim_num+1]+dom["revision"]) + board_id = board_id & 0x1 + if board_id==0x0: + return 0 + else: + return 1 + + + def get_pim_status(self, pim_num): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return 0xFF + power_status =0 + #device_power_bad_status + status=fpga_io(dom_base[pim_num+1]+dom["device_power_bad_status"]) + + for x in range(0, 5): + if status & ( (0xf) << (4*x) ) : + power_status = power_status | (0x1 << x) + + if ( status & 0x1000000): + power_status=power_status | (0x1 << 5) + if ( status & 0x2000000): + power_status=power_status | (0x1 << 6) + if ( status & 0x8000000): + power_status=power_status | (0x1 << 7) + if ( status & 0x10000000): + power_status=power_status | (0x1 << 8) + if ( status & 0x40000000): + power_status=power_status | (0x1 << 9) + if ( status & 0x80000000): + power_status=power_status | (0x1 << 10) + + return power_status + #path=0:MDIO path is set on TH3. path=1:MDIO path is set on FPGA. + def set_pim_mdio_source_sel(self, pim_num, path): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False + status= pim_io(pim_num+1, dom["mdio"]["source_sel"]) + + if path==1: + status = status | 0x2 + else: + status = status & 0xfffffffd + + pim_io(pim_num+1, dom["mdio"]["source_sel"], status) + return True + #retrun code=0, path is TH3. retrun code=1, path is FPGA + def get_pim_mdio_source_sel(sefl, pim_num): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False + path= pim_io(pim_num+1, dom["mdio"]["source_sel"]) + path = path & 0x2 + if path: + return 1 + else: + return 0 + + #This api will set mdio path to MAC side.(At default, mdio path is set to FPGA side). + def pim_init(self, pim_num): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False + status=self.set_pim_mdio_source_sel(pim_num, 0) + #put init phy cmd here + + + #return code="pim_dict[pim_num]='1' ":insert evt. return code="pim_dict[pim_num]='0' ":remove evt + def get_pim_change_event(self, timeout=0): + start_time = time.time() + pim_dict = {} + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print("get_transceiver_change_event:Invalid timeout value=%d"%(timeout)) + return False, {} + + end_time = start_time + timeout + if start_time > end_time: + print('get_transceiver_change_event:' \ + 'time wrap / invalid timeout value=%d'%timeout) + + return False, {} # Time wrap or possibly incorrect timeout + + pim_mask_status = fpga_io(iob["pim_present_intr_mask"], 0xffff00000) + + while timeout >= 0: + new_pim_status=0 + pim_status = fpga_io(iob["pim_status"]) + present_status= pim_status & 0xff0000 + change_status=pim_status & 0xff + interrupt_status = fpga_io(iob["interrupt_status"]) + + for pim_num in range(0,8): + if change_status & (0x1 << pim_num) : + status = present_status & (0x10000 << pim_num) + new_pim_status = new_pim_status | (0x1 << pim_num) #prepare to W1C to clear + if status: + pim_dict[pim_num]='1' + else: + pim_dict[pim_num]='0' + + if change_status: + new_pim_status = pim_status | new_pim_status #Write one to clear interrupt bit + fpga_io(iob["pim_status"], new_pim_status) + return True, pim_dict + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, {} + print("get_evt_change_event: Should not reach here.") + return False, {} + + + def get_pim_max_number(self): + return 8 + + #pim_num start from 0 to 7 + #color:0=amber, 1=blue + #contrl:off(0),on(1), flash(2) + def set_pim_led(self, pim_num, color, control): + if pim_num < self.PIM_START or pim_num > self.PIM_END: + return False + + led_val=fpga_io(dom_base[pim_num+1]+dom["system_led"]) + + if color==1: + led_val = led_val | (0x8000 | 0x4000) #blue + elif color==0: + led_val = (led_val & ( ~ 0x8000)) | 0x4000 #amber + else: + + led_val = led_val & (~ 0x4000) + led_val = led_val & (~ 0xfff) + led_val = led_val | 0x0f0 #B.G.R Birghtness, set to Green + + if control==0: + led_val = led_val & ( ~ 0x3000) #Off + elif control==1: + led_val = led_val & ( ~ 0x3000) #Off + led_val = led_val | 0x1000 #On + else: + led_val = led_val | 0x3000 #Flash + + fpga_io(dom_base[pim_num+1]+dom["system_led"], led_val) + + def get_qsfp_presence(self, port_num): + #xlate port to get pim_num + status, pim_num=self.get_pim_by_port(port_num) + + if status==0: + return False + else: + present = fpga_io(dom_base[pim_num]+dom["qsfp_present"]) + status, shift = self.get_onepimport_by_port(port_num) + if status==0: + return False + else: + if bool(present & (0x1 << shift)): + return 1 #present + else: + return 0 #not present + + #return code: low_power(1) or high_power(0) + def get_low_power_mode(self, port_num): + status, pim_num=self.get_pim_by_port(port_num) + + if status==0: + return False + else: + lp_mode = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"]) + + status, shift=self.get_onepimport_by_port(port_num) + if status==0: + return False + else: + if (lp_mode & (0x1 << shift)): + return 1 #low + else: + return 0 #high + + #lpmode=1 to hold QSFP in low power mode. lpmode=0 to release QSFP from low power mode. + def set_low_power_mode(self, port_num, mode): + status, pim_num=self.get_pim_by_port(port_num) + if status==0: + return False + val = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"]) + status, shift=self.get_onepimport_by_port(port_num) + if status==0: + return False + else: + if mode==0: + new_val = val & (~(0x1 << shift)) + else: + new_val=val|(0x1 << shift) + status=fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"], new_val) + return status + + #port_dict[idx]=1 means get interrupt(change evt), port_dict[idx]=0 means no get interrupt + def get_qsfp_interrupt(self): + port_dict={} + #show_qsfp_present_status(1) + for pim_num in range(0, 8): + fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr_mask"], 0xffff0000) + fpga_io(dom_base[pim_num+1]+dom["qsfp_intr_mask"], 0xffff0000) + for pim_num in range(0, 8): + clear_bit=0 + qsfp_present_intr_status = fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr"]) + interrupt_status = qsfp_present_intr_status & 0xffff + #time.sleep(2) + if interrupt_status: + for idx in range (0,16): + port_idx=idx + (pim_num*16) + if interrupt_status & (0x1< #include #include @@ -119,13 +120,6 @@ static char docstr[] = "\ In reading operation: data which is read from FPGA\n\ In writing operation: None\n"; -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC -initfbfpgaio(void) -{ - (void) Py_InitModule3("fbfpgaio", FbfpgaMethods, docstr); -} -#else static struct PyModuleDef FbfpgaModule = { PyModuleDef_HEAD_INIT, @@ -140,5 +134,5 @@ PyInit_fbfpgaio(void) { return PyModule_Create(&FbfpgaModule); } -#endif + diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c b/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c index 3155b2b27c4f..72826f46093a 100755 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/modules/minipack_psensor.c @@ -62,7 +62,8 @@ MODULE_PARM_DESC(poll_interval, "Time interval for data polling, in unit of seco #define CHASSIS_LED_COUNT (2) #define CHASSIS_PSU_VOUT_COUNT (1) /*V output only.*/ #define CHASSIS_PSU_VOUT_INDEX (1) /*V output start index.*/ - +#define MAX_MODEL_NAME 21 +#define MAX_SERIAL_NUMBER 19 #define ATTR_ALLOC_EXTRA 1 /*For last attribute which is NUll.*/ #define ATTR_NAME_SIZE 24 @@ -102,6 +103,14 @@ enum sensor_type_e { SENSOR_TYPE_PSU2, SENSOR_TYPE_PSU3, SENSOR_TYPE_PSU4, + SENSOR_TYPE_PSU1_MODEL, + SENSOR_TYPE_PSU2_MODEL, + SENSOR_TYPE_PSU3_MODEL, + SENSOR_TYPE_PSU4_MODEL, + SENSOR_TYPE_PSU1_SERIAL, + SENSOR_TYPE_PSU2_SERIAL, + SENSOR_TYPE_PSU3_SERIAL, + SENSOR_TYPE_PSU4_SERIAL, SENSOR_TYPE_MAX, }; @@ -113,6 +122,14 @@ enum sysfs_attributes_index { INDEX_PSU2_START = SENSOR_TYPE_PSU2 *ATTR_TYPE_INDEX_GAP, INDEX_PSU3_START = SENSOR_TYPE_PSU3 *ATTR_TYPE_INDEX_GAP, INDEX_PSU4_START = SENSOR_TYPE_PSU4 *ATTR_TYPE_INDEX_GAP, + INDEX_PSU1_MODEL = SENSOR_TYPE_PSU1_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU2_MODEL = SENSOR_TYPE_PSU2_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU3_MODEL = SENSOR_TYPE_PSU3_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU4_MODEL = SENSOR_TYPE_PSU4_MODEL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU1_SERIAL = SENSOR_TYPE_PSU1_SERIAL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU2_SERIAL = SENSOR_TYPE_PSU2_SERIAL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU3_SERIAL = SENSOR_TYPE_PSU3_SERIAL *ATTR_TYPE_INDEX_GAP, + INDEX_PSU4_SERIAL = SENSOR_TYPE_PSU4_SERIAL *ATTR_TYPE_INDEX_GAP, INDEX_NAME = SENSOR_TYPE_MAX *ATTR_TYPE_INDEX_GAP, }; @@ -123,6 +140,9 @@ enum sysfs_attributes_index { #define PMBUS_READ_IOUT 0x8C #define PMBUS_READ_POUT 0x96 #define PMBUS_READ_PIN 0x97 +#define PMBUS_READ_FAN 0x90 +#define PMBUS_READ_TEMP 0x8D + #define PMBUS_REG_START PMBUS_READ_VIN #define PMBUS_REG_END PMBUS_READ_PIN @@ -134,6 +154,8 @@ enum psu_data_e { PSU_DATA_IOUT, PSU_DATA_PIN, PSU_DATA_POUT, + PSU_DATA_FAN, + PSU_DATA_TEMP, PSU_DATA_MAX, }; @@ -147,6 +169,8 @@ struct pmbus_reg_t { [PSU_DATA_IOUT] = {PMBUS_READ_IOUT, false}, [PSU_DATA_PIN ] = {PMBUS_READ_PIN, true}, [PSU_DATA_POUT] = {PMBUS_READ_POUT, true}, + [PSU_DATA_FAN] = {PMBUS_READ_FAN, false}, + [PSU_DATA_TEMP] = {PMBUS_READ_TEMP, false}, }; struct sensor_data { @@ -154,6 +178,8 @@ struct sensor_data { int fan_rpm[MAX_FAN_COUNT]; int fan_rpm_dn[MAX_FAN_COUNT]; int psu_data [MAX_PSU_COUNT][PSU_DATA_MAX]; + int psu_model [MAX_PSU_COUNT][MAX_MODEL_NAME]; + int psu_serial [MAX_PSU_COUNT][MAX_SERIAL_NUMBER]; int led_bright[CHASSIS_LED_COUNT]; }; @@ -225,6 +251,10 @@ static struct attr_pattern psu##index##_curr = {CHASSIS_PSU_CHAR_COUNT, \ CHASSIS_PSU_CHAR_COUNT*index, "curr","_input", S_IRUGO, _attr_show, NULL}; \ static struct attr_pattern psu##index##_pwr = {CHASSIS_PSU_CHAR_COUNT, \ CHASSIS_PSU_CHAR_COUNT*index, "power","_input", S_IRUGO, _attr_show, NULL}; \ +static struct attr_pattern psu##index##_fan_speed = {1, \ +1*index, "psu","_fan_speed", S_IRUGO, _attr_show, NULL}; \ +static struct attr_pattern psu##index##_temp_input = {1, \ +1*index, "psu","_temp_input", S_IRUGO, _attr_show, NULL}; \ static struct attr_pattern psu##index##_vmax = {CHASSIS_PSU_VOUT_COUNT, \ CHASSIS_PSU_CHAR_COUNT*index + 1, "in","_max", S_IRUGO, show_psu_vout_max, NULL};\ static struct attr_pattern psu##index##_vmin = {CHASSIS_PSU_VOUT_COUNT, \ @@ -232,7 +262,21 @@ CHASSIS_PSU_CHAR_COUNT*index + 1, "in","_min", S_IRUGO, show_psu_vout_min, NULL} #define DECLARE_PSU_ATTR(index) \ &psu##index##_vin, &psu##index##_curr, &psu##index##_pwr, \ - &psu##index##_vmax, &psu##index##_vmin + &psu##index##_fan_speed, &psu##index##_temp_input ,&psu##index##_vmax, &psu##index##_vmin + +#define DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(index) \ +static struct attr_pattern psu##index##_model_name = {1, \ +1*index, "psu","_model_name", S_IRUGO, _attr_show, NULL}; + +#define DECLARE_PSU_MODEL_NAME_ATTR(index) \ + &psu##index##_model_name + +#define DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(index) \ +static struct attr_pattern psu##index##_serial_name = {1, \ +1*index, "psu","_serial_num", S_IRUGO, _attr_show, NULL}; + +#define DECLARE_PSU_SERIAL_NUMBER_ATTR(index) \ + &psu##index##_serial_name DECLARE_PSU_SENSOR_DEVICE_ATTR(0); @@ -240,6 +284,15 @@ DECLARE_PSU_SENSOR_DEVICE_ATTR(1); DECLARE_PSU_SENSOR_DEVICE_ATTR(2); DECLARE_PSU_SENSOR_DEVICE_ATTR(3); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(0); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(1); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(2); +DECLARE_PSU_MODEL_NAME_SENSOR_DEVICE_ATTR(3); + +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(0); +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(1); +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(2); +DECLARE_PSU_SERIAL_NUMBER_SENSOR_DEVICE_ATTR(3); static char tty_cmd[SENSOR_TYPE_MAX][TTY_CMD_MAX_LEN] = { @@ -259,6 +312,14 @@ static char tty_cmd[SENSOR_TYPE_MAX][TTY_CMD_MAX_LEN] = { "i2cdump -y -f -r "\ __stringify(PMBUS_REG_START)"-" __stringify(PMBUS_REG_END)\ " 56 0x58 w\r", + "i2cdump -y -f 49 0x59 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 48 0x58 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 57 0x59 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 56 0x58 s 0x9a|tail -n +2|cut -c56-\r", + "i2cdump -y -f 49 0x59 s 0x9e|tail -n +2|cut -c56-\r", + "i2cdump -y -f 48 0x58 s 0x9e|tail -n +2|cut -c56-\r", + "i2cdump -y -f 57 0x59 s 0x9e|tail -n +2|cut -c56-\r", + "i2cdump -y -f 56 0x58 s 0x9e|tail -n +2|cut -c56-\r", }; static struct attr_pattern temp_in = @@ -305,6 +366,31 @@ struct sensor_set model_ssets[SENSOR_TYPE_MAX] = { PSU_DATA_MAX, INDEX_PSU4_START, tty_cmd[SENSOR_TYPE_PSU4], TTY_PMBUS_INTERVAL, {DECLARE_PSU_ATTR(3), NULL}, }, + { 1, INDEX_PSU1_MODEL, tty_cmd[SENSOR_TYPE_PSU1_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(0), NULL}, + }, + { 1, INDEX_PSU2_MODEL, tty_cmd[SENSOR_TYPE_PSU2_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(1), NULL}, + }, + { 1, INDEX_PSU3_MODEL, tty_cmd[SENSOR_TYPE_PSU3_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(2), NULL}, + }, + { 1, INDEX_PSU4_MODEL, tty_cmd[SENSOR_TYPE_PSU4_MODEL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_MODEL_NAME_ATTR(3), NULL}, + }, + { 1, INDEX_PSU1_SERIAL, tty_cmd[SENSOR_TYPE_PSU1_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(0), NULL}, + }, + { 1, INDEX_PSU2_SERIAL, tty_cmd[SENSOR_TYPE_PSU2_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(1), NULL}, + }, + { 1, INDEX_PSU3_SERIAL, tty_cmd[SENSOR_TYPE_PSU3_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(2), NULL}, + }, + { 1, INDEX_PSU4_SERIAL, tty_cmd[SENSOR_TYPE_PSU4_SERIAL], + TTY_PMBUS_INTERVAL, {DECLARE_PSU_SERIAL_NUMBER_ATTR(3), NULL}, + }, + }; static struct minipack_data *mp_data = NULL; @@ -359,9 +445,7 @@ static int _tty_open(struct file **fd) kt.c_iflag = IGNPAR; kt.c_oflag = 0; kt.c_lflag = 0; - kt.c_cc[VMIN] = (unsigned char) - ((MAXIMUM_TTY_STRING_LENGTH > 0xFF) ? - 0xFF : MAXIMUM_TTY_STRING_LENGTH); + kt.c_cc[VMIN] = 0; kt.c_cc[VTIME] = 0; tty_set_termios(tty, &kt); @@ -393,11 +477,9 @@ static int _tty_tx(struct file *tty_fd, const char *str) /*Sanity check*/ if (tty_fd == NULL) return -EINVAL; - if(!(tty_fd->f_op) || !(tty_fd->f_op->read) ||!(tty_fd->f_op->write)) { - return -EINVAL; - } - rc = tty_fd->f_op->write(tty_fd, str, strlen(str)+1,0); + rc = kernel_write(tty_fd, str, strlen(str)+1,0); + if (rc < 0) { pr_info( "failed to write(%d)\n", rc); return -EBUSY; @@ -414,14 +496,11 @@ static int _tty_rx(struct file *tty_fd, char *buf, int max_len) /*Sanity check*/ if (tty_fd == NULL) return -EINVAL; - if(!(tty_fd->f_op) || !(tty_fd->f_op->read) ||!(tty_fd->f_op->write)) { - return -EINVAL; - } /*Clear for remained data cause ambiguous string*/ memset(buf, 0, max_len); do { - rc = tty_fd->f_op->read(tty_fd, buf, max_len, 0); + rc = kernel_read(tty_fd, buf, max_len, 0); if (rc == 0) { /*Buffer Empty, waits. */ timeout++; _tty_wait(TTY_RETRY_INTERVAL); @@ -441,22 +520,19 @@ static int _tty_rx(struct file *tty_fd, char *buf, int max_len) /*Clear Rx buffer by reading it out.*/ static int _tty_clear_rxbuf(struct file *tty_fd, char* buf, size_t max_size) { int rc, i; - mm_segment_t old_fs; int retry = TTY_CMD_RETRY; if (tty_fd == NULL) { return -EINVAL; } - old_fs = get_fs(); - set_fs(KERNEL_DS); + i = 0; do { - rc = tty_fd->f_op->read(tty_fd, buf, max_size, 0); + rc = kernel_read(tty_fd, buf, max_size, 0); memset(buf, 0, max_size); i++; } while (rc > 0 && i < retry); - set_fs(old_fs); return rc; } @@ -464,20 +540,13 @@ static int _tty_writeNread(struct file *tty_fd, char *wr_p, char *rd_p, int rx_max_len, u32 mdelay) { int rc; - mm_segment_t old_fs; /*Presumed file is opened!*/ if (tty_fd == NULL) return -EINVAL; - if(!(tty_fd->f_op) || !(tty_fd->f_op->read) ||!(tty_fd->f_op->write)) { - pr_info("file %s cann't readable or writable?\n", TTY_DEVICE); - return -EINVAL; - } - memset(rd_p, 0, rx_max_len); - old_fs = get_fs(); - set_fs(KERNEL_DS); + rc = _tty_tx(tty_fd, wr_p); if (rc < 0) { DEBUG_INTR( "failed to write(%d)\n", rc); @@ -491,7 +560,6 @@ static int _tty_writeNread(struct file *tty_fd, } exit: - set_fs(old_fs); return rc; } @@ -810,6 +878,27 @@ static int get_pmbus_regs_partial(int *in, int in_cnt, int *out, int *out_cnt) return 0; } +static int extract_psu_str(int type, char *buf, int *out, int len) +{ + char *ptr; + int x, i; + + ptr = buf; + + i=0; + for (x = 0; x < strlen(ptr); x++) { + if(ptr[x] > 0x7A || ptr[x] <0x1E) + continue; + + out[i]=ptr[x]; + i++; + if(i==(len-2)) + break; + } + out[len-1]=0x0; + + return 0; +} static int comm2BMC(enum sensor_type_e type, int *out, int out_cnt) { @@ -853,6 +942,18 @@ static int comm2BMC(enum sensor_type_e type, int *out, int out_cnt) get_pmbus_regs_partial(reg, total, out, &out_cnt); break; } + case SENSOR_TYPE_PSU1_MODEL: + case SENSOR_TYPE_PSU2_MODEL: + case SENSOR_TYPE_PSU3_MODEL: + case SENSOR_TYPE_PSU4_MODEL: + ret=extract_psu_str(type, ptr, out, MAX_MODEL_NAME); + break; + case SENSOR_TYPE_PSU1_SERIAL: + case SENSOR_TYPE_PSU2_SERIAL: + case SENSOR_TYPE_PSU3_SERIAL: + case SENSOR_TYPE_PSU4_SERIAL: + ret=extract_psu_str(type ,ptr, out, MAX_SERIAL_NUMBER); + break; default: return -EINVAL; } @@ -882,6 +983,18 @@ static int get_type_data ( case SENSOR_TYPE_PSU4: *out = &data->psu_data[type-SENSOR_TYPE_PSU1][index]; break; + case SENSOR_TYPE_PSU1_MODEL: + case SENSOR_TYPE_PSU2_MODEL: + case SENSOR_TYPE_PSU3_MODEL: + case SENSOR_TYPE_PSU4_MODEL: + *out = &data->psu_model[type-SENSOR_TYPE_PSU1_MODEL][index]; + break; + case SENSOR_TYPE_PSU1_SERIAL: + case SENSOR_TYPE_PSU2_SERIAL: + case SENSOR_TYPE_PSU3_SERIAL: + case SENSOR_TYPE_PSU4_SERIAL: + *out = &data->psu_serial[type-SENSOR_TYPE_PSU1_SERIAL][index]; + break; default: return -EINVAL; } @@ -942,6 +1055,9 @@ static ssize_t _attr_show(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct sensor_data* data; int *out = NULL; + int i; + char model_name[MAX_MODEL_NAME]; + char serial_number[MAX_SERIAL_NUMBER]; enum sensor_type_e type; type = attr->index / ATTR_TYPE_INDEX_GAP; @@ -958,6 +1074,35 @@ static ssize_t _attr_show(struct device *dev, struct device_attribute *da, if( index > count) return -EINVAL; + + if(type >=SENSOR_TYPE_PSU1_MODEL && type <=SENSOR_TYPE_PSU4_MODEL) + { + for(i=0; i=SENSOR_TYPE_PSU1_SERIAL && type <=SENSOR_TYPE_PSU4_SERIAL) + { + + for(i=0; i. -# -# Description: -# Due to adoption of optoe drivers, sideband signals of SFPs are moved -# into cpld drivers. Add a new dict, cpld_of_module, for mapping this -# attributes to corresponding cpld nodes. -# - """ Usage: %(scriptName)s [options] command object @@ -32,17 +25,13 @@ 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 led|sfp """ - import subprocess import getopt import sys import logging -import re import time +import os PROJECT_NAME = 'minipack' version = '0.2.0' @@ -50,24 +39,11 @@ DEBUG = False args = [] ALL_DEVICE = {} -DEVICE_NO = {'led':5, 'psu':2, 'sfp':32} - - -led_prefix ='' -hwmon_types = {'led': ['diag','loc'], - } -hwmon_nodes = {'led': ['brightness'] , - } -hwmon_prefix ={'led': led_prefix, - } i2c_prefix = '/sys/bus/i2c/devices/' i2c_bus = { 'psu': ['35-0038','36-003b'], 'sfp': ['-0050']} -i2c_nodes = { - 'psu': ['psu_present ', 'psu_power_good'] , - 'sfp': ['module_present_', 'sfp_tx_disable']} NO_QSFP = 128 @@ -123,22 +99,15 @@ 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() + elif arg == 'fpga': + do_minipack_fpga_install() + elif arg == 'fpga_clean': + do_minipack_fpga_clean() + else: show_help() @@ -149,18 +118,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]") - print(" use \""+ cmd + " led 0-4 \" to set led color") - print(" use \""+ cmd + " sfp 1-32 {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) @@ -177,7 +134,7 @@ def log_os_system(cmd, show): if status: logging.info('Failed :'+cmd) if show: - print(('Failed :'+cmd)) + print('Failed :'+cmd) return status, output def driver_inserted(): @@ -225,7 +182,7 @@ def driver_uninstall(): def sfp_map(index): port = index + 1 - base = ((port-1)/8*8) + 10 + base = ((port-1)//8*8) + 10 index = (port - 1) % 8 index = 7 - index if (index%2): @@ -276,6 +233,80 @@ 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 + +MINIPACK_FPGA_WHL_FILE_PY3 ='minipack_platform_fpga-1.0-py3-none-any.whl' +def do_minipack_fpga_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + MINIPACK_FPGA_BSP_WHL_PKG_PY3 = "/".join([device_path, MINIPACK_FPGA_WHL_FILE_PY3]) + + status, output = log_os_system("pip3 show minipack-platform-fpga > /dev/null 2>&1", 0) + if status: + if os.path.exists(MINIPACK_FPGA_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ MINIPACK_FPGA_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(MINIPACK_FPGA_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(MINIPACK_FPGA_WHL_FILE_PY3)) + else: + print('{} is not found'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + else: + print('{} has installed'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + + return + +def do_minipack_fpga_clean(): + status, output = log_os_system("pip3 show minipack-platform-fpga > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall minipack-platform-fpga -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(MINIPACK_FPGA_WHL_FILE_PY3)) + + return + def do_install(): print("Checking system....") if driver_inserted() == False: @@ -293,7 +324,9 @@ def do_install(): if FORCE == 0: return status else: - print(PROJECT_NAME.upper()+" devices detected....") + print( PROJECT_NAME.upper()+" devices detected....") + do_sonic_platform_install() + do_minipack_fpga_install() return def do_uninstall(): @@ -316,165 +349,10 @@ def do_uninstall(): if FORCE == 0: return status + do_sonic_platform_clean() + do_minipack_fpga_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 'sfp' == key: - for k in range(0,DEVICE_NO[key]): - bus = 1 - node = key+str(k+1) - path = i2c_prefix + str(bus) + lk + "/"+ nodes[j] + str(k+1) - 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 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]=='sfp': - if int(args[1])> DEVICE_NO[args[0]] 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 - - #print ALL_DEVICE[args[0]] - for i in range(0,len(ALL_DEVICE[args[0]])): - for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: - if j.find('tx_disable')!= -1: - ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) - if ret: - 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 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=' ') - for k in (ALL_DEVICE[i][j]): - 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: - print(func+"="+log+" ", end=' ') - else: - print(func+"="+"X"+" ", end=' ') - print() - print("----------------------------------------------------------------") - - - print() - return def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0) diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py b/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py index 5ef6a4107e35..dbfcb114944e 100755 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/utils/setup_qsfp_eeprom.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (c) 2019 Edgecore Networks Corporation # @@ -21,17 +21,18 @@ # ------------------------------------------------------------------ try: + import os import getopt import sys import subprocess + import imp import logging import logging.config import logging.handlers import types import time # this is only being used as part of the example - import traceback - from tabulate import tabulate - from minipack.pimutil import PimUtil + import traceback + from minipack.fpgautil import FpgaUtil except ImportError as e: raise ImportError('%s - required module not found' % str(e)) @@ -57,7 +58,7 @@ oom_i2c_bus_table=1 -pim_dev=PimUtil() +pim_dev=FpgaUtil() # Deafults VERSION = '1.0' @@ -82,7 +83,7 @@ def log_os_system(cmd): def qsfp_map_bus(idx): port = idx + 1 - base = ((port-1)/8*8) + 10 + base = ((port-1)//8*8) + 10 idx = (port - 1) % 8 idx = 7 - idx if (idx%2): @@ -91,23 +92,23 @@ def qsfp_map_bus(idx): idx = idx +1 bus = base + idx return bus - + def pca9548_sysfs(i2c_bus, create): - if create==1: + if create==1: cmdl = "echo pca9548 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device" else: - cmdl = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" - + cmdl = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" + cmdm = cmdl % (0x72, i2c_bus) - status1, output =log_os_system(cmdm) + status1, output =log_os_system(cmdm) cmdm = cmdl % (0x71, i2c_bus) status2, output =log_os_system(cmdm) return (status1 | status2) -def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create): +def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create): # initialize multiplexer for 8 PIMs - global port_use_i2c_bus + global port_use_i2c_bus start_port=pim_idx*16 end_port = (pim_idx+1)*16 start_bus=(i2c_bus_order-1)*16 @@ -123,18 +124,18 @@ def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create): return 1 status, output =log_os_system( "echo port"+str(k+1)+" > /sys/bus/i2c/devices/"+str(bus)+"-0050/port_name") - + status, output =log_os_system( "ln -s -f /sys/bus/i2c/devices/"+str(bus)+"-0050/eeprom" + " /usr/local/bin/minipack_qsfp/port" + str(k) + "_eeprom") if status: print(output) return 1 - else: + else: status, output =log_os_system( "echo 0x50 > /sys/bus/i2c/devices/i2c-"+str(bus)+"/delete_device") if status: print(output) - + k=k+1 return 0 @@ -149,31 +150,31 @@ def set_pim_port_use_bus(pim_idx): global pim_port_use_bus global oom_i2c_bus_table - + if pim_port_use_bus[pim_idx]!=0: return 0 - + pim_port_use_bus[pim_idx]=oom_i2c_bus_table oom_i2c_bus_table=oom_i2c_bus_table+1 - + return pim_port_use_bus[pim_idx] - + def del_pim_port_use_bus(pim_idx): global oom_i2c_bus_table - + oom_i2c_bus_table=oom_i2c_bus_table-1 pim_port_use_bus[pim_idx]=0 - -def device_remove(): - cmd1 = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" - - for bus in range(2, 10): + +def device_remove(): + cmd1 = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device" + + for bus in range(2, 10): #ret=check_pca_active(0x72, bus) #if ret==0: - - cmdm= cmd1 % (0x72, bus) + + cmdm= cmd1 % (0x72, bus) status, output = subprocess.getstatusoutput(cmdm) print("Remove %d-0072 i2c device"%bus) cmdm= cmd1 % (0x71, bus) @@ -183,13 +184,13 @@ def device_remove(): cmd="rm -f /usr/local/bin/minipack_qsfp/port*" status, output=log_os_system(cmd) return status - + class device_monitor(object): - + PIM_STATE_REMOVE = 0 PIM_STATE_INSERT = 1 - PIM_STATE_IDLE=2 - + PIM_STATE_IDLE=2 + def __init__(self, log_file, log_level): """Needs a logger and a logger level.""" # set up logging to file @@ -209,7 +210,7 @@ def __init__(self, log_file, log_level): logging.getLogger('').addHandler(console) sys_handler = handler = logging.handlers.SysLogHandler(address = '/dev/log') - sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.WARNING) logging.getLogger('').addHandler(sys_handler) #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) @@ -217,7 +218,7 @@ def __init__(self, log_file, log_level): def manage_pim(self): global pim_dev global pim_state - + for pim_idx in range(PIM_MIN, PIM_MAX): presence=pim_dev.get_pim_presence(pim_idx) if presence==1: @@ -228,19 +229,19 @@ def manage_pim(self): logging.info("pim_state[%d] PIM_STATE_INSERT", pim_idx); pim_state[pim_idx]=self.PIM_STATE_INSERT continue - + logging.info ("pim_idx=%d oom use i2c_bus_order=%d", pim_idx, i2c_bus_order) ready=0 retry_limit=100 retry_count=0 - while retry_count < retry_limit: + while retry_count < retry_limit: ret=check_pca_active(0x72, pim_idx+2) if ret==0: ready=1 - break + break retry_count=retry_count+1 time.sleep(0.2) - + if ready==1: status=pca9548_sysfs(pim_idx+2, 1) if status: @@ -250,28 +251,28 @@ def manage_pim(self): status=qsfp_eeprom_sys(pim_idx,i2c_bus_order, 1) if status: status=pca9548_sysfs(pim_idx+2, 0) #del pca i2c device, give up set oom at this time. - del_pim_port_use_bus(pim_idx) + del_pim_port_use_bus(pim_idx) continue #ret_2=check_pca_active(0x72, pim_idx+2) #ret_1=check_pca_active(0x71, pim_idx+2) - + pim_state[pim_idx]=self.PIM_STATE_INSERT logging.info("pim_state[%d] PIM_STATE_INSERT", pim_idx); else: print("retry check 100 times for check pca addr") del_pim_port_use_bus(pim_idx) else: - if pim_state[pim_idx]==self.PIM_STATE_INSERT: + if pim_state[pim_idx]==self.PIM_STATE_INSERT: #pca9548_sysfs(pim_idx+2, 0) pim_state[pim_idx]=self.PIM_STATE_REMOVE logging.info("pim_state[%d] PIM_STATE_REMOVE", pim_idx); - + def main(argv): log_file = '%s.log' % FUNCTION_NAME log_level = logging.INFO remove_dev=0 cpu_pca_i2c_ready=0 - + if len(sys.argv) != 1: try: opts, args = getopt.getopt(argv,'hdlr',['lfile=']) @@ -288,14 +289,14 @@ def main(argv): log_file = arg elif opt in ('-r', '--remove'): remove_dev=1 - + if remove_dev==1: device_remove() return 0 monitor = device_monitor(log_file, log_level) global pim_dev pim_dev.init_pim_fpga() - + while cpu_pca_i2c_ready==0: status=check_pca_active(0x70, 1) time.sleep(0.5) @@ -303,7 +304,7 @@ def main(argv): cpu_pca_i2c_ready=1 print("Make sure CPU pca i2c device is ready") break - + while True: monitor.manage_pim() time.sleep(2) From 86f1badfdf6560429930db1ea1a6f4fe95097b31 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Wed, 19 Jan 2022 14:36:36 +0800 Subject: [PATCH 2/4] Fix LGTM alerts --- .../sonic_platform/sfp.py | 1 - .../minipack/classes/fpgautil.py | 8 +- .../minipack/classes/pimutil.py | 578 ------------------ .../minipack/utils/setup_qsfp_eeprom.py | 2 - 4 files changed, 4 insertions(+), 585 deletions(-) delete mode 100755 platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py index 7c767f24395b..6d171d5b257b 100644 --- a/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/sfp.py @@ -25,7 +25,6 @@ from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper from .helper import APIHelper from minipack.fpgautil import FpgaUtil - import fbfpgaio except ImportError as e: raise ImportError(str(e) + "- required module not found") diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py index fce1b0ca6d20..6e469630602b 100644 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py +++ b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/fpgautil.py @@ -167,7 +167,6 @@ def show_qsfp_present_status(pim_num): print(" 0x%08X 0x%08X 0x%08X" %(status, interrupt, mask)) print(" Status Interrupt Mask") for row in range(8): - output_str = str() status_left = bool(status & (0x1 << row*2)) status_right = bool(status & (0x2 << row*2)) interrupt_left = bool(interrupt & (0x1 << row*2)) @@ -278,7 +277,7 @@ def set_pim_mdio_source_sel(self, pim_num, path): pim_io(pim_num+1, dom["mdio"]["source_sel"], status) return True #retrun code=0, path is TH3. retrun code=1, path is FPGA - def get_pim_mdio_source_sel(sefl, pim_num): + def get_pim_mdio_source_sel(self, pim_num): if pim_num < self.PIM_START or pim_num > self.PIM_END: return False path= pim_io(pim_num+1, dom["mdio"]["source_sel"]) @@ -293,6 +292,7 @@ def pim_init(self, pim_num): if pim_num < self.PIM_START or pim_num > self.PIM_END: return False status=self.set_pim_mdio_source_sel(pim_num, 0) + return status #put init phy cmd here @@ -317,14 +317,14 @@ def get_pim_change_event(self, timeout=0): return False, {} # Time wrap or possibly incorrect timeout - pim_mask_status = fpga_io(iob["pim_present_intr_mask"], 0xffff00000) + fpga_io(iob["pim_present_intr_mask"], 0xffff00000) while timeout >= 0: new_pim_status=0 pim_status = fpga_io(iob["pim_status"]) present_status= pim_status & 0xff0000 change_status=pim_status & 0xff - interrupt_status = fpga_io(iob["interrupt_status"]) + fpga_io(iob["interrupt_status"]) for pim_num in range(0,8): if change_status & (0x1 << pim_num) : diff --git a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py b/platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py deleted file mode 100755 index 05b68202be3c..000000000000 --- a/platform/broadcom/sonic-platform-modules-accton/minipack/classes/pimutil.py +++ /dev/null @@ -1,578 +0,0 @@ -# Copyright (c) 2019 Edgecore Networks Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT -# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS -# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. -# -# See the Apache Version 2.0 License for specific language governing -# permissions and limitations under the License. - -# ------------------------------------------------------------------ -# HISTORY: -# mm/dd/yyyy (A.D.) -# 5/29/2019: Jostar create for minipack -# ----------------------------------------------------------- -try: - import os - import sys, getopt - import subprocess - import click - import imp - import logging - import logging.config - import logging.handlers - import types - import time # this is only being used as part of the example - import traceback - from tabulate import tabulate - import fbfpgaio - import re - import time - from select import select - #from ctypes import fbfpgaio - -except ImportError as e: - raise ImportError('%s - required module not found' % str(e)) - - -# pimutil.py -# -# Platform-specific PIM interface for SONiC -# - -iob = { - "revision": 0x0, - "scratchpad": 0x4, - "interrupt_status": 0x2C, - "pim_status": 0x40, - "pim_present_intr_mask": 0x44, -} - -dom_base = [ - 0xFFFFFFFF, # Padding - 0x40000, - 0x48000, - 0x50000, - 0x58000, - 0x60000, - 0x68000, - 0x70000, - 0x78000, -] - - -dom = { - "revision": 0x0, - "system_led": 0xC, - "intr_status": 0x2C, - "qsfp_present": 0x48, - "qsfp_present_intr": 0x50, - "qsfp_present_intr_mask": 0x58, - "qsfp_intr": 0x60, - "qsfp_intr_mask": 0x68, - "qsfp_reset": 0x70, - "qsfp_lp_mode": 0x78, - "device_power_bad_status": 0x90, - "port_led_color_profile": { - 0: 0x300, - 1: 0x300, - 2: 0x304, - 3: 0x304, - 4: 0x308, - 5: 0x308, - 6: 0x30C, - 7: 0x30C, - }, - "port_led_control": { - 1: 0x310, - 2: 0x314, - 3: 0x318, - 4: 0x31C, - 5: 0x320, - 6: 0x324, - 7: 0x328, - 8: 0x32C, - 9: 0x330, - 10: 0x334, - 11: 0x338, - 12: 0x33C, - 13: 0x340, - 14: 0x344, - 15: 0x348, - 16: 0x34C, - }, - "dom_control_config": 0x410, - "dom_global_status": 0x414, - "dom_data": 0x4000, - - - "mdio": { - "config": 0x0200, - "command": 0x0204, - "write": 0x0208, - "read": 0x020C, - "status": 0x0210, - "intr_mask": 0x0214, - "source_sel": 0x0218, - }, # mdio -} - -mdio_read_cmd = 0x1 -mdio_write_cmd = 0x0 -mdio_device_type = 0x1F - - -#fbfpgaio=cdll.LoadLibrary('./fbfpgaio.so') - -def init_resources(): - fbfpgaio.hw_init() - return - -def release_resources(): - fbfpgaio.hw_release() - return - -def fpga_io(offset, data=None): - if data is None: - return fbfpgaio.hw_io(offset) - else: - fbfpgaio.hw_io(offset, data) - return - -def pim_io(pim, offset, data=None): - global dom_base - target_offset = dom_base[pim]+offset - if data is None: - retval = fpga_io(target_offset) - #print ("0x%04X" % retval) # idebug - return retval - else: - retval = fpga_io(target_offset, data) - return retval - - -def show_pim_present(): - pim_status = fpga_io(iob["pim_status"]) - - header = "PIM # " - status_str = " " - for shift in range(0,8): - status = pim_status & (0x10000 << shift) #[23:16] from pim_0 to pim_7 - header += " %d " % (shift+1) - if status: - status_str += (" | ") - else: - status_str += (" X ") - print(header) - print(status_str) - -def show_qsfp_present_status(pim_num): - status = fpga_io(dom_base[pim_num]+dom["qsfp_present"]) - interrupt = fpga_io(dom_base[pim_num]+dom["qsfp_present_intr"]) - mask = fpga_io(dom_base[pim_num]+dom["qsfp_present_intr_mask"]) - - print() - print(" (0x48) (0x50) (0x58)") - print((" 0x%08X 0x%08X 0x%08X" %(status, interrupt, mask))) - print(" Status Interrupt Mask") - for row in range(8): - output_str = str() - status_left = bool(status & (0x1 << row*2)) - status_right = bool(status & (0x2 << row*2)) - interrupt_left = bool(interrupt & (0x1 << row*2)) - interrupt_right = bool(interrupt & (0x2 << row*2)) - mask_left = bool(mask & (0x1 << row*2)) - mask_right = bool(mask & (0x2 << row*2)) - print(("%2d: %d %d %d %d %d %d" % \ - (row*2+1, status_left, status_right, \ - interrupt_left, interrupt_right, \ - mask_left, mask_right))) - print() - - - -#pim_index start from 0 to 7 -#port_index start from 0 to 127. Each 16-port is to one pim card. -class PimUtil(object): - - PORT_START = 0 - PORT_END = 127 - - def __init__(self): - self.value=1 - - def __del__(self): - self.value=0 - - def init_pim_fpga(self): - init_resources() - - def release_pim_fpga(self): - release_resources() - - def get_pim_by_port(self, port_num): - if port_num < self.PORT_START or port_num > self.PORT_END: - return False - pim_num=port_num/16 - return True, pim_num+1 - - def get_onepimport_by_port(self, port_num): - if port_num < self.PORT_START or port_num > self.PORT_END: - return False - if port_num < 16: - return True, port_num - else: - return True, port_num%16 - - def get_pim_presence(self, pim_num): - if pim_num <0 or pim_num > 7: - return 0 - pim_status = fpga_io(iob["pim_status"]) - status = pim_status & (0x10000 << pim_num) - if status: - return 1 #present - else: - return 0 #not present - - #return code=0:100G. return code=1:400G - def get_pim_board_id(self, pim_num): - if pim_num <0 or pim_num > 7: - return False - board_id = fpga_io(dom_base[pim_num+1]+dom["revision"]) - board_id = board_id & 0x1 - if board_id==0x0: - return 0 - else: - return 1 - - - def get_pim_status(self, pim_num): - if pim_num <0 or pim_num > 7: - return 0xFF - power_status =0 - #device_power_bad_status - status=fpga_io(dom_base[pim_num+1]+dom["device_power_bad_status"]) - - for x in range(0, 5): - if status & ( (0xf) << (4*x) ) : - power_status = power_status | (0x1 << x) - - if ( status & 0x1000000): - power_status=power_status | (0x1 << 5) - if ( status & 0x2000000): - power_status=power_status | (0x1 << 6) - if ( status & 0x8000000): - power_status=power_status | (0x1 << 7) - if ( status & 0x10000000): - power_status=power_status | (0x1 << 8) - if ( status & 0x40000000): - power_status=power_status | (0x1 << 9) - if ( status & 0x80000000): - power_status=power_status | (0x1 << 10) - - return power_status - #path=0:MDIO path is set on TH3. path=1:MDIO path is set on FPGA. - def set_pim_mdio_source_sel(self, pim_num, path): - if pim_num <0 or pim_num > 7: - return False - status= pim_io(pim_num+1, dom["mdio"]["source_sel"]) - - if path==1: - status = status | 0x2 - else: - status = status & 0xfffffffd - - pim_io(pim_num+1, dom["mdio"]["source_sel"], status) - return True - #retrun code=0, path is TH3. retrun code=1, path is FPGA - def get_pim_mdio_source_sel(sefl, pim_num): - if pim_num <0 or pim_num > 7: - return False - path= pim_io(pim_num+1, dom["mdio"]["source_sel"]) - path = path & 0x2 - if path: - return 1 - else: - return 0 - - #This api will set mdio path to MAC side.(At default, mdio path is set to FPGA side). - def pim_init(self, pim_num): - if pim_num <0 or pim_num > 7: - return False - status=self.set_pim_mdio_source_sel(pim_num, 0) - #put init phy cmd here - - - #return code="pim_dict[pim_num]='1' ":insert evt. return code="pim_dict[pim_num]='0' ":remove evt - def get_pim_change_event(self, timeout=0): - start_time = time.time() - pim_dict = {} - forever = False - - if timeout == 0: - forever = True - elif timeout > 0: - timeout = timeout / float(1000) # Convert to secs - else: - print("get_transceiver_change_event:Invalid timeout value", timeout) - return False, {} - - end_time = start_time + timeout - if start_time > end_time: - print('get_transceiver_change_event:' \ - 'time wrap / invalid timeout value', timeout) - - return False, {} # Time wrap or possibly incorrect timeout - - pim_mask_status = fpga_io(iob["pim_present_intr_mask"], 0xffff00000) - - while timeout >= 0: - new_pim_status=0 - pim_status = fpga_io(iob["pim_status"]) - present_status= pim_status & 0xff0000 - change_status=pim_status & 0xff - interrupt_status = fpga_io(iob["interrupt_status"]) - - for pim_num in range(0,8): - if change_status & (0x1 << pim_num) : - status = present_status & (0x10000 << pim_num) - new_pim_status = new_pim_status | (0x1 << pim_num) #prepare to W1C to clear - if status: - pim_dict[pim_num]='1' - else: - pim_dict[pim_num]='0' - - if change_status: - new_pim_status = pim_status | new_pim_status #Write one to clear interrupt bit - fpga_io(iob["pim_status"], new_pim_status) - return True, pim_dict - if forever: - time.sleep(1) - else: - timeout = end_time - time.time() - if timeout >= 1: - time.sleep(1) # We poll at 1 second granularity - else: - if timeout > 0: - time.sleep(timeout) - return True, {} - print("get_evt_change_event: Should not reach here.") - return False, {} - - - def get_pim_max_number(self): - return 8 - - #pim_num start from 0 to 7 - #color:0=amber, 1=blue - #contrl:off(0),on(1), flash(2) - def set_pim_led(self, pim_num, color, control): - if pim_num <0 or pim_num > 7: - return False - - led_val=fpga_io(dom_base[pim_num+1]+dom["system_led"]) - - if color==1: - led_val = led_val | (0x8000 | 0x4000) #blue - elif color==0: - led_val = (led_val & ( ~ 0x8000)) | 0x4000 #amber - else: - print("Set RGB control to Green1") - led_val = led_val & (~ 0x4000) - led_val = led_val & (~ 0xfff) - led_val = led_val | 0x0f0 #B.G.R Birghtness, set to Green - - if control==0: - led_val = led_val & ( ~ 0x3000) #Off - elif control==1: - led_val = led_val & ( ~ 0x3000) #Off - led_val = led_val | 0x1000 #On - else: - led_val = led_val | 0x3000 #Flash - - fpga_io(dom_base[pim_num+1]+dom["system_led"], led_val) - - def get_qsfp_presence(self, port_num): - #xlate port to get pim_num - status, pim_num=self.get_pim_by_port(port_num) - - if status==0: - return False - else: - present = fpga_io(dom_base[pim_num]+dom["qsfp_present"]) - status, shift = self.get_onepimport_by_port(port_num) - if status==0: - return False - else: - if bool(present & (0x1 << shift)): - return 1 #present - else: - return 0 #not present - - #return code: low_power(1) or high_power(0) - def get_low_power_mode(self, port_num): - status, pim_num=self.get_pim_by_port(port_num) - - if status==0: - return False - else: - lp_mode = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"]) - - status, shift=self.get_onepimport_by_port(port_num) - if status==0: - return False - else: - if (lp_mode & (0x1 << shift)): - return 1 #low - else: - return 0 #high - - #lpmode=1 to hold QSFP in low power mode. lpmode=0 to release QSFP from low power mode. - def set_low_power_mode(self, port_num, mode): - status, pim_num=self.get_pim_by_port(port_num) - if status==0: - return False - val = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"]) - status, shift=self.get_onepimport_by_port(port_num) - if status==0: - return False - else: - if mode==0: - new_val = val & (~(0x1 << shift)) - else: - new_val=val|(0x1 << shift) - status=fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"], new_val) - return status - - #port_dict[idx]=1 means get interrupt(change evt), port_dict[idx]=0 means no get interrupt - def get_qsfp_interrupt(self): - port_dict={} - #show_qsfp_present_status(1) - for pim_num in range(0, 8): - fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr_mask"], 0xffff0000) - fpga_io(dom_base[pim_num+1]+dom["qsfp_intr_mask"], 0xffff0000) - for pim_num in range(0, 8): - clear_bit=0 - qsfp_present_intr_status = fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr"]) - interrupt_status = qsfp_present_intr_status & 0xffff - #time.sleep(2) - if interrupt_status: - for idx in range (0,16): - port_idx=idx + (pim_num*16) - if interrupt_status & (0x1< Date: Tue, 4 Oct 2022 11:32:46 +0800 Subject: [PATCH 3/4] Add set_status_led to fan_drawer.py --- .../sonic_platform/fan_drawer.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py index 17d339ee55f6..260a052dbc9d 100644 --- a/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/fan_drawer.py @@ -81,6 +81,17 @@ def get_position_in_parent(self): """ 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. From 302b159a2ee5c4ce61fd8351e27b0b6309a5cb89 Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Fri, 21 Apr 2023 06:13:12 +0000 Subject: [PATCH 4/4] [Edgecore][Minipack] Fix wrong system eeprom data of 0x25 field Signed-off-by: brandonchuang --- .../accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py index 180be75454d5..1ea2c2ea1f76 100644 --- a/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_minipack-r0/sonic_platform/eeprom.py @@ -33,7 +33,7 @@ def __parse_output(self, decode_output): for line in lines: try: match = re.search( - '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + '(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')