diff --git a/.artifactignore b/.artifactignore deleted file mode 100644 index 5ccfaaba3..000000000 --- a/.artifactignore +++ /dev/null @@ -1,2 +0,0 @@ -**/* -!dist/*.whl diff --git a/ThirdPartyLicenses.txt b/ThirdPartyLicenses.txt deleted file mode 100644 index 35a93e1dc..000000000 --- a/ThirdPartyLicenses.txt +++ /dev/null @@ -1,29 +0,0 @@ -Third Party Notices - -This Microsoft Open Source project incorporates material from the project(s) listed below -(Third Party Code). Microsoft is not the original author of the Third Party Code. Microsoft -reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. - -1. sonic_platform_base/sonic_eeprom/eeprom_base.py https://cumulusnetworks.com -2. sonic_platform_base/sonic_eeprom/eeprom_dts.py https://cumulusnetworks.com -3. sonic_platform_base/sonic_eeprom/eeprom_tlvinfo.py https://cumulusnetworks.com -4. sonic_platform_base/sonic_sfp/bcmshell.py https://cumulusnetworks.com -5. sonic_platform_base/sonic_sfp/sff8472.py https://cumulusnetworks.com -6. sonic_platform_base/sonic_sfp/sfputilbase.py https://cumulusnetworks.com - - -+ * Copyright (C) 2014 Cumulus Networks, LLC -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA." diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index faffed121..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,99 +0,0 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml - -trigger: - branches: - include: - - '*' - -variables: - DIFF_COVER_CHECK_THRESHOLD: 80 - DIFF_COVER_ENABLE: 'true' - DIFF_COVER_WORKING_DIRECTORY: $(System.DefaultWorkingDirectory) - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - BRANCH_NAME: $(System.PullRequest.TargetBranch) - ${{ else }}: - BRANCH_NAME: $(Build.SourceBranchName) - - -pool: - vmImage: 'ubuntu-20.04' - -container: - image: sonicdev-microsoft.azurecr.io:443/sonic-slave-bullseye:latest - -steps: -- task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: build - pipeline: 142 - artifact: sonic-buildimage.vs - runVersion: 'latestFromBranch' - runBranch: 'refs/heads/$(BRANCH_NAME)' - displayName: "Download artifacts from latest sonic-buildimage build" - -- script: | - set -xe - sudo apt-get -y purge libhiredis-dev libnl-3-dev libnl-route-3-dev - sudo dpkg -i libyang_1.0.73_amd64.deb \ - libnl-3-200_*.deb \ - libnl-genl-3-200_*.deb \ - libnl-route-3-200_*.deb \ - libnl-nf-3-200_*.deb \ - libhiredis0.14_*.deb \ - libswsscommon_1.0.0_amd64.deb \ - python3-swsscommon_1.0.0_amd64.deb - workingDirectory: $(Pipeline.Workspace)/target/debs/bullseye/ - displayName: 'Install Debian dependencies' - -- script: | - set -xe - sudo pip3 install swsssdk-2.0.1-py3-none-any.whl - sudo pip3 install sonic_py_common-1.0-py3-none-any.whl - sudo pip3 install sonic_yang_mgmt-1.0-py3-none-any.whl - sudo pip3 install sonic_yang_models-1.0-py3-none-any.whl - sudo pip3 install sonic_config_engine-1.0-py3-none-any.whl - workingDirectory: $(Pipeline.Workspace)/target/python-wheels/bullseye/ - displayName: 'Install Python dependencies' - -- script: | - set -ex - # Install .NET CORE - curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - . /etc/os-release - sudo apt-add-repository https://packages.microsoft.com/debian/$VERSION_ID/prod - sudo apt-get update - sudo apt-get install -y dotnet-sdk-5.0 - displayName: "Install .NET CORE" - -# Python 3 -- script: | - python3 setup.py test - displayName: 'Test Python 3' - -- task: PublishTestResults@2 - inputs: - testResultsFiles: '$(System.DefaultWorkingDirectory)/test-results.xml' - testRunTitle: Python 3 - failTaskOnFailedTests: true - condition: succeededOrFailed() - displayName: 'Publish Python 3 test results' - -- task: PublishCodeCoverageResults@1 - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/coverage.xml' - reportDirectory: '$(System.DefaultWorkingDirectory)/htmlcov/' - displayName: 'Publish Python 3 test coverage' - -- script: | - set -e - python3 setup.py bdist_wheel - displayName: 'Build Python 3 wheel' - -- publish: '$(System.DefaultWorkingDirectory)/dist/' - artifact: wheels - displayName: "Publish Python wheels" diff --git a/sonic_fan/__init__.py b/otn_pmon/__init__.py similarity index 100% rename from sonic_fan/__init__.py rename to otn_pmon/__init__.py diff --git a/otn_pmon/alarm.py b/otn_pmon/alarm.py new file mode 100644 index 000000000..08f5b962c --- /dev/null +++ b/otn_pmon/alarm.py @@ -0,0 +1,173 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import time +import otn_pmon.db as db +from otn_pmon.common import * +from otn_pmon.thrift_api.ttypes import periph_type + +_alarms = { + "FAN_FAIL" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "FAN CARD FAIL"}, + "FAN_HIGH" : {"severity" : "NOT_ALARMED", "service_affect" : "false", "text" : "FAN HIGH SPEED"}, + "FAN_LOW" : {"severity" : "NOT_ALARMED", "service_affect" : "false", "text" : "FAN LOW SPEED"}, + "CRD_MISS" : {"severity" : "MAJOR", "service_affect" : "true", "text" : "CARD MISSING"}, + "PSU_MISMATCH" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "PSU CARD MISMATCH"}, + "CRD_MISMATCH" : {"severity" : "CRITICAL", "service_affect" : "true", "text" : "SLOT CARD MISMATCH"}, + "CRD_UNKNOWN" : {"severity" : "CRITICAL", "service_affect" : "true", "text" : "SLOT CARD UNKNOWN"}, + "DISK_FULL" : {"severity" : "MINOR", "service_affect" : "false", "text" : "DISK SPACE ALERT"}, + "CHASSIS_TEMP_HIALM" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "CHASSIS TEMPERATURE HIGH alarm"}, + "CHASSIS_TEMP_LOALM" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "CHASSIS TEMPERATURE LOW alarm"}, + "CHASSIS_TEMP_HIWAR" : {"severity" : "MAJOR", "service_affect" : "false", "text" : "CHASSIS TEMPERATURE HIGH warning"}, + "CHASSIS_TEMP_LOWAR" : {"severity" : "MAJOR", "service_affect" : "false", "text" : "CHASSIS TEMPERATURE LOW warning"}, + "MEM_USAGE_HIGH" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "MEMORY USAGE ALARM"}, + "CPU_USAGE_HIGH" : {"severity" : "MAJOR", "service_affect" : "false", "text" : "CPU USAGE ALARM"}, + "CRD_BOOT_FAIL" : {"severity" : "CRITICAL", "service_affect" : "true", "text" : "CARD BOOT FAIL"}, + "VOLTAGE_INPUT_HIGH" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "VOLTAGE INPUT HIGH"}, + "VOLTAGE_INPUT_LOW" : {"severity" : "CRITICAL", "service_affect" : "false", "text" : "VOLTAGE INPUT LOW"}, +} + +def alarm_exist_by_type(type) : + from otn_pmon.public import get_first_slot_id, get_last_slot_id + + # check host db + dbc = db.Client(db.HOST_DB, db.STATE_DB).db + if len(dbc.keys(f"{db.Table.CURRENT_ALARM}*{type}*")) != 0 : + return True + + # check asic dbs + start = get_first_slot_id(periph_type.LINECARD) + end = get_last_slot_id(periph_type.LINECARD) + for i in range (start, end + 1) : + dbc = db.Client(i, db.STATE_DB, True).db + if len(dbc.keys(f"{db.Table.CURRENT_ALARM}*{type}*")) != 0 : + return True + + return False + +def alarm_exist_by_severity(severity) : + from otn_pmon.public import get_first_slot_id, get_last_slot_id + + def exist_in(db_type, multi_db = False) : + dbc = db.Client(db_type, db.STATE_DB, multi_db) + keys = dbc.get_keys(db.Table.CURRENT_ALARM) + for k in keys : + ok, val = dbc.get_field(db.Table.CURRENT_ALARM, k, "severity") + if not ok or not val : + continue + if val == severity : + return True + return False + + # check host db + if exist_in(db.HOST_DB) : + return True + + # check asic dbs + start = get_first_slot_id(periph_type.LINECARD) + end = get_last_slot_id(periph_type.LINECARD) + for i in range (start, end + 1) : + if exist_in(i, True) : + return True + + return False + +def _moveCurAlarmToHisAlarm(dbs, id) : + # get current alarm info + ok, info = dbs[db.STATE_DB].get_entry(db.Table.CURRENT_ALARM, id) + if not ok or not info : + #alarm not exist + return + # delete current alarm + dbs[db.STATE_DB].delete_entry(db.Table.CURRENT_ALARM, id) + info_dict = dict(info) + time_created = info_dict.get('time-created','NA') + his_key = id + "_" + f"{time_created}" + cur_time = int(time.time() * 1000000000) + time_cleared = (('time-cleared', f"{cur_time}"),) + his_alm_info = info + time_cleared + # create histroy alarm + dbs[db.HISTORY_DB].set(db.Table.HISTORY_ALARM, his_key, his_alm_info) + dbs[db.HISTORY_DB].expire(db.Table.HISTORY_ALARM, his_key) + print(f"alarm {id} cleared") + +class Alarm(object): + def __init__(self, resource, type_id, serverity = None, sa = None, text = None) : + self.dbs = db.get_dbs(resource, [db.STATE_DB, db.HISTORY_DB]) + self.id = f"{resource}"+"#"+f"{type_id}" + self.resource = resource + self.type_id = type_id + self.serverity = serverity + self.service_affect = sa + self.text = text + self.__init_alarm(resource, type_id) + + def __init_alarm(self, resource, type_id) : + if type_id not in _alarms : + # print(f"pmom has no alarm {type_id} for {resource}") + return + self.serverity = _alarms[type_id]["severity"] + self.service_affect = _alarms[type_id]["service_affect"] + self.text = _alarms[type_id]["text"] + + @staticmethod + def clearBy(resource, pattern = None) : + dbs = db.get_dbs(resource, [db.STATE_DB, db.HISTORY_DB]) + if not dbs : + return + keys = dbs[db.STATE_DB].get_keys(db.Table.CURRENT_ALARM) + for k in keys : + if resource not in k : + continue + if pattern and pattern not in k : + continue + + _moveCurAlarmToHisAlarm(dbs, k) + + def create(self): + # time_created = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + time_created = int(time.time() * 1000000000) # ms + alarm_data = [ + ("time-created", f"{time_created}"), + ("id", f"{self.id}"), + ("resource", f"{self.resource}"), + ("text", f"{self.text}"), + ("type-id", f"{self.type_id}"), + ("severity", f"{self.serverity}"), + ("service-affect", f"{self.service_affect}"), + ] + + if not self.dbs[db.STATE_DB].exists(db.Table.CURRENT_ALARM, self.id) : + self.dbs[db.STATE_DB].set(db.Table.CURRENT_ALARM, self.id, alarm_data) + LOG.log_warning(f"alarm {self.id} created") + + def createAndClearOthers(self, pattern = None) : + keys = self.dbs[db.STATE_DB].get_keys(db.Table.CURRENT_ALARM) + for k in keys : + # alarm does not belong to the resource + if self.resource not in k : + continue + # the alarm already existed + if self.id == k : + continue + # clear as the k has the pattern + if pattern and pattern not in k : + continue + + _moveCurAlarmToHisAlarm(self.dbs, k) + + self.create() + + def clear(self) : + _moveCurAlarmToHisAlarm(self.dbs, self.id) \ No newline at end of file diff --git a/otn_pmon/chassis.py b/otn_pmon/chassis.py new file mode 100644 index 000000000..ab77caa85 --- /dev/null +++ b/otn_pmon/chassis.py @@ -0,0 +1,102 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import psutil +from otn_pmon.common import * +from otn_pmon.alarm import Alarm +import otn_pmon.periph as periph +import otn_pmon.db as db +from functools import lru_cache +from otn_pmon.thrift_api.ttypes import led_color, periph_type + +def get_chassis_power_capacity() : + pc = 0 + chassis_pn = periph.get_periph_expected_pn(periph_type.CHASSIS) + if chassis_pn and len(chassis_pn) >= 4 : + power_type = chassis_pn[3] + if power_type == "0" : + pc = 550 + elif power_type == "1" : + pc = 800 + elif power_type == "2" : + pc = 1300 + return pc + + +@lru_cache() +class Chassis(periph.Periph): + TEMP_HIGH_ALARM_THRESH = 55.0 + TEMP_HIGH_WARN_THRESH = 50.0 + TEMP_LOW_WARN_THRESH = 15.0 + TEMP_LOW_ALARM_THRESH = 10.0 + DISK_USAGE_THRESH = 90.0 + + def __init__(self, id): + super().__init__(periph_type.CHASSIS, id) + + def initialize_state(self): + inv = self.get_inventory() + if not inv : + return + + data = [ + ("part-no", inv.pn), + ("serial-no", inv.sn), + ("mfg-date", inv.mfg_date), + ("hardware-version", inv.hw_ver), + ("software-version", inv.sw_ver), + ("parent", "CHASSIS-1"), + ("empty", "false"), + ("removable", "false"), + ("mfg-name", "alibaba"), + ("oper-status", periph.slot_status_to_oper_status(slot_status.INIT)), + ] + + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def get_temperature(self): + from otn_pmon.public import get_inlet_temp + return get_inlet_temp() + + def update_pm(self) : + temp = self.get_temperature() + super().update_pm("Temperature", temp) + + def __get_disk_usage(self) : + return psutil.disk_usage("/").percent + + def update_alarm(self) : + alarm = Alarm(self.name, "DISK_FULL") + disk_usage = self.__get_disk_usage() + if disk_usage >= Chassis.DISK_USAGE_THRESH : + alarm.create() + else : + alarm.clear() + + alarm = None + temp = self.get_temperature() + if temp > Chassis.TEMP_HIGH_ALARM_THRESH : + alarm = Alarm(self.name, "CHASSIS_TEMP_HIALM") + elif Chassis.TEMP_HIGH_WARN_THRESH <= temp <= Chassis.TEMP_HIGH_ALARM_THRESH : + alarm = Alarm(self.name, "CHASSIS_TEMP_HIWAR") + elif Chassis.TEMP_LOW_ALARM_THRESH <= temp <= Chassis.TEMP_LOW_WARN_THRESH : + alarm = Alarm(self.name, "CHASSIS_TEMP_LOWAR") + elif temp < Chassis.TEMP_LOW_ALARM_THRESH : + alarm = Alarm(self.name, "CHASSIS_TEMP_LOALM") + + if alarm : + alarm.createAndClearOthers("CHASSIS_TEMP") + else : + Alarm.clearBy(self.name, "CHASSIS_TEMP") diff --git a/otn_pmon/common.py b/otn_pmon/common.py new file mode 100644 index 000000000..69b4b5a69 --- /dev/null +++ b/otn_pmon/common.py @@ -0,0 +1,80 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +from sonic_py_common.logger import Logger + +INVALID_TEMPERATURE = -99 +LOG = Logger("PMOND", Logger.LOG_FACILITY_DAEMON, Logger.LOG_OPTION_NDELAY | Logger.LOG_OPTION_PID) +LOG.set_min_log_priority_info() + +class fan_control_mode(object): + AUTO = 0 + MANUAL = 1 + + _VALUES_TO_NAMES = { + 0: "AUTO", + 1: "MANUAL", + } + + _NAMES_TO_VALUES = { + "AUTO": 0, + "MANUAL": 1, + } + +class slot_status(object): + EMPTY = 0 + INIT = 1 + READY = 2 + MISMATCH = 3 + COMFAIL = 4 + BOOTFAIL = 5 + UNKNOWN = 6 + + _VALUES_TO_NAMES = { + 0: "Empty", + 1: "Init", + 2: "Ready", + 3: "Mismatch", + 4: "Comfail", + 5: "Bootfail", + 6: "Unknown", + } + + _NAMES_TO_VALUES = { + "Empty": 0, + "Init": 1, + "Ready": 2, + "Mismatch": 3, + "Comfail": 4, + "Bootfail": 5, + "Unknown": 6, + } + +def slot_status_to_oper_status(status) : + oper_status = None + if status == slot_status.READY : + oper_status = "ACTIVE" + elif status == slot_status.INIT or status == slot_status.COMFAIL : + oper_status = "INACTIVE" + else : + oper_status = "DISABLED" + + return oper_status + +def get_slot_status_value(status_name) : + return slot_status._NAMES_TO_VALUES[status_name] + +def get_slot_status_name(status) : + return slot_status._VALUES_TO_NAMES[status] diff --git a/otn_pmon/cu.py b/otn_pmon/cu.py new file mode 100644 index 000000000..046885eef --- /dev/null +++ b/otn_pmon/cu.py @@ -0,0 +1,128 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import psutil +from functools import lru_cache +from otn_pmon.common import * +from otn_pmon.alarm import Alarm, alarm_exist_by_type, alarm_exist_by_severity +from otn_pmon.pm import Pm +import otn_pmon.periph as periph +import otn_pmon.db as db +from otn_pmon.thrift_api.ttypes import led_color, error_code, periph_type +from otn_pmon.thrift_client import thrift_try + +class CoreCollector() : + def __init__(self) : + self.count = psutil.cpu_count(logical = False) + + def execute(self) : + def gen_pm(tname, kname, pm_name, val) : + pm15 = Pm(tname, kname, pm_name, Pm.PM_TYPE_15) + pm24 = Pm(tname, kname, pm_name, Pm.PM_TYPE_24) + pm15.update(val) + pm24.update(val) + + times_percent = psutil.cpu_times_percent(percpu=True) + if not times_percent : + return + + for i in range(self.count) : + cpu = times_percent[i] + total = cpu.user + cpu.nice + cpu.system + cpu.iowait + cpu.irq +\ + cpu.softirq + cpu.steal + cpu.guest + cpu.guest_nice + # the type of percentage is uint8 + gen_pm("CPU", f"CPU-{i}", "Total", int(total)) + gen_pm("CPU", f"CPU-{i}", "User", int(cpu.user)) + gen_pm("CPU", f"CPU-{i}", "Kernel", int(cpu.system)) + gen_pm("CPU", f"CPU-{i}", "Nice", int(cpu.nice)) + gen_pm("CPU", f"CPU-{i}", "Idle", int(cpu.idle)) + gen_pm("CPU", f"CPU-{i}", "Wait", int(cpu.iowait)) + +@lru_cache() +class Cu(periph.Periph): + CPU_MEMORY_USAGE_THRESH = 80 + CPU_MEMORY_CLEAR_THRESH = 60 + + def __init__(self, id): + super().__init__(periph_type.CU, id) + self.led_flash_color = led_color.NONE + + def initialize_state(self): + inv = self.get_inventory() + if not inv : + return + + data = [ + ("part-no", inv.pn), + ("serial-no", inv.sn), + ("mfg-date", inv.mfg_date), + ("hardware-version", inv.hw_ver), + ("software-version", inv.sw_ver), + ("parent", "CHASSIS-1"), + ("empty", "false"), + ("removable", "false"), + ("mfg-name", "alibaba"), + ("oper-status", periph.slot_status_to_oper_status(slot_status.INIT)), + ] + + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def __get_memory(self) : + memory = {} + tmp = psutil.virtual_memory() + memory["utilized"] = tmp.used + memory["available"] = tmp.available + memory["percent"] = tmp.percent + return memory + + def set_led_color(self, color) : + def inner(client): + return client.set_led_color(self.type, self.id, color) + + ret = thrift_try(inner) + if ret == error_code.OK : + # update the current color to the FAN instance + self.led_flash_color = color + + return ret + + def led_contorl(self) : + if alarm_exist_by_severity("CRITICAL") : + self.set_led_color(led_color.RED) + elif alarm_exist_by_severity("MAJOR") or alarm_exist_by_severity("MINOR") : + self.set_led_color(led_color.YELLOW) + elif self.led_flash_color != led_color.GREEN : + self.set_led_color(led_color.GREEN) + + def update_pm(self) : + temp = self.get_temperature() + super().update_pm("Temperature", temp) + + memory = self.__get_memory() + super().update_pm("MemoryUtilized", memory["utilized"]) + super().update_pm("MemoryAvailable", memory["available"]) + + percent = int(psutil.cpu_percent()) + super().update_pm("CpuUtilization", percent) + + CoreCollector().execute() + + def update_alarm(self) : + memory_hi = Alarm(self.name, "MEM_USAGE_HIGH") + memory = self.__get_memory() + if memory["percent"] > Cu.CPU_MEMORY_USAGE_THRESH : + memory_hi.create() + elif memory["percent"] < Cu.CPU_MEMORY_CLEAR_THRESH : + memory_hi.clear() \ No newline at end of file diff --git a/otn_pmon/db.py b/otn_pmon/db.py new file mode 100644 index 000000000..8035969dc --- /dev/null +++ b/otn_pmon/db.py @@ -0,0 +1,132 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +from swsscommon import swsscommon +from sonic_py_common.device_info import get_path_to_platform_dir +import json + +EXPIRE_7_DAYS = 7 * 24 * 60 * 60 #unit s +EXPIRE_1_DAYS = 1 * 24 * 60 * 60 #unit s +HOST_DB = 0 +CONFIG_DB = swsscommon.CONFIG_DB +STATE_DB = swsscommon.STATE_DB +COUNTERS_DB = swsscommon.COUNTERS_DB +HISTORY_DB = swsscommon.HISTORY_DB + + +def db_get_dev_spec(): + platform_path = get_path_to_platform_dir() + # platform_path = "/usr/share/sonic/platform" + spec_path = f"{platform_path}/dev_spec.json" + with open(spec_path, 'r', encoding='utf8') as fp: + return json.load(fp) + + +def db_get_periph_number(type_name): + spec = db_get_dev_spec() + if type_name: + return spec["number"][type_name] + return 0 + + +def get_dbs(periph_name, db_types): + if not isinstance(db_types, list) or len(db_types) == 0 : + return None + slot_id = HOST_DB + multi_db = False + elmts = periph_name.split("-") + if len(elmts) > 2 and int(elmts[2]) <= db_get_periph_number("LINECARD"): + slot_id = int(elmts[2]) + multi_db = True + dbs = {} + for t in db_types : + dbs[t] = Client(slot_id, t, multi_db) + return dbs + + +class Table(): + CHASSIS = "CHASSIS" + FAN = "FAN" + LINECARD = "LINECARD" + PSU = "PSU" + CU = "CU" + CURRENT_ALARM = "CURALARM" + HISTORY_ALARM = "HISALARM" + + +class Client(): + def __init__(self, slot_id, db_index, multi_db = False) : + if multi_db == True : + redis_sock = f"/var/run/redis{slot_id-1}/redis.sock" + else: + redis_sock = f"/var/run/redis/redis.sock" + self.db = swsscommon.DBConnector(db_index, redis_sock, 0) + + def exists(self, tname, kname) : + t = swsscommon.Table(self.db, tname) + if not t : + return False + ok, _ = t.get(kname) + return ok + + def get_entry(self, tname, kname) : + t = swsscommon.Table(self.db, tname) + if not t : + return + return t.get(kname) + + def get_keys(self, tname) : + t = swsscommon.Table(self.db, tname) + if not t : + print(f"{tname} is not exist") + return + return t.getKeys() + + def get_field(self, tname, kname, fname) : + t = swsscommon.Table(self.db, tname) + if not t : + return + return t.hget(kname, fname) + + def set(self, tname, kname, data) : + t = swsscommon.Table(self.db, tname) + if not t : + return + return t.set(kname, swsscommon.FieldValuePairs(data)) + + def set_field(self, tname, kname, fname, fval) : + data = [(fname, fval)] + t = swsscommon.Table(self.db, tname) + if not t : + return + return t.set(kname, swsscommon.FieldValuePairs(data)) + + def expire(self, tname, kname, seconds = EXPIRE_7_DAYS) : + t = swsscommon.Table(self.db, tname) + if not t : + return + return t.expire(kname, seconds) + + def delete_entry(self, tname, kname) : + t = swsscommon.Table(self.db, tname) + if not t : + return + return t.delete(kname) + + def pub_sub(self) : + pubsub = swsscommon.PubSub(self.db) + if not pubsub : + return + return pubsub diff --git a/otn_pmon/fan.py b/otn_pmon/fan.py new file mode 100644 index 000000000..e1c197226 --- /dev/null +++ b/otn_pmon/fan.py @@ -0,0 +1,263 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import threading +from otn_pmon.common import * +from otn_pmon.alarm import Alarm, alarm_exist_by_type +import otn_pmon.periph as periph +import otn_pmon.db as db +from functools import lru_cache +from otn_pmon.thrift_api.ttypes import error_code, periph_type, led_color +from otn_pmon.thrift_client import thrift_try + +@lru_cache() +class Fan(periph.Periph) : + def __init__(self, id) : + super().__init__(periph_type.FAN, id) + self.boot_timeout_secs = 10 + self.control_mode = fan_control_mode.AUTO + self.led_cur_color = led_color.NONE + + def initialize_state(self) : + inv = self.get_inventory() + if not inv : + return + + s_status = self.get_slot_status() + if not s_status or s_status == slot_status.EMPTY : + s_status = slot_status.INIT + + data = [ + ('part-no', inv.pn), + ('serial-no', inv.sn), + ('mfg-date', inv.mfg_date), + ('hardware-version', inv.hw_ver), + ("parent", "CHASSIS-1"), + ("empty", "false"), + ('removable', "true"), + ("mfg-name", "alibaba"), + ("oper-status", periph.slot_status_to_oper_status(s_status)), + ("slot-status", get_slot_status_name(s_status)), + ] + + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def get_speed_rate(self) : + ok, rate = self.dbs[db.STATE_DB].get_field(self.table_name, self.name, "speed-rate") + if not ok or not rate : + return None + + return float(rate) + + def set_speed_rate(self, rate) : + if not isinstance(rate, int) : + return + + # set speed-rate to driver + def inner(client): + return client.set_fan_speed_rate(self.id, rate) + + ret = thrift_try(inner) + if ret != error_code.OK : + LOG.log_error(f"set {self.name} speed-rate {rate} to driver failed") + return + LOG.log_info(f"set {self.name} speed-rate {rate} success") + # update the value of speed-rate in STATE_DB + self.dbs[db.STATE_DB].set_field(self.table_name, self.name, "speed-rate", str(rate)) + + def set_led_color(self, color) : + def inner(client): + return client.set_led_color(self.type, self.id, color) + + ret = thrift_try(inner) + if ret == error_code.OK : + # update the current color to the FAN instance + self.led_cur_color = color + + return ret + + def __get_speed(self) : + def inner(client) : + return client.get_fan_speed(self.id) + + result = thrift_try(inner) + if result.ret != error_code.OK : + return None + return result.speed + + def __get_speed_spec(self) : + def inner(client) : + return client.get_fan_speed_spec(self.id) + return thrift_try(inner) + + def update_pm(self) : + temp = self.get_temperature() + super().update_pm("Temperature", temp) + + speed = self.__get_speed() + if not speed : + return + super().update_pm("Speed", speed.front) + super().update_pm("Speed_2", speed.behind) + + def update_alarm(self) : + alarm = None + s_status = None + + speed = self.__get_speed() + if not speed : + return + max_speed = speed.front if speed.front >= speed.behind else speed.behind + min_speed = speed.front if speed.front <= speed.behind else speed.behind + + speed_spec = self.__get_speed_spec() + if max_speed > speed_spec.max : + alarm = Alarm(self.name, "FAN_HIGH") + elif max_speed == 0 or min_speed == 0 : + alarm = Alarm(self.name, "FAN_FAIL") + s_status = slot_status.UNKNOWN + elif min_speed < speed_spec.min : + alarm = Alarm(self.name, "FAN_LOW") + + if alarm : + alarm.createAndClearOthers() + if s_status : + self.update_slot_status(s_status) + else : + cur_status = self.get_slot_status() + if cur_status == slot_status.READY : + Alarm.clearBy(self.name, "FAN_") + +class FanControl(threading.Thread) : + SPEED_RATE_L1 = 30 + SPEED_RATE_L2 = 35 + SPEED_RATE_L3 = 40 + SPEED_RATE_L4 = 45 + SPEED_RATE_L5 = 75 + SPEED_RATE_L6 = 100 + # level, rate, upshift_temp_thresh, downshift_temp_thresh + CTRL_RULES = [ + ["S1", SPEED_RATE_L1, 35, 0], + ["S2", SPEED_RATE_L2, 38, 33], + ["S3", SPEED_RATE_L3, 41, 36], + ["S4", SPEED_RATE_L4, 44, 39], + ["S5", SPEED_RATE_L5, 48, 42], + ["S6", SPEED_RATE_L6, 0, 46], + ] + def __init__(self, interval = 1) : + threading.Thread.__init__(self) + self.interval = interval + self.stop = threading.Event() + + def __get_fan_list(self) : + from otn_pmon.public import get_first_slot_id, get_last_slot_id + start = get_first_slot_id(periph_type.FAN) + end = get_last_slot_id(periph_type.FAN) + list = [] + for i in range (start, end + 1) : + f = Fan(i) + if f.presence() : + list.append(f) + return list + + def speed_control_manual(self, rate) : + for f in self.list : + f.set_speed_rate(rate) + + def _get_ctrl_rule_index(self, rate) : + if not rate : + return 5 # full speed + + if rate <= FanControl.SPEED_RATE_L1 : + return 0 + elif FanControl.SPEED_RATE_L1 < rate <= FanControl.SPEED_RATE_L2 : + return 1 + elif FanControl.SPEED_RATE_L2 < rate <= FanControl.SPEED_RATE_L3 : + return 2 + elif FanControl.SPEED_RATE_L3 < rate <= FanControl.SPEED_RATE_L4 : + return 3 + elif FanControl.SPEED_RATE_L4 < rate <= FanControl.SPEED_RATE_L5 : + return 4 + elif FanControl.SPEED_RATE_L5 < rate <= FanControl.SPEED_RATE_L6 : + return 5 + + def _expect_speed_rate(self, fan) : + from otn_pmon.public import get_inlet_temp + + cur_temp = get_inlet_temp() + index = self._get_ctrl_rule_index(fan.get_speed_rate()) + ctrl_info = FanControl.CTRL_RULES[index] + upshift_temp_thresh = ctrl_info[2] + downshift_temp_thresh = ctrl_info[3] + # the default value of speed rate + rate = FanControl.CTRL_RULES[index][1] + # need upshift + if upshift_temp_thresh != 0 and cur_temp > upshift_temp_thresh : + rate = FanControl.CTRL_RULES[index + 1][1] + # need downshift + if downshift_temp_thresh != 0 and cur_temp < downshift_temp_thresh : + rate = FanControl.CTRL_RULES[index - 1][1] + + return rate + + def _need_full_speed(self) : + from otn_pmon.public import get_inlet_temp + + # get inlet temperature failed + temp = get_inlet_temp() + if temp == INVALID_TEMPERATURE : + return True + + # any fan is absent + fan_num = periph.get_periph_number(periph_type.FAN) + fan_presence_num = len(self.list) + if fan_num != fan_presence_num : + return True + + # alarms exists + if alarm_exist_by_type("HIGH_TEMPERATURE_ALARM") or alarm_exist_by_type("SLOT_COMM_FAIL") : + return True + + return False + + def speed_control_auto(self) : + if self._need_full_speed() : + self.speed_control_manual(FanControl.SPEED_RATE_L6) + return + + for f in self.list : + if f.control_mode != fan_control_mode.AUTO : + continue + expect_rate = self._expect_speed_rate(f) + if not expect_rate : + continue + f.set_speed_rate(expect_rate) + + def led_control(self) : + for f in self.list : + # fan alarms exist + if alarm_exist_by_type(f"{f.name}#FAN_FAIL") : + f.set_led_color(led_color.RED) + elif alarm_exist_by_type(f.name) : + f.set_led_color(led_color.YELLOW) + elif f.led_cur_color != led_color.GREEN : + f.set_led_color(led_color.GREEN) + + def run(self) : + while not self.stop.wait(self.interval) : + # get the latest fan list + self.list = self.__get_fan_list() + self.speed_control_auto() + self.led_control() diff --git a/otn_pmon/linecard.py b/otn_pmon/linecard.py new file mode 100644 index 000000000..be71c3142 --- /dev/null +++ b/otn_pmon/linecard.py @@ -0,0 +1,114 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +from functools import lru_cache +from otn_pmon.common import * +import otn_pmon.periph as periph +import otn_pmon.db as db +from otn_pmon.thrift_api.ttypes import led_color, power_ctl_type, periph_type +from otn_pmon.thrift_client import thrift_try + +@lru_cache() +class Linecard(periph.Periph): + def __init__(self, id): + super().__init__(periph_type.LINECARD, id) + self.boot_timeout_secs = 8 * 60 + + def initialize_state(self): + s_status = self.get_slot_status() + if not s_status or s_status != slot_status.READY : + s_status = slot_status.INIT + + data = [ + ("parent", "CHASSIS-1"), + ("empty", "false"), + ("removable", "true"), + ("power-admin-state", "POWER_ENABLED"), + ("mfg-name", "alibaba"), + ("oper-status", periph.slot_status_to_oper_status(s_status)), + ("slot-status", get_slot_status_name(s_status)), + ] + + # initialize inventory info if linecard`s eeprom can be read by thrift + inv = self.get_inventory() + if inv : + extend = [ + ("linecard-type", inv.type), + ("part-no", inv.pn), + ("serial-no", inv.sn), + ("mfg-date", inv.mfg_date), + ("hardware-version", inv.hw_ver), + ] + data.extend(extend) + # the host controls the power on|off if the real card type can be read from eeprom + self.set_power_control(power_ctl_type.ON) + + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def __get_subcomponents(self, card_type): + if card_type == "E100C" : + return f"AMPLIFIER-1-{self.id}-1,AMPLIFIER-1-{self.id}-2,ATTENUATOR-1-{self.id}-1,ATTENUATOR-1-{self.id}-3,OSC-1-{self.id}-1,MUX-1-{self.id}-1,OSC-1-{self.id}-1,PORT-1-{self.id}-L1IN,PORT-1-{self.id}-L1OUT" + elif card_type == "E110C" : + return f"AMPLIFIER-1-{self.id}-1,AMPLIFIER-1-{self.id}-2,ATTENUATOR-1-{self.id}-1,ATTENUATOR-1-{self.id}-2,ATTENUATOR-1-{self.id}-3,APS-1-{self.id}-1,OSC-1-{self.id}-1,MUX-1-{self.id}-1,PORT-1-{self.id}-L1IN,PORT-1-{self.id}-L1OUT,PORT-1-{self.id}-L2IN,PORT-1-{self.id}-L2OUT" + elif card_type == "E120C" : + return f"ATTENUATOR-1-{self.id}-1,ATTENUATOR-1-{self.id}-2,APS-1-{self.id}-1,PORT-1-{self.id}-C1IN,PORT-1-{self.id}-C1OUT,PORT-1-{self.id}-L1IN,PORT-1-{self.id}-L1OUT,PORT-1-{self.id}-L2IN,PORT-1-{self.id}-L2OUT" + elif card_type == "P230C" : + return f"PORT-1-{self.id}-C1,PORT-1-{self.id}-C2,PORT-1-{self.id}-C3,PORT-1-{self.id}-C4,PORT-1-{self.id}-L1,PORT-1-{self.id}-L2" + else : + return "" + + def set_power_control(self, type) : + def inner(client): + return client.set_power_control(self.id, type) + LOG.log_info(f"set {self.name} power control {type}") + return thrift_try(inner) + + def get_temperature(self): + counters_db = self.dbs[db.COUNTERS_DB] + key = f"{self.name}_Temperature:15_pm_current" + ok, instant = counters_db.get_field(self.table_name, key, "instant") + if not ok or not instant : + return INVALID_TEMPERATURE + return float(instant) + + def mismatch(self) : + config_db = self.dbs[db.CONFIG_DB] + ok, type_c = config_db.get_field(self.table_name, self.name, "linecard-type") + if not ok or type_c == "NONE" : + return False + + inv = self.get_inventory() + if inv : + # the real card type should be read from driver + if inv.type.upper() != type_c.upper() : + return True + else : + # the real card type should be read from db + state_db = self.dbs[db.STATE_DB] + ok, type_s = state_db.get_field(self.table_name, self.name, "linecard-type") + if not ok or not type_s : + return False + + if type_c.upper() != type_s.upper() : + return True + + return False + + def update_pm(self) : + temp = self.get_temperature() + super().update_pm("Temperature", temp) + + def update_alarm(self) : + super().update_alarm() \ No newline at end of file diff --git a/otn_pmon/periph.py b/otn_pmon/periph.py new file mode 100644 index 000000000..97d559288 --- /dev/null +++ b/otn_pmon/periph.py @@ -0,0 +1,252 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import json +from threading import Timer +from otn_pmon.thrift_api.ttypes import periph_type, error_code +from otn_pmon.thrift_client import thrift_try +from otn_pmon.common import * +import otn_pmon.db as db +from otn_pmon.alarm import Alarm +from otn_pmon.pm import Pm +from sonic_py_common.device_info import get_path_to_platform_dir + +def get_dev_spec() : + platform_path = get_path_to_platform_dir() + # platform_path = "/usr/share/sonic/platform" + spec_path = f"{platform_path}/dev_spec.json" + with open(spec_path, 'r', encoding='utf8') as fp: + return json.load(fp) + +def get_periph_number(type) : + spec = get_dev_spec() + type_name = periph_type._VALUES_TO_NAMES[type] + if type_name : + return spec["number"][type_name] + return 0 + +def get_periph_expected_pn(type) : + spec = get_dev_spec() + type_name = periph_type._VALUES_TO_NAMES[type] + if type_name : + return spec["expected-pn"][type_name] + return None + +class Periph(object): + def __init__(self, type, id): + self.type = type + self.id = id + self.name = self.__get_name() + self.table_name = periph_type._VALUES_TO_NAMES[type] + self.dbs = db.get_dbs(self.name, [db.CONFIG_DB, db.STATE_DB, db.COUNTERS_DB]) + self.state_initialized = False + self.inventory = None + self.slot_init_flag = slot_status.EMPTY + + def __get_name(self) : + type_string = periph_type._VALUES_TO_NAMES[self.type] + if self.type == periph_type.FAN or self.type == periph_type.PSU or self.type == periph_type.LINECARD : + name = f"{type_string}-1-{self.id}" + else : + name = f"{type_string}-{self.id}" + return name + + def synchronize(self) : + try: + card_miss = Alarm(self.name, "CRD_MISS") + if self.presence() : + card_miss.clear() + self.synchronize_presence() + else : + card_miss.createAndClearOthers() + self.synchronize_not_presence() + except Exception as e : + LOG.log_warning(f"Failed to synchronize {self.name} as error : {e}") + # raise e + + def synchronize_presence(self) : + card_mismatch = Alarm(self.name, "CRD_MISMATCH") + + if not self.state_initialized : + # when plug in update the mismatch stauts,avoiding to get get_inventory frequently + if self.mismatch(): + card_mismatch.createAndClearOthers() + self.state_initialized = False + self.synchronize_mismatch() + self.update_slot_status(slot_status.MISMATCH) + return + else : + card_mismatch.clear() + + # print(f"synchronize_presence in {self.name}") + self.initialize_state() + self.state_initialized = True + # start a timer to check whether booting successed or failed + if hasattr(self, 'boot_timeout_secs') : + self.start_boot_timer(self.boot_timeout_secs) + else : + # print("{} update_state doing".format(self.name)) + self.update_state() + self.update_alarm() + self.update_pm() + + def synchronize_not_presence(self): + from otn_pmon.public import clearPmByName + clearPmByName(self.name) + + self.state_initialized = False + self.dbs[db.STATE_DB].delete_entry(self.table_name, self.name) + + data = [ + ("empty", "true"), + ("slot-status", get_slot_status_name(slot_status.EMPTY)), + ] + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def synchronize_mismatch(self): + from otn_pmon.public import clearPmByName + clearPmByName(self.name) + + self.state_initialized = False + self.dbs[db.STATE_DB].delete_entry(self.table_name, self.name) + + data = [ + ("empty", "false"), + ("slot-status", get_slot_status_name(slot_status.MISMATCH)), + ] + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def update_state(self): + # check unknown and mismatch + if self.unknown(): + self.update_slot_status(slot_status.UNKNOWN) + return + + if self.slot_init_flag == slot_status.MISMATCH: + self.update_slot_status(slot_status.MISMATCH) + return + + if self.slot_init_flag == slot_status.INIT: + return + + # only the slot-status of the linecard is updated by southbound api + if self.type == periph_type.LINECARD: + # do nothing if the linecard is still initializing. + if self.get_slot_status() == slot_status.INIT or self.get_slot_status() == slot_status.MISMATCH: + return + else: + self.update_slot_status(slot_status.READY) + + def update_pm(self, pm_name, value): + pm15 = Pm(self.table_name, self.name, pm_name, Pm.PM_TYPE_15) + pm24 = Pm(self.table_name, self.name, pm_name, Pm.PM_TYPE_24) + pm15.update(value) + pm24.update(value) + + def mismatch(self) : + return False + + def unknown(self) : + return False + + def update_alarm(self): + if self.removable() : + s_status = self.get_slot_status() + if s_status == slot_status.READY : + Alarm.clearBy(self.name, "CRD_BOOT_FAIL") + + def start_boot_timer(self, timeout) : + def handler(self) : + s_status = self.get_slot_status() + # slot_status changed as boot finished with timeout + if slot_status.INIT == s_status : + self.update_slot_status(slot_status.BOOTFAIL) + boot_fail = Alarm(self.name, 'CRD_BOOT_FAIL') + boot_fail.createAndClearOthers() + + elif s_status is not None: + LOG.log_info(f"{self.name} boot finished with {get_slot_status_name(s_status)}") + + boot_timer = Timer(timeout, handler, (self, )) + boot_timer.start() + LOG.log_info(f"{self.name} boot timer with timeout({timeout}s) started") + + def update_slot_status(self, status) : + if not self.removable() : + return + state_db = self.dbs[db.STATE_DB] + # compare with the slot-status in db + _, db_s_status = state_db.get_field(self.table_name, self.name, "slot-status") + if db_s_status and status != get_slot_status_value(db_s_status) : + state_db.set_field(self.table_name, self.name, "slot-status", get_slot_status_name(status)) + + # oper-status need to update with the updation of slot-status + _, db_o_status = state_db.get_field(self.table_name, self.name, "oper-status") + if db_o_status and db_o_status != slot_status_to_oper_status(status) : + state_db.set_field(self.table_name, self.name, "oper-status", slot_status_to_oper_status(status)) + + def removable(self) : + if self.type in (periph_type.LINECARD, periph_type.FAN, periph_type.PSU) : + return True + return False + + def initialize(self): + def inner(client): + return client.initialize(self.type, self.id) + return thrift_try(inner) + + def presence(self): + def inner(client): + return client.periph_presence(self.type, self.id) + return thrift_try(inner) + + def get_version(self): + def inner(client): + return client.get_periph_version(self.type, self.id) + return thrift_try(inner) + + def get_temperature(self): + def inner(client): + return client.get_periph_temperature(self.type, self.id) + + temp = thrift_try(inner) + if temp.ret != error_code.OK : + return INVALID_TEMPERATURE + + return temp.temperature / 100 + + def get_slot_status(self): + state_db = self.dbs[db.STATE_DB] + ok, status = state_db.get_field(self.table_name, self.name, "slot-status") + # print(f"get_slot_status ,table_name={self.table_name},name={self.name}") + if ok and status in slot_status._NAMES_TO_VALUES : + return get_slot_status_value(status) + + return None + + def get_inventory(self): + def inner(client): + return client.get_inventory(self.type, self.id) + + result = thrift_try(inner) + if result.ret != error_code.OK : + return None + + return result.inv + + def set_led_color(self, type, id, color): + def inner(client): + return client.set_led_color(type, id, color) + return thrift_try(inner) \ No newline at end of file diff --git a/otn_pmon/pm.py b/otn_pmon/pm.py new file mode 100644 index 000000000..284edf375 --- /dev/null +++ b/otn_pmon/pm.py @@ -0,0 +1,138 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import time +from functools import lru_cache +import otn_pmon.db as db + +@lru_cache() +class Pm : + """PM class""" + PM_TYPE_15 = "15" + PM_TYPE_24 = "24" + def __init__(self, table, base_key, name, type) : + self.table = table + self.base_key = base_key + self.name = name # PM name + self.type = type # PM type 15|24 + self.dbs = db.get_dbs(base_key, [db.COUNTERS_DB, db.HISTORY_DB]) + + self.starttime = 0 + self.interval = self.__get_interval() + self.instant = 0 # current value + self.avg = 0 + self.min = 0 + self.max = 0 + self.min_time = 0 + self.max_time = 0 + self.sum = 0 # sampling sum + self.count = 0 # sampling total count + + def __get_interval(self) : + ns_unit = 1000000000 + interval = 0 + if self.type == Pm.PM_TYPE_15 : + interval = 15 * 60 * ns_unit + else : + interval = 24 * 60 * 60 * ns_unit + return interval + + def __get_latest_sampling_timestamp(self, time) : + delta = self.__get_interval() + # timezone ??? + return int(time / delta) * delta + + def __need_reset(self, time) : + new_timestamp = self.__get_latest_sampling_timestamp(time) + if self.starttime != 0 and self.starttime != new_timestamp : + return True + return False + + def __reset(self) : + # generate history pm then do reset + self.__save(db.HISTORY_DB) + + self.starttime = 0 + self.instant = 0 # current value + self.avg = 0.0 + self.min = 0.0 + self.max = 0.0 + self.min_time = 0 + self.max_time = 0 + self.sum = 0 + self.count = 0 # accumulate times + + def __get_key(self, type = db.COUNTERS_DB) : + if type == db.HISTORY_DB : + suffix = "15_pm_history" + if self.type != Pm.PM_TYPE_15 : + suffix = "24_pm_history" + + return f"{self.base_key}_{self.name}:{suffix}_{self.starttime}" + + suffix = "15_pm_current" + if self.type != Pm.PM_TYPE_15 : + suffix = "24_pm_current" + return f"{self.base_key}_{self.name}:{suffix}" + + def __save(self, type = db.COUNTERS_DB) : + if self.starttime == 0 : + return + + validity = "incomplete" + if type == db.HISTORY_DB : + validity = "complete" + + data = [ + ("starttime", f"{self.starttime}"), + ("instant", f"{self.instant}"), + ("avg", f"{self.avg}"), + ("min", f"{self.min}"), + ("max", f"{self.max}"), + ("interval", f"{self.interval}"), + ("min-time", f"{self.min_time}"), + ("max-time", f"{self.max_time}"), + ("validity", validity), + ] + + key = self.__get_key(type) + if type not in self.dbs : + print(f"save pm {key} to db failed as the type {type} is invalid") + return + # print(f"set {self.table} {key}") + self.dbs[type].set(self.table, key, data) + + def update(self, value) : + cur_time = int(time.time() * 1000000000) # ns + + if self.__need_reset(cur_time) : + # print(f"{self.name} {self.type} PM reset") + self.__reset() + + self.starttime = self.__get_latest_sampling_timestamp(cur_time) + self.instant = value + if value < self.min or self.min_time == 0 : + self.min = value + self.min_time = cur_time + if value > self.max or self.max_time == 0 : + self.max = value + self.max_time = cur_time + + self.sum += value + self.count += 1 + self.avg = round(self.sum / self.count, 1) + + # save current pm to counters db + self.__save() \ No newline at end of file diff --git a/otn_pmon/psu.py b/otn_pmon/psu.py new file mode 100644 index 000000000..7e7a8c043 --- /dev/null +++ b/otn_pmon/psu.py @@ -0,0 +1,149 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +from functools import lru_cache +from otn_pmon.common import * +from otn_pmon.alarm import Alarm +import otn_pmon.periph as periph +import otn_pmon.chassis as chassis +import otn_pmon.db as db +from otn_pmon.thrift_api.ttypes import error_code, led_color, periph_type +from otn_pmon.thrift_client import thrift_try + +@lru_cache() +class Psu(periph.Periph): + def __init__(self, id): + super().__init__(periph_type.PSU, id) + self.boot_timeout_secs = 10 + + def __get_psu_info(self): + def inner(client): + return client.get_psu_info(self.id) + + result = thrift_try(inner) + if result.ret != error_code.OK : + return None + + return result.info + + def __psu_vin_high(self) : + def inner(client): + return client.psu_vin_high(self.id) + return thrift_try(inner) + + def __psu_vin_low(self) : + def inner(client): + return client.psu_vin_low(self.id) + return thrift_try(inner) + + def __expected_psu(self, pn) : + expected_pn = periph.get_periph_expected_pn(self.type) + if pn in expected_pn : + return True + return False + + def initialize_state(self): + inv = self.get_inventory() + if not inv : + return + + psu_info = self.__get_psu_info() + if not psu_info : + return + + s_status = self.get_slot_status() + if not s_status or s_status == slot_status.EMPTY : + s_status = slot_status.INIT + + data = [ + ('part-no', inv.pn), + ('serial-no', inv.sn), + ('mfg-date', inv.mfg_date), + ('hardware-version', inv.hw_ver), + ("parent", "CHASSIS-1"), + ("empty", "false"), + ('removable', "true"), + ("mfg-name", "alibaba"), + ("oper-status", periph.slot_status_to_oper_status(s_status)), + ("slot-status", get_slot_status_name(s_status)), + ("capacity", str(psu_info.capacity)), + ] + + self.dbs[db.STATE_DB].set(self.table_name, self.name, data) + + def update_pm(self): + temp = self.get_temperature() + super().update_pm("Temperature", temp) + + psu_info = self.__get_psu_info() + if not psu_info : + return + + super().update_pm("InputCurrent", psu_info.iin) + super().update_pm("InputVoltage", psu_info.vin) + super().update_pm("InputPower", psu_info.pin) + super().update_pm("OutputCurrent", psu_info.iout) + super().update_pm("OutputPower", psu_info.pout) + super().update_pm("OutputVoltage", psu_info.vout) + + super().update_pm("AmbientTemperature", psu_info.ambient_temp) + super().update_pm("PrimaryTemperature", psu_info.primary_temp) + super().update_pm("SecondaryTemperature", psu_info.secondary_temp) + super().update_pm("FanSpeed", psu_info.fan) + + def mismatch(self) : + psu_info = self.__get_psu_info() + if not psu_info : + return False + + cpc = chassis.get_chassis_power_capacity() + if cpc != psu_info.capacity : + return True + + return False + + def unknown(self) : + inv = self.get_inventory() + # check unknown as the pn is expected or not + if inv and inv.pn and not self.__expected_psu(inv.pn) : + return True + + return False + + def __proc_vin_alarm(self) : + vin_h = Alarm(self.name, "VOLTAGE_INPUT_HIGH") + if self.__psu_vin_high() : + vin_h.create() + else : + vin_h.clear() + + vin_l = Alarm(self.name, "VOLTAGE_INPUT_LOW") + if self.__psu_vin_low() : + vin_l.create() + else : + vin_l.clear() + + def update_alarm(self): + cur_status = self.get_slot_status() + if cur_status == slot_status.UNKNOWN : + alarm = Alarm(self.name, "CRD_UNKNOWN") + alarm.createAndClearOthers() + elif cur_status == slot_status.MISMATCH : + alarm = Alarm(self.name, "PSU_MISMATCH") + alarm.createAndClearOthers() + elif cur_status == slot_status.READY : + Alarm.clearBy(self.name, "CRD_UNKNOWN") + Alarm.clearBy(self.name, "PSU_MISMATCH") + self.__proc_vin_alarm() \ No newline at end of file diff --git a/otn_pmon/public.py b/otn_pmon/public.py new file mode 100644 index 000000000..25f1c8316 --- /dev/null +++ b/otn_pmon/public.py @@ -0,0 +1,156 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import time +from otn_pmon.thrift_api.ttypes import error_code, led_state, power_ctl_type, periph_type +from otn_pmon.thrift_client import thrift_try +from otn_pmon.common import * +import otn_pmon.periph as periph +import otn_pmon.linecard as linecard +import otn_pmon.fan as fan +import otn_pmon.cu as cu +import otn_pmon.db as db + +def get_first_slot_id(type) : + linecard_num = periph.get_periph_number(periph_type.LINECARD) + psu_num = periph.get_periph_number(periph_type.PSU) + if type == periph_type.LINECARD or type == periph_type.CU or type == periph_type.CHASSIS : + return 1 + elif type == periph_type.PSU : + # the fan is behind the linecard + return 1 + linecard_num + elif type == periph_type.FAN : + # the fan is behind the psu + return 1 + linecard_num + psu_num + else : + return 0 + +def get_last_slot_id(type) : + start = get_first_slot_id(type) + if start == 0 : + return 0 + + number = periph.get_periph_number(type) + return start + number - 1 + +def get_system_version(): + def inner(client): + return client.get_system_version() + return thrift_try(inner) + +def get_product_name() : + name = "" + def inner(client): + return client.get_inventory(periph_type.CHASSIS, 1) + + result = thrift_try(inner) + if result.ret != error_code.OK : + return name + + return result.inv.model_name + +def get_chassis_mac() : + def inner(client): + return client.get_inventory(periph_type.CHASSIS, 1) + + result = thrift_try(inner) + if result.ret != error_code.OK : + return None + + return result.inv.mac_addr + +def set_power_control(slot_id, type) : + card = linecard.Linecard(slot_id) + return card.set_power_control(type) + +def get_inlet_temp() : + card_temp = INVALID_TEMPERATURE + start = get_first_slot_id(periph_type.LINECARD) + end = get_last_slot_id(periph_type.LINECARD) + for i in range (start, end + 1) : + card = linecard.Linecard(i) + tmp = card.get_temperature() + if tmp and tmp > card_temp : + card_temp = tmp + + if card_temp != INVALID_TEMPERATURE : + return card_temp + + # all linecards are absent + c = cu.Cu(1) + return c.get_temperature() + +def get_outlet_temp() : + temp = INVALID_TEMPERATURE + start = get_first_slot_id(periph_type.FAN) + end = get_last_slot_id(periph_type.FAN) + for i in range (start, end + 1) : + f = fan.Fan(i) + tmp = f.get_temperature() + if tmp and tmp > temp : + temp = tmp + return temp + +def get_reboot_type() : + def inner(client): + return client.get_reboot_type() + return thrift_try(inner) + +def switch_slot_uart(slot_id) : + def inner(client): + return client.switch_slot_uart(slot_id) + return thrift_try(inner) + +def periph_reboot(p_type, id, r_type) : + def inner(client): + return client.periph_reboot(p_type, id, r_type) + return thrift_try(inner) + +def set_fan_speed(id, speed_rate) : + f = fan.Fan(id) + if str(speed_rate) == "auto" : + f.control_mode = fan_control_mode.AUTO + return + + f.control_mode = fan_control_mode.MANUAL + f.set_speed_rate(speed_rate) + +def clearPmByName(name) : + tname = name.split("-")[0] + dbs = db.get_dbs(name, [db.COUNTERS_DB]) + if not dbs : + return + keys = dbs[db.COUNTERS_DB].get_keys(tname) + for k in keys : + if name not in k : + continue + dbs[db.COUNTERS_DB].delete_entry(tname, k) + +def set_led_state(led_type, id, state) : + def inner(client): + return client.set_led_state(led_type, id, state) + return thrift_try(inner) + +def set_led_color(led_type, id, color) : + def inner(client): + return client.set_led_color(led_type, id, color) + return thrift_try(inner) + +def led_flash_by(id, type, colors) : + for color in colors : + set_led_color(type, id, color) + time.sleep(0.5) + set_led_state(type, id, led_state.OFF) + time.sleep(0.5) diff --git a/otn_pmon/thrift_api/device.thrift b/otn_pmon/thrift_api/device.thrift new file mode 100755 index 000000000..0468bada3 --- /dev/null +++ b/otn_pmon/thrift_api/device.thrift @@ -0,0 +1,184 @@ +/** + * Copyright (c) 2021 Alibaba Group and Accelink Technologies + * + * 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, MERCHANTABILITY OR NON-INFRINGEMENT. + * + * See the Apache Version 2.0 License for specific language governing + * permissions and limitations under the License. + **/ + + +typedef i8 ret_code // OK:0, ERROR:1~ +enum error_code { + OK, + ERROR +} + +enum periph_type { + CHASSIS, + LINECARD, + CU, + FAN, + PSU, + UNKNOWN +} + +enum led_type { + CU, + FAN, + PSU, + UNKNOWN +} + +enum led_state { + OFF, + ON +} + +enum led_color { + RED, + GREEN, + YELLOW, + NONE +} + +enum linecard_type { + P230C, + E100C, + E110C, + E120C +} + +enum reboot_type { + POWER, + COLD, + SOFT, + ABNORMAL, + DOG, + BUTTON, +} + +enum power_ctl_type { + OFF, + ON +} + +struct system_version { +1: string fpga; # eg: "1:v1.0;2:v1.1;3:v1.3" +2: string pcb; +3: string bom; +4: string devmgr; +5: string ucd90120; +6: optional string reserve +} + +struct ret_temp { +1: ret_code ret; +2: i32 temperature; +} + +struct psu_info { +1: i32 abs; # absorbed power +2: i32 ambient_temp; # ambient temperature sensors +3: i32 primary_temp; # primary temperature sensors +4: i32 secondary_temp; # secondary temperature sensors +5: i32 vout; # voltage output +6: i32 vin; # voltage input +7: i32 iout; # current output +8: i32 iin; # current input +9: i32 pout; # power output +10: i32 pin; # power input +11: i32 fan; # fan speed +12: i32 capacity; # power capacity +13: optional string reserve # reserve field +} + +struct ret_psu_info { +1: ret_code ret; +2: psu_info info; +} + +struct inventory { +1: optional string type; +2: string model_name; +3: string pn; +4: string sn; +5: string label; +6: string hw_ver; +7: string sw_ver; +8: string mfg_date; +9: string mac_addr; +10: optional string reserve +} + +struct ret_inventory { +1: ret_code ret; +2: inventory inv; +} + +struct fan_speed { +1: i32 front; +2: i32 behind; +} + +struct ret_fan_speed { +1: ret_code ret; +2: fan_speed speed; +} + +struct fan_speed_spec { +1: i32 max; +2: i32 min; +} + +service periph_rpc { + // common APIs + system_version get_system_version(); + + bool periph_presence(1: periph_type type, 2: i8 id); + + string get_periph_version(1: periph_type type, 2: i8 id); + + ret_temp get_periph_temperature(1: periph_type type, 2: i8 id); + + ret_inventory get_inventory(1: periph_type type, 2: i8 id); + + ret_psu_info get_psu_info(1: i8 id); + + bool psu_vin_high(1: i8 id); + + bool psu_vin_low(1: i8 id); + + ret_code set_led_state(1: led_type type, 2: i8 id, 3: led_state state); + + ret_code set_led_color(1: led_type type, 2: i8 id, 3: led_color color); + + reboot_type get_reboot_type(); + + ret_code periph_reboot(1: periph_type ptype, 2: i8 id, 3: reboot_type rtype); + + string get_power_control_version(1: i8 slot_id); + + ret_code set_power_control(1: i8 slot_id, 2: power_ctl_type type); + + ret_code recover_linecard_default_config(1: i8 id, 2: linecard_type type); + + ret_code switch_slot_uart(1: i8 id); + + ret_fan_speed get_fan_speed(1: i8 id); + + fan_speed_spec get_fan_speed_spec(1: i8 id); + + ret_code set_fan_speed_rate(1: i8 id, 2: i32 speed_rate); + + string get_fpga_version(1: i8 id); +} + + diff --git a/otn_pmon/thrift_client.py b/otn_pmon/thrift_client.py new file mode 100644 index 000000000..9c5d49c73 --- /dev/null +++ b/otn_pmon/thrift_client.py @@ -0,0 +1,52 @@ +## +# Copyright (c) 2021 Alibaba Group and Accelink Technologies +# +# 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, MERCHANTABILITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +## + +import time +import importlib +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol +from thrift.Thrift import TException + +THRIFT_SERVER = 'localhost' +THRIFT_SERVER_PORT = 9092 + +class ThriftClient(object): + def open(self): + socket = TSocket.TSocket(THRIFT_SERVER, THRIFT_SERVER_PORT) + self.transport = TTransport.TBufferedTransport(socket) + bprotocol = TBinaryProtocol.TBinaryProtocol(self.transport) + + periph_rpc = importlib.import_module("otn_pmon.thrift_api.periph_rpc") + self.pltfm_mgr = periph_rpc.Client(bprotocol) + + self.transport.open() + return self + def close(self): + self.transport.close() + def __enter__(self): + return self.open() + def __exit__(self, exc_type, exc_value, tb): + self.close() + +def thrift_try(func, attempts=35): + for attempt in range(attempts): + try: + with ThriftClient() as client: + return func(client.pltfm_mgr) + except TException as e: + if attempt + 1 == attempts: + raise e + time.sleep(1) diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index f540f4138..000000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -addopts = --cov=sonic_platform_base --cov-report html --cov-report term --cov-report xml --junitxml=test-results.xml -v diff --git a/setup.py b/setup.py index 9d8a669b9..b74ac9980 100644 --- a/setup.py +++ b/setup.py @@ -1,42 +1,22 @@ +import os from setuptools import setup +def get_packages() : + os.system("thrift --gen py --out ./otn_pmon/thrift_api ./otn_pmon/thrift_api/device.thrift") + os.system("mv ./otn_pmon/thrift_api/device/* ./otn_pmon/thrift_api") + os.system("rm -rf ./otn_pmon/thrift_api/device") + return ['otn_pmon', 'otn_pmon.thrift_api'] + setup( name='sonic-platform-common', version='1.0', - description='Platform-specific peripheral hardware interface APIs for SONiC', + description='Platform-specific peripheral hardware interface APIs for SONiC-OTN', license='Apache 2.0', - author='SONiC Team', - author_email='linuxnetdev@microsoft.com', - url='https://github.com/Azure/sonic-platform-common', - maintainer='Joe LeVeque', - maintainer_email='jolevequ@microsoft.com', - packages=[ - 'sonic_eeprom', - 'sonic_led', - 'sonic_fan', - 'sonic_platform_base', - 'sonic_platform_base.sonic_eeprom', - 'sonic_platform_base.sonic_sfp', - 'sonic_platform_base.sonic_ssd', - 'sonic_platform_base.sonic_pcie', - 'sonic_platform_base.sonic_thermal_control', - 'sonic_platform_base.sonic_xcvr', - 'sonic_platform_base.sonic_xcvr.fields', - 'sonic_platform_base.sonic_xcvr.fields.public', - 'sonic_platform_base.sonic_xcvr.mem_maps', - 'sonic_platform_base.sonic_xcvr.mem_maps.public', - 'sonic_platform_base.sonic_xcvr.api', - 'sonic_platform_base.sonic_xcvr.api.public', - 'sonic_platform_base.sonic_xcvr.codes', - 'sonic_platform_base.sonic_xcvr.codes.public', - 'sonic_psu', - 'sonic_sfp', - 'sonic_thermal', - 'sonic_y_cable', - 'sonic_y_cable.credo', - 'sonic_y_cable.broadcom', - 'sonic_y_cable.microsoft' - ], + author='SONiC-otn Team', + author_email='sonic-wg-otn@lists.sonicfoundation.dev', + url='https://github.com/zhengweitang-zwt/sonic-otn-platform-common', + maintainer='leixin', + packages=get_packages(), # NOTE: Install also depends on sonic-config-engine for portconfig.py # This dependency should be eliminated by moving portconfig.py # functionality into sonic-py-common @@ -44,7 +24,6 @@ 'natsort==6.2.1', # 6.2.1 is the last version which supports Python 2 'PyYAML', 'redis', - 'sonic-config-engine', 'sonic-py-common' ], setup_requires = [ diff --git a/sonic_eeprom b/sonic_eeprom deleted file mode 120000 index 0ef76adaa..000000000 --- a/sonic_eeprom +++ /dev/null @@ -1 +0,0 @@ -sonic_platform_base/sonic_eeprom \ No newline at end of file diff --git a/sonic_fan/fan_base.py b/sonic_fan/fan_base.py deleted file mode 100644 index 9c3a0adc6..000000000 --- a/sonic_fan/fan_base.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# fan_base.py -# -# Base class for implementing platform-specific -# FAN control functionality for SONiC -# - -try: - import abc -except ImportError as e: - raise ImportError (str(e) + " - required module not found") - -class FanBase(object): - __metaclass__ = abc.ABCMeta - - # Possible fan directions (relative to port-side of device) - FAN_DIRECTION_INTAKE = "intake" - FAN_DIRECTION_EXHAUST = "exhaust" - FAN_DIRECTION_NOT_APPLICABLE = "N/A" - - def get_num_fans(self): - """ - Retrieves the number of FANs supported on the device - - :return: An integer, the number of FANs supported on the device - """ - return 0 - - def get_status(self, index): - """ - Retrieves the operational status of FAN defined - by index 1-based - - :param index: An integer, 1-based index of the PSU of which to query status - :return: Boolean, - - True if FAN is running with some speed - - False if FAN has stopped running - """ - return False - - def get_presence(self, index): - """ - Retrieves the presence status of a FAN defined - by 1-based index - - :param index: An integer, 1-based index of the FAN of which to query status - :return: Boolean, True if FAN is plugged, False if not - """ - return False - - def get_direction(self, index): - """ - Retrieves the airflow direction of a FAN defined - by 1-based index - - :param index: An integer, 1-based index of the FAN of which to query status - :return: string, denoting FAN airflow direction - """ - return "" - - def get_speed(self, index): - """ - Retrieves the speed of a FAN in the tray in revolutions per minute defined - by 1-based index - - :param index: An integer, 1-based index of the FAN of which to query speed - :return: integer, denoting front FAN speed - """ - return 0 - - def set_speed(self, val): - """ - Sets the speed of all the FANs to a value denoted by the duty-cycle percentage val - - :param val: An integer, <0-100> denoting FAN duty cycle percentage - :return: Boolean, True if operation is successful, False if not - """ - return False diff --git a/sonic_led/__init__.py b/sonic_led/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_led/led_control_base.py b/sonic_led/led_control_base.py deleted file mode 100644 index 9505f2a4a..000000000 --- a/sonic_led/led_control_base.py +++ /dev/null @@ -1,24 +0,0 @@ -# -# led_control_base.py -# -# Abstract base class for implementing platform-specific -# LED control functionality for SONiC -# - -try: - import abc -except ImportError as e: - raise ImportError (str(e) + " - required module not found") - -class LedControlBase(object): - __metaclass__ = abc.ABCMeta - - @abc.abstractmethod - def port_link_state_change(self, port, state): - """ - Called when port link state changes. Update port link state LED here. - - :param port: A string, SONiC port name (e.g., "Ethernet0") - :param state: A string, the port link state (either "up" or "down") - """ - return diff --git a/sonic_platform_base/__init__.py b/sonic_platform_base/__init__.py deleted file mode 100644 index 3d7f64b24..000000000 --- a/sonic_platform_base/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from . import chassis_base -from . import component_base -from . import device_base -from . import fan_base -from . import fan_drawer_base -from . import module_base -from . import platform_base -from . import psu_base -from . import sfp_base -from . import thermal_base -from . import watchdog_base diff --git a/sonic_platform_base/chassis_base.py b/sonic_platform_base/chassis_base.py deleted file mode 100644 index e292cfcd3..000000000 --- a/sonic_platform_base/chassis_base.py +++ /dev/null @@ -1,605 +0,0 @@ -""" - chassis_base.py - - Base class for implementing a platform-specific class with which - to interact with a chassis device in SONiC. -""" - -import sys -from . import device_base -from . import sfp_base - -class ChassisBase(device_base.DeviceBase): - """ - Base class for interfacing with a platform chassis - """ - # Device type definition. Note, this is a constant. - DEVICE_TYPE = "chassis" - - # Possible reboot causes - REBOOT_CAUSE_POWER_LOSS = "Power Loss" - REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload: CPU" - REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload: ASIC" - REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload: Other" - REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED = "Insufficient Fan Speed" - REBOOT_CAUSE_WATCHDOG = "Watchdog" - REBOOT_CAUSE_HARDWARE_OTHER = "Hardware - Other" - REBOOT_CAUSE_HARDWARE_BIOS = "BIOS" - REBOOT_CAUSE_HARDWARE_CPU = "CPU" - REBOOT_CAUSE_HARDWARE_BUTTON = "Push button" - REBOOT_CAUSE_HARDWARE_RESET_FROM_ASIC = "Reset from ASIC" - REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware" - - def __init__(self): - # List of ComponentBase-derived objects representing all components - # available on the chassis - self._component_list = [] - - # List of ModuleBase-derived objects representing all modules - # available on the chassis (for use with modular chassis) - self._module_list = [] - - # List of FanBase-derived objects representing all fans - # available on the chassis - self._fan_list = [] - - # List of FanDrawerBase-derived objects representing all fan drawers - # available on the chassis - self._fan_drawer_list = [] - - # List of PsuBase-derived objects representing all power supply units - # available on the chassis - self._psu_list = [] - - # List of ThermalBase-derived objects representing all thermals - # available on the chassis - self._thermal_list = [] - - # List of SfpBase-derived objects representing all sfps - # available on the chassis - self._sfp_list = [] - - # Object derived from WatchdogBase for interacting with hardware watchdog - self._watchdog = None - - # Object derived from eeprom_tlvinfo.TlvInfoDecoder indicating the eeprom on the chassis - self._eeprom = None - - # System status LED - self._status_led = None - - - 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' - """ - raise NotImplementedError - - 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. - Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', - '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', - '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} - """ - raise NotImplementedError - - 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. - """ - raise NotImplementedError - - def get_supervisor_slot(self): - """ - Retrieves the physical-slot of the supervisor-module in the modular - chassis. On the supervisor or line-card modules, it will return the - physical-slot of the supervisor-module. - - On the fixed-platforms, the API can be ignored. - - Users of the API can catch the exception and return a default - ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. - - Returns: - An integer, the vendor specific physical slot identifier of the - supervisor module in the modular-chassis. - """ - return NotImplementedError - - def get_my_slot(self): - """ - Retrieves the physical-slot of this module in the modular chassis. - On the supervisor, it will return the physical-slot of the supervisor - module. On the linecard, it will return the physical-slot of the - linecard module where this instance of SONiC is running. - - On the fixed-platforms, the API can be ignored. - - Users of the API can catch the exception and return a default - ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms. - - Returns: - An integer, the vendor specific physical slot identifier of this - module in the modular-chassis. - """ - return NotImplementedError - - def is_modular_chassis(self): - """ - Retrieves whether the sonic instance is part of modular chassis - - Returns: - A bool value, should return False by default or for fixed-platforms. - Should return True for supervisor-cards, line-cards etc running as part - of modular-chassis. - """ - return False - - def init_midplane_switch(self): - """ - Initializes the midplane functionality of the modular chassis. For - example, any validation of midplane, populating any lookup tables etc - can be done here. The expectation is that the required kernel modules, - ip-address assignment etc are done before the pmon, database dockers - are up. - - Returns: - A bool value, should return True if the midplane initialized - successfully. - """ - return NotImplementedError - - ############################################## - # Component methods - ############################################## - - def get_num_components(self): - """ - Retrieves the number of components available on this chassis - - Returns: - An integer, the number of components available on this chassis - """ - return len(self._component_list) - - def get_all_components(self): - """ - Retrieves all components available on this chassis - - Returns: - A list of objects derived from ComponentBase representing all components - available on this chassis - """ - return self._component_list - - def get_component(self, index): - """ - Retrieves component represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the component to retrieve - - Returns: - An object dervied from ComponentBase representing the specified component - """ - component = None - - try: - component = self._component_list[index] - except IndexError: - sys.stderr.write("Component index {} out of range (0-{})\n".format( - index, len(self._component_list)-1)) - - return component - - ############################################## - # Module methods - ############################################## - - def get_num_modules(self): - """ - Retrieves the number of modules available on this chassis - - Returns: - An integer, the number of modules available on this chassis - """ - return len(self._module_list) - - def get_all_modules(self): - """ - Retrieves all modules available on this chassis - - Returns: - A list of objects derived from ModuleBase representing all - modules available on this chassis - """ - return self._module_list - - def get_module(self, index): - """ - Retrieves module represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the module to - retrieve - - Returns: - An object dervied from ModuleBase representing the specified - module - """ - module = None - - try: - module = self._module_list[index] - except IndexError: - sys.stderr.write("Module index {} out of range (0-{})\n".format( - index, len(self._module_list)-1)) - - return module - - def get_module_index(self, module_name): - """ - Retrieves module index from the module name - - Args: - module_name: A string, prefixed by SUPERVISOR, LINE-CARD or FABRIC-CARD - Ex. SUPERVISOR0, LINE-CARD1, FABRIC-CARD5 - - Returns: - An integer, the index of the ModuleBase object in the module_list - """ - raise NotImplementedError - - ############################################## - # Fan methods - ############################################## - - def get_num_fans(self): - """ - Retrieves the number of fans available on this chassis - - Returns: - An integer, the number of fan modules available on this chassis - """ - return len(self._fan_list) - - def get_all_fans(self): - """ - Retrieves all fan modules available on this chassis - - Returns: - A list of objects derived from FanBase representing all fan - modules available on this chassis - """ - return self._fan_list - - def get_fan(self, index): - """ - Retrieves fan module represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the fan module to - retrieve - - Returns: - An object dervied from FanBase representing the specified fan - module - """ - fan = None - - try: - fan = self._fan_list[index] - except IndexError: - sys.stderr.write("Fan index {} out of range (0-{})\n".format( - index, len(self._fan_list)-1)) - - return fan - - def get_num_fan_drawers(self): - """ - Retrieves the number of fan drawers available on this chassis - - Returns: - An integer, the number of fan drawers available on this chassis - """ - return len(self._fan_drawer_list) - - def get_all_fan_drawers(self): - """ - Retrieves all fan drawers available on this chassis - - Returns: - A list of objects derived from FanDrawerBase representing all fan - drawers available on this chassis - """ - return self._fan_drawer_list - - def get_fan_drawer(self, index): - """ - Retrieves fan drawers represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the fan drawer to - retrieve - - Returns: - An object dervied from FanDrawerBase representing the specified fan - drawer - """ - fan_drawer = None - - try: - fan_drawer = self._fan_drawer_list[index] - except IndexError: - sys.stderr.write("Fan drawer index {} out of range (0-{})\n".format( - index, len(self._fan_drawer_list)-1)) - - return fan_drawer - - ############################################## - # PSU methods - ############################################## - - def get_num_psus(self): - """ - Retrieves the number of power supply units available on this chassis - - Returns: - An integer, the number of power supply units available on this - chassis - """ - return len(self._psu_list) - - def get_all_psus(self): - """ - Retrieves all power supply units available on this chassis - - Returns: - A list of objects derived from PsuBase representing all power - supply units available on this chassis - """ - return self._psu_list - - def get_psu(self, index): - """ - Retrieves power supply unit represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the power supply unit to - retrieve - - Returns: - An object dervied from PsuBase representing the specified power - supply unit - """ - psu = None - - try: - psu = self._psu_list[index] - except IndexError: - sys.stderr.write("PSU index {} out of range (0-{})\n".format( - index, len(self._psu_list)-1)) - - return psu - - ############################################## - # THERMAL methods - ############################################## - - def get_num_thermals(self): - """ - Retrieves the number of thermals available on this chassis - - Returns: - An integer, the number of thermals available on this chassis - """ - return len(self._thermal_list) - - def get_all_thermals(self): - """ - Retrieves all thermals available on this chassis - - Returns: - A list of objects derived from ThermalBase representing all thermals - available on this chassis - """ - return self._thermal_list - - def get_thermal(self, index): - """ - Retrieves thermal unit represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the thermal to - retrieve - - Returns: - An object dervied from ThermalBase representing the specified thermal - """ - thermal = None - - try: - thermal = self._thermal_list[index] - except IndexError: - sys.stderr.write("THERMAL index {} out of range (0-{})\n".format( - index, len(self._thermal_list)-1)) - - return thermal - - def get_thermal_manager(self): - """ - Retrieves thermal manager class on this chassis - :return: A class derived from ThermalManagerBase representing the - specified thermal manager. ThermalManagerBase is returned as default - """ - raise NotImplementedError - - ############################################## - # SFP methods - ############################################## - - def get_num_sfps(self): - """ - Retrieves the number of sfps available on this chassis - - Returns: - An integer, the number of sfps available on this chassis - """ - return len(self._sfp_list) - - def get_all_sfps(self): - """ - Retrieves all sfps available on this chassis - - Returns: - A list of objects derived from SfpBase representing all sfps - available on this chassis - """ - return [ sfp for sfp in self._sfp_list if sfp is not None ] - - def get_sfp(self, index): - """ - Retrieves sfp corresponding to physical port - - Args: - index: An integer (>=0), the index of the sfp to retrieve. - The index should correspond to the physical port in a chassis. - For example:- - 1 for Ethernet0, 2 for Ethernet4 and so on for one platform. - 0 for Ethernet0, 1 for Ethernet4 and so on for another platform. - - Returns: - An object dervied from SfpBase representing the specified sfp - """ - sfp = None - - try: - sfp = self._sfp_list[index] - except IndexError: - sys.stderr.write("SFP index {} out of range (0-{})\n".format( - index, len(self._sfp_list)-1)) - - return sfp - - - def get_port_or_cage_type(self, index): - """ - Retrieves sfp port or cage type corresponding to physical port - - Args: - index: An integer (>=0), the index of the sfp to retrieve. - The index should correspond to the physical port in a chassis. - For example:- - 1 for Ethernet0, 2 for Ethernet4 and so on for one platform. - 0 for Ethernet0, 1 for Ethernet4 and so on for another platform. - - Returns: - The masks of all types of port or cage that can be supported on the port - Types are defined in sfp_base.py - Eg. - Both SFP and SFP+ are supported on the port, the return value should be 0x0a - which is 0x02 | 0x08 - """ - raise NotImplementedError - - ############################################## - # System LED methods - ############################################## - - def set_status_led(self, color): - """ - Sets the state of the system LED - - Args: - color: A string representing the color with which to set the - system LED - - Returns: - bool: True if system LED state is set successfully, False if not - """ - raise NotImplementedError - - def get_status_led(self): - """ - Gets the state of the system LED - - Returns: - A string, one of the valid LED color strings which could be vendor - specified. - """ - raise NotImplementedError - - ############################################## - # Other methods - ############################################## - - def get_watchdog(self): - """ - Retreives hardware watchdog device on this chassis - - Returns: - An object derived from WatchdogBase representing the hardware - watchdog device - """ - return self._watchdog - - def get_eeprom(self): - """ - Retreives eeprom device on this chassis - - Returns: - An object derived from WatchdogBase representing the hardware - eeprom device - """ - return self._eeprom - - def get_change_event(self, timeout=0): - """ - Returns a nested dictionary containing all devices which have - experienced a change at chassis level - - Args: - timeout: Timeout in milliseconds (optional). If timeout == 0, - this method will block until a change is detected. - - Returns: - (bool, dict): - - True if call successful, False if not; - - A nested dictionary where key is a device type, - value is a dictionary with key:value pairs in the format of - {'device_id':'device_event'}, - where device_id is the device ID for this device and - device_event, - status='1' represents device inserted, - status='0' represents device removed. - Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} - indicates that fan 0 has been removed, fan 2 - has been inserted and sfp 11 has been removed. - Specifically for SFP event, besides SFP plug in and plug out, - there are some other error event could be raised from SFP, when - these error happened, SFP eeprom will not be avalaible, XCVRD shall - stop to read eeprom before SFP recovered from error status. - status='2' I2C bus stuck, - status='3' Bad eeprom, - status='4' Unsupported cable, - status='5' High Temperature, - status='6' Bad cable. - """ - raise NotImplementedError diff --git a/sonic_platform_base/component_base.py b/sonic_platform_base/component_base.py deleted file mode 100644 index 8f3887f95..000000000 --- a/sonic_platform_base/component_base.py +++ /dev/null @@ -1,150 +0,0 @@ -""" - component_base.py - - Abstract base class for implementing a platform-specific class - to interact with a chassis/module component (e.g., BIOS, CPLD, FPGA, etc.) in SONiC -""" - -# Return codes for firmware updates - -FW_AUTO_INSTALLED = 1 -FW_AUTO_UPDATED = 2 -FW_AUTO_SCHEDULED = 3 -FW_AUTO_ERR_BOOT_TYPE = -1 -FW_AUTO_ERR_IMAGE = -2 -FW_AUTO_ERR_UNKNOWN = -3 - - -class ComponentBase(object): - """ - Abstract base class for implementing a platform-specific class - to interact with a chassis/module component (e.g., BIOS, CPLD, FPGA, etc.) - """ - - def get_name(self): - """ - Retrieves the name of the component - - Returns: - A string containing the name of the component - """ - raise NotImplementedError - - def get_description(self): - """ - Retrieves the description of the component - - Returns: - A string containing the description of the component - """ - raise NotImplementedError - - def get_firmware_version(self): - """ - Retrieves the firmware version of the component - - Note: the firmware version will be read from HW - - Returns: - A string containing the firmware version of the component - """ - raise NotImplementedError - - def get_available_firmware_version(self, image_path): - """ - Retrieves the available firmware version of the component - - Note: the firmware version will be read from image - - Args: - image_path: A string, path to firmware image - - Returns: - A string containing the available firmware version of the component - """ - raise NotImplementedError - - def get_firmware_update_notification(self, image_path): - """ - Retrieves a notification on what should be done in order to complete - the component firmware update - - Args: - image_path: A string, path to firmware image - - Returns: - A string containing the component firmware update notification if required. - By default 'None' value will be used, which indicates that no actions are required - """ - return None - - def install_firmware(self, image_path): - """ - Installs firmware to the component - - This API performs firmware installation only: this may/may not be the same as firmware update. - In case platform component requires some extra steps (apart from calling Low Level Utility) - to load the installed firmware (e.g, reboot, power cycle, etc.) - this must be done manually by user - - Note: in case immediate actions are required to complete the component firmware update - (e.g., reboot, power cycle, etc.) - will be done automatically by API and no return value provided - - Args: - image_path: A string, path to firmware image - - Returns: - A boolean, True if install was successful, False if not - """ - raise NotImplementedError - - def update_firmware(self, image_path): - """ - Updates firmware of the component - - This API performs firmware update: it assumes firmware installation and loading in a single call. - In case platform component requires some extra steps (apart from calling Low Level Utility) - to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API - - Args: - image_path: A string, path to firmware image - - Returns: - Boolean False if image_path doesn't exist instead of throwing an exception error - Nothing when the update is successful - - Raises: - RuntimeError: update failed - """ - raise NotImplementedError - - def auto_update_firmware(self, image_path, boot_type): - """ - Updates firmware of the component - - This API performs firmware update automatically based on boot_type: it assumes firmware installation - and/or creating a loading task during the reboot, if needed, in a single call. - In case platform component requires some extra steps (apart from calling Low Level Utility) - to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically during the reboot. - The loading task will be created by API. - - Args: - image_path: A string, path to firmware image - boot_type: A string, reboot type following the upgrade - - none/fast/warm/cold - - Returns: - Output: A return code - return_code: An integer number, status of component firmware auto-update - - return code of a positive number indicates successful auto-update - - status_installed = 1 - - status_updated = 2 - - status_scheduled = 3 - - return_code of a negative number indicates failed auto-update - - status_err_boot_type = -1 - - status_err_image = -2 - - status_err_unknown = -3 - - Raises: - RuntimeError: auto-update failure cause - """ - raise NotImplementedError diff --git a/sonic_platform_base/device_base.py b/sonic_platform_base/device_base.py deleted file mode 100644 index 02227b9b1..000000000 --- a/sonic_platform_base/device_base.py +++ /dev/null @@ -1,91 +0,0 @@ -""" - device_base.py - - Abstract base class for interfacing with a generic type of platform - peripheral device in SONiC -""" - - -class DeviceBase(object): - """ - Abstract base class for interfacing with a generic type of platform - peripheral device - """ - - # Possible status LED colors - STATUS_LED_COLOR_GREEN = "green" - STATUS_LED_COLOR_AMBER = "amber" - STATUS_LED_COLOR_RED = "red" - STATUS_LED_COLOR_OFF = "off" - - def get_name(self): - """ - Retrieves the name of the device - - Returns: - string: The name of the device - """ - raise NotImplementedError - - - def get_presence(self): - """ - Retrieves the presence of the device - - Returns: - bool: True if device is present, False if not - """ - raise NotImplementedError - - def get_model(self): - """ - Retrieves the model number (or part number) of the device - - Returns: - string: Model/part number of device - """ - raise NotImplementedError - - def get_serial(self): - """ - Retrieves the serial number of the device - - Returns: - string: Serial number of device - """ - raise NotImplementedError - - def get_revision(self): - """ - Retrieves the hardware revision of the device - - Returns: - string: Revision value of device - """ - raise NotImplementedError - - def get_status(self): - """ - Retrieves the operational status of the device - - Returns: - A boolean value, True if device is operating properly, False if not - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - def is_replaceable(self): - """ - Indicate whether this device is replaceable. - Returns: - bool: True if it is replaceable. - """ - raise NotImplementedError diff --git a/sonic_platform_base/fan_base.py b/sonic_platform_base/fan_base.py deleted file mode 100644 index 2b1259144..000000000 --- a/sonic_platform_base/fan_base.py +++ /dev/null @@ -1,102 +0,0 @@ -""" - fan_base.py - - Abstract base class for implementing a platform-specific class with which - to interact with a fan module in SONiC -""" - -from . import device_base - - -class FanBase(device_base.DeviceBase): - """ - Abstract base class for interfacing with a fan module - """ - # Device type definition. Note, this is a constant. - DEVICE_TYPE = "fan" - - # Possible fan directions (relative to port-side of device) - FAN_DIRECTION_INTAKE = "intake" - FAN_DIRECTION_EXHAUST = "exhaust" - FAN_DIRECTION_NOT_APPLICABLE = "N/A" - - # Possible fan status LED colors - STATUS_LED_COLOR_GREEN = "green" - STATUS_LED_COLOR_AMBER = "amber" - STATUS_LED_COLOR_RED = "red" - STATUS_LED_COLOR_OFF = "off" - - def get_direction(self): - """ - Retrieves the direction of fan - - Returns: - A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST - depending on fan direction - """ - raise NotImplementedError - - 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) - """ - raise NotImplementedError - - 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) - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError diff --git a/sonic_platform_base/fan_drawer_base.py b/sonic_platform_base/fan_drawer_base.py deleted file mode 100644 index 0f56c8579..000000000 --- a/sonic_platform_base/fan_drawer_base.py +++ /dev/null @@ -1,94 +0,0 @@ -""" - fan_drawer_base.py - - Abstract base class for implementing a platform-specific class with which - to interact with a fan drawer module in SONiC -""" - -import sys -from . import device_base - - -class FanDrawerBase(device_base.DeviceBase): - """ - Abstract base class for interfacing with a fan drawer - """ - # Device type definition. Note, this is a constant. - DEVICE_TYPE = "fan_drawer" - - def __init__(self): - self._fan_list = [] - - def get_num_fans(self): - """ - Retrieves the number of fans available on this fan drawer - - Returns: - An integer, the number of fan modules available on this fan drawer - """ - return len(self._fan_list) - - def get_all_fans(self): - """ - Retrieves all fan modules available on this fan drawer - - Returns: - A list of objects derived from FanBase representing all fan - modules available on this fan drawer - """ - return self._fan_list - - def get_fan(self, index): - """ - Retrieves fan module represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the fan module to - retrieve - - Returns: - An object dervied from FanBase representing the specified fan - module - """ - fan = None - - try: - fan = self._fan_list[index] - except IndexError: - sys.stderr.write("Fan index {} out of range (0-{})\n".format( - index, len(self._fan_list)-1)) - - return fan - - - def set_status_led(self, color): - """ - Sets the state of the fan drawer status LED - - Args: - color: A string representing the color with which to set the - fan drawer status LED - - Returns: - bool: True if status LED state is set successfully, False if not - """ - raise NotImplementedError - - def get_status_led(self): - """ - Gets the state of the fan drawer LED - - Returns: - A string, one of the predefined STATUS_LED_COLOR_* strings above - """ - raise NotImplementedError - - def get_maximum_consumed_power(self): - """ - Retrives the maximum power drawn by Fan Drawer - - Returns: - A float, with value of the maximum consumable power of the - component. - """ - raise NotImplementedError diff --git a/sonic_platform_base/module_base.py b/sonic_platform_base/module_base.py deleted file mode 100644 index 3e96f8b24..000000000 --- a/sonic_platform_base/module_base.py +++ /dev/null @@ -1,498 +0,0 @@ -""" - module_base.py - - Base class for implementing a platform-specific class with which - to interact with a module (as used in a modular chassis) SONiC. -""" - -import sys -from . import device_base - - -class ModuleBase(device_base.DeviceBase): - """ - Base class for interfacing with a module (supervisor module, line card - module, etc. (applicable for a modular chassis) - """ - # Device type definition. Note, this is a constant. - DEVICE_TYPE = "module" - - # Possible card types for modular chassis - MODULE_TYPE_SUPERVISOR = "SUPERVISOR" - MODULE_TYPE_LINE = "LINE-CARD" - MODULE_TYPE_FABRIC = "FABRIC-CARD" - - # Possible card status for modular chassis - # Module state is Empty if no module is inserted in the slot - MODULE_STATUS_EMPTY = "Empty" - # Module state if Offline. This is also the admin-down state. - MODULE_STATUS_OFFLINE = "Offline" - # Module state if power down was triggered. Example, this could be a - # policy action from sensors reaching a critical state triggering the - # module to be powered-down. - MODULE_STATUS_POWERED_DOWN = "PoweredDown" - # Module state is Present when it is powered up, but not fully functional. - MODULE_STATUS_PRESENT = "Present" - # Module state is Present when it is powered up, but entered a fault state. - # Module is not able to go Online. - MODULE_STATUS_FAULT = "Fault" - # Module state is Online when fully operational - MODULE_STATUS_ONLINE = "Online" - - # Invalid slot for modular chassis - MODULE_INVALID_SLOT = -1 - - # Possible reboot types for modular chassis - # Module reboot type to reboot entire card - MODULE_REBOOT_DEFAULT = "Default" - # Module reboot type to reboot CPU complex - MODULE_REBOOT_CPU_COMPLEX = "CPU" - # Module reboot type to reboot FPGA complex - MODULE_REBOOT_FPGA_COMPLEX = "FPGA" - - def __init__(self): - # List of ComponentBase-derived objects representing all components - # available on the module - self._component_list = [] - - # List of FanBase-derived objects representing all fans - # available on the module - self._fan_list = [] - - # List of PsuBase-derived objects representing all power supply units - # available on the module - self._psu_list = [] - - # List of ThermalBase-derived objects representing all thermals - # available on the module - self._thermal_list = [] - - # List of SfpBase-derived objects representing all sfps - # available on the module - self._sfp_list = [] - - # List of ASIC-derived objects representing all ASICs - # visibile in PCI domain on the module - self._asic_list = [] - - def get_base_mac(self): - """ - Retrieves the base MAC address for the module - - Returns: - A string containing the MAC address in the format - 'XX:XX:XX:XX:XX:XX' - """ - raise NotImplementedError - - def get_system_eeprom_info(self): - """ - Retrieves the full content of system EEPROM information for the module - - Returns: - A dictionary where keys are the type code defined in - OCP ONIE TlvInfo EEPROM format and values are their corresponding - values. - Ex. { '0x21': 'AG9064', '0x22': 'V1.0', '0x23': 'AG9064-0109867821', - '0x24': '001c0f000fcd0a', '0x25': '02/03/2018 16:22:00', - '0x26': '01', '0x27': 'REV01', '0x28': 'AG9064-C2358-16G'} - """ - raise NotImplementedError - - def get_name(self): - """ - Retrieves the name of the module prefixed by SUPERVISOR, LINE-CARD, - FABRIC-CARD - - Returns: - A string, the module name prefixed by one of MODULE_TYPE_SUPERVISOR, - MODULE_TYPE_LINE or MODULE_TYPE_FABRIC and followed by a 0-based index - - Ex. A Chassis having 1 supervisor, 4 line-cards and 6 fabric-cards - can provide names SUPERVISOR0, LINE-CARD0 to LINE-CARD3, - FABRIC-CARD0 to FABRIC-CARD5 - """ - raise NotImplementedError - - def get_description(self): - """ - Retrieves the platform vendor's product description of the module - - Returns: - A string, providing the vendor's product description of the module. - """ - raise NotImplementedError - - def get_slot(self): - """ - Retrieves the platform vendor's slot number of the module - - Returns: - An integer, indicating the slot number in the chassis - """ - raise NotImplementedError - - def get_type(self): - """ - Retrieves the type of the module. - - Returns: - A string, the module-type from one of the predefined types: - MODULE_TYPE_SUPERVISOR, MODULE_TYPE_LINE or MODULE_TYPE_FABRIC - """ - raise NotImplementedError - - def get_oper_status(self): - """ - Retrieves the operational status of the module - - Returns: - A string, the operational status of the module from one of the - predefined status values: MODULE_STATUS_EMPTY, MODULE_STATUS_OFFLINE, - MODULE_STATUS_FAULT, MODULE_STATUS_PRESENT or MODULE_STATUS_ONLINE - """ - raise NotImplementedError - - def reboot(self, reboot_type): - """ - Request to reboot the module - - Args: - reboot_type: A string, the type of reboot requested from one of the - predefined reboot types: MODULE_REBOOT_DEFAULT, MODULE_REBOOT_CPU_COMPLEX, - or MODULE_REBOOT_FPGA_COMPLEX - - Returns: - bool: True if the request has been issued successfully, False if not - """ - raise NotImplementedError - - def set_admin_state(self, up): - """ - Request to keep the card in administratively up/down state. - The down state will power down the module and the status should show - MODULE_STATUS_OFFLINE. - The up state will take the module to MODULE_STATUS_FAULT or - MODULE_STAUS_ONLINE states. - - Args: - up: A boolean, True to set the admin-state to UP. False to set the - admin-state to DOWN. - - Returns: - bool: True if the request has been issued successfully, False if not - """ - raise NotImplementedError - - def get_maximum_consumed_power(self): - """ - Retrives the maximum power drawn by this module - - Returns: - A float, with value of the maximum consumable power of the - module. - """ - raise NotImplementedError - - ############################################## - # Component methods - ############################################## - - def get_num_components(self): - """ - Retrieves the number of components available on this module - - Returns: - An integer, the number of components available on this module - """ - return len(self._component_list) - - def get_all_components(self): - """ - Retrieves all components available on this module - - Returns: - A list of objects derived from ComponentBase representing all components - available on this module - """ - return self._component_list - - def get_component(self, index): - """ - Retrieves component represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the component to retrieve - - Returns: - An object dervied from ComponentBase representing the specified component - """ - component = None - - try: - component = self._component_list[index] - except IndexError: - sys.stderr.write("Component index {} out of range (0-{})\n".format( - index, len(self._component_list)-1)) - - return component - - ############################################## - # Fan module methods - ############################################## - - def get_num_fans(self): - """ - Retrieves the number of fan modules available on this module - - Returns: - An integer, the number of fan modules available on this module - """ - return len(self._fan_list) - - def get_all_fans(self): - """ - Retrieves all fan modules available on this module - - Returns: - A list of objects derived from FanBase representing all fan - modules available on this module - """ - return self._fan_list - - def get_fan(self, index): - """ - Retrieves fan module represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the fan module to - retrieve - - Returns: - An object dervied from FanBase representing the specified fan - module - """ - fan = None - - try: - fan = self._fan_list[index] - except IndexError: - sys.stderr.write("Fan index {} out of range (0-{})\n".format( - index, len(self._fan_list)-1)) - - return fan - - ############################################## - # PSU module methods - ############################################## - - def get_num_psus(self): - """ - Retrieves the number of power supply units available on this module - - Returns: - An integer, the number of power supply units available on this - module - """ - return len(self._psu_list) - - def get_all_psus(self): - """ - Retrieves all power supply units available on this module - - Returns: - A list of objects derived from PsuBase representing all power - supply units available on this module - """ - return self._psu_list - - def get_psu(self, index): - """ - Retrieves power supply unit represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the power supply unit to - retrieve - - Returns: - An object dervied from PsuBase representing the specified power - supply unit - """ - psu = None - - try: - psu = self._psu_list[index] - except IndexError: - sys.stderr.write("PSU index {} out of range (0-{})\n".format( - index, len(self._psu_list)-1)) - - return psu - - ############################################## - # THERMAL methods - ############################################## - - def get_num_thermals(self): - """ - Retrieves the number of thermals available on this module - - Returns: - An integer, the number of thermals available on this module - """ - return len(self._thermal_list) - - def get_all_thermals(self): - """ - Retrieves all thermals available on this module - - Returns: - A list of objects derived from ThermalBase representing all thermals - available on this module - """ - return self._thermal_list - - def get_thermal(self, index): - """ - Retrieves thermal unit represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the thermal to - retrieve - - Returns: - An object dervied from ThermalBase representing the specified thermal - """ - thermal = None - - try: - thermal = self._thermal_list[index] - except IndexError: - sys.stderr.write("THERMAL index {} out of range (0-{})\n".format( - index, len(self._thermal_list)-1)) - - return thermal - - ############################################## - # SFP methods - ############################################## - - def get_num_sfps(self): - """ - Retrieves the number of sfps available on this module - - Returns: - An integer, the number of sfps available on this module - """ - return len(self._sfp_list) - - def get_all_sfps(self): - """ - Retrieves all sfps available on this module - - Returns: - A list of objects derived from PsuBase representing all sfps - available on this module - """ - return self._sfp_list - - def get_sfp(self, index): - """ - Retrieves sfp represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the sfp to retrieve - - Returns: - An object dervied from SfpBase representing the specified sfp - """ - sfp = None - - try: - sfp = self._sfp_list[index] - except IndexError: - sys.stderr.write("SFP index {} out of range (0-{})\n".format( - index, len(self._sfp_list)-1)) - - return sfp - - def get_change_event(self, timeout=0): - """ - Returns a nested dictionary containing all devices which have - experienced a change in this module - - Args: - timeout: Timeout in milliseconds (optional). If timeout == 0, - this method will block until a change is detected. - - Returns: - (bool, dict): - - True if call successful, False if not; - - A nested dictionary where key is a device type, - value is a dictionary with key:value pairs in the format of - {'device_id':'device_event'}, - where device_id is the device ID for this device and - device_event, - status='1' represents device inserted, - status='0' represents device removed. - Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} - indicates that fan 0 has been removed, fan 2 - has been inserted and sfp 11 has been removed. - """ - raise NotImplementedError - - ############################################## - # Midplane methods for modular chassis - ############################################## - def get_midplane_ip(self): - """ - Retrieves the midplane IP-address of the module in a modular chassis - When called from the Supervisor, the module could represent the - line-card and return the midplane IP-address of the line-card. - When called from the line-card, the module will represent the - Supervisor and return its midplane IP-address. - - Returns: - A string, the IP-address of the module reachable over the midplane - - """ - raise NotImplementedError - - def is_midplane_reachable(self): - """ - Retrieves the reachability status of the module from the Supervisor or - of the Supervisor from the module via the midplane of the modular chassis - - Returns: - A bool value, should return True if module is reachable via midplane - """ - return NotImplementedError - - ############################################## - # ASIC methods - ############################################## - def get_all_asics(self): - """ - Retrieves the list of all ASICs on the module that are visible in PCI domain. - When called from the Supervisor of modular system, the module could be - fabric card, and the function returns all fabric ASICs on this module that - appear in PCI domain of the Supervisor. - - Returns: - A list of ASICs. Index of an ASIC in the list is the index of the ASIC - on the module. Index is 0 based. - - An item in the list is a tuple that includes: - - ASIC instance number (indexed globally across all modules of - the chassis). This number is used to find settings for the ASIC - from /usr/share/sonic/device/platform/hwsku/asic_instance_number/. - - ASIC PCI address: It is used by syncd to attach the correct ASIC. - - For example: [('4', '0000:05:00.0'), ('5', '0000:07:00.0')] - In this example, from the output, we know the module has 2 ASICs. - Item ('4', '0000:05:00.0') describes information about the first ASIC - in the module. - '4' means it is asic4 in the chassis. Settings for this ASIC is at - /usr/share/sonic/device/platform/hwsku/4/. - And '0000:05:00.0' is its PCI address. - """ - return self._asic_list diff --git a/sonic_platform_base/platform_base.py b/sonic_platform_base/platform_base.py deleted file mode 100644 index f1a77b439..000000000 --- a/sonic_platform_base/platform_base.py +++ /dev/null @@ -1,24 +0,0 @@ -""" - platform_base.py - - Base class for implementing platform-specific functionality in SONiC. - This is the root class of sonic_platform_base hierarchy. A platform - may contain one or more chassis. Classes derived from this class provide - the ability to interact with all available chassis on the platform. -""" - -class PlatformBase(object): - - def __init__(self): - # ChassisBase-derived object representing the platform's chassis - self._chassis = None - - def get_chassis(self): - """ - Retrieves the chassis for this platform - - Returns: - An object derived from ChassisBase representing the platform's - chassis - """ - return self._chassis diff --git a/sonic_platform_base/psu_base.py b/sonic_platform_base/psu_base.py deleted file mode 100644 index 95ec516c4..000000000 --- a/sonic_platform_base/psu_base.py +++ /dev/null @@ -1,286 +0,0 @@ -""" - psu_base.py - - Abstract base class for implementing a platform-specific class with which - to interact with a power supply unit (PSU) in SONiC -""" - -import sys -from . import device_base - - -class PsuBase(device_base.DeviceBase): - """ - Abstract base class for interfacing with a power supply unit - """ - # Device type definition. Note, this is a constant. - DEVICE_TYPE = "psu" - - # Status of Master LED - # This is a class attribute because there is only one master status LED - # on the platform. This attribute is shared among all objects inheriting - # from this class and can be read or set from any of them. - _psu_master_led_color = None - - def __init__(self): - # List of FanBase-derived objects representing all fans - # available on the PSU - self._fan_list = [] - - # List of ThermalBase-derived objects representing all thermals - # available on the PSU - self._thermal_list = [] - - PsuBase._psu_master_led_color = self.STATUS_LED_COLOR_OFF - - def get_num_fans(self): - """ - Retrieves the number of fan modules available on this PSU - - Returns: - An integer, the number of fan modules available on this PSU - """ - return len(self._fan_list) - - def get_all_fans(self): - """ - Retrieves all fan modules available on this PSU - - Returns: - A list of objects derived from FanBase representing all fan - modules available on this PSU - """ - return self._fan_list - - def get_fan(self, index): - """ - Retrieves fan module represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the fan module to - retrieve - - Returns: - An object dervied from FanBase representing the specified fan - module - """ - fan = None - - try: - fan = self._fan_list[index] - except IndexError: - sys.stderr.write("Fan index {} out of range (0-{})\n".format( - index, len(self._fan_list)-1)) - - return fan - - def get_num_thermals(self): - """ - Retrieves the number of thermals available on this PSU - - Returns: - An integer, the number of thermals available on this PSU - """ - return len(self._thermal_list) - - def get_all_thermals(self): - """ - Retrieves all thermals available on this PSU - - Returns: - A list of objects derived from ThermalBase representing all thermals - available on this PSU - """ - return self._thermal_list - - def get_thermal(self, index): - """ - Retrieves thermal unit represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the thermal to - retrieve - - Returns: - An object dervied from ThermalBase representing the specified thermal - """ - thermal = None - - try: - thermal = self._thermal_list[index] - except IndexError: - sys.stderr.write("THERMAL index {} out of range (0-{})\n".format( - index, len(self._thermal_list)-1)) - - return thermal - - def get_voltage(self): - """ - Retrieves current PSU voltage output - - Returns: - A float number, the output voltage in volts, - e.g. 12.1 - """ - raise NotImplementedError - - def get_current(self): - """ - Retrieves present electric current supplied by PSU - - Returns: - A float number, the electric current in amperes, e.g 15.4 - """ - raise NotImplementedError - - def get_power(self): - """ - Retrieves current energy supplied by PSU - - Returns: - A float number, the power in watts, e.g. 302.6 - """ - raise NotImplementedError - - 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. - """ - raise NotImplementedError - - 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 - - Returns: - bool: True if status LED state is set successfully, False if not - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - def get_maximum_supplied_power(self): - """ - Retrieves the maximum supplied power by PSU - - Returns: - A float number, the maximum power output in Watts. - e.g. 1200.1 - """ - raise NotImplementedError - - def get_psu_power_warning_suppress_threshold(self): - """ - Retrieve the warning suppress threshold of the power on this PSU - The value can be volatile, so the caller should call the API each time it is used. - - Returns: - A float number, the warning suppress threshold of the PSU in watts. - """ - raise NotImplementedError - - def get_psu_power_critical_threshold(self): - """ - Retrieve the critical threshold of the power on this PSU - The value can be volatile, so the caller should call the API each time it is used. - - Returns: - A float number, the critical threshold of the PSU in watts. - """ - raise NotImplementedError - - @classmethod - def get_status_master_led(cls): - """ - Gets the state of the Master status LED for a given device-type - - Returns: - A string, one of the predefined STATUS_LED_COLOR_* strings. - """ - return cls._psu_master_led_color - - @classmethod - def set_status_master_led(cls, color): - """ - Gets the state of the Master status LED for a given device-type - - Returns: - bool: True if status LED state is set successfully, False if - not - """ - cls._psu_master_led_color = color - return True - - def get_input_voltage(self): - """ - Retrieves current PSU voltage input - - Returns: - A float number, the input voltage in volts, - e.g. 12.1 - """ - raise NotImplementedError - - def get_input_current(self): - """ - Retrieves the input current draw of the power supply - - Returns: - A float number, the electric current in amperes, e.g 15.4 - """ - raise NotImplementedError diff --git a/sonic_platform_base/sfp_base.py b/sonic_platform_base/sfp_base.py deleted file mode 100644 index 0d98caa29..000000000 --- a/sonic_platform_base/sfp_base.py +++ /dev/null @@ -1,472 +0,0 @@ -""" - sfp_base.py - - Abstract base class for implementing a platform-specific class with which - to interact with a SFP module in SONiC -""" - -import sys -from . import device_base - -from .sonic_xcvr.xcvr_api_factory import XcvrApiFactory - -class SfpBase(device_base.DeviceBase): - """ - Abstract base class for interfacing with a SFP module - """ - # Device type definition. Note, this is a constant. - DEVICE_TYPE = "sfp" - - # Generic error types definition - SFP_STATUS_INITIALIZING = 'Initializing' - SFP_STATUS_OK = 'OK' - SFP_STATUS_UNPLUGGED = 'Unplugged' - SFP_STATUS_DISABLED = 'Disabled' - SFP_ERROR_DESCRIPTION_BLOCKING = 'Blocking EEPROM from being read' - SFP_ERROR_DESCRIPTION_POWER_BUDGET_EXCEEDED = 'Power budget exceeded' - SFP_ERROR_DESCRIPTION_I2C_STUCK = 'Bus stuck (I2C data or clock shorted)' - SFP_ERROR_DESCRIPTION_BAD_EEPROM = 'Bad or unsupported EEPROM' - SFP_ERROR_DESCRIPTION_UNSUPPORTED_CABLE = 'Unsupported cable' - SFP_ERROR_DESCRIPTION_HIGH_TEMP = 'High temperature' - SFP_ERROR_DESCRIPTION_BAD_CABLE = 'Bad cable (module/cable is shorted)' - - # SFP status - SFP_STATUS_BIT_REMOVED = 0x00000000 - SFP_STATUS_BIT_INSERTED = 0x00000001 - # SFP error status - SFP_ERROR_BIT_BLOCKING = 0x00000002 - SFP_ERROR_BIT_POWER_BUDGET_EXCEEDED = 0x00000004 - SFP_ERROR_BIT_I2C_STUCK = 0x00000008 - SFP_ERROR_BIT_BAD_EEPROM = 0x00000010 - SFP_ERROR_BIT_UNSUPPORTED_CABLE = 0x00000020 - SFP_ERROR_BIT_HIGH_TEMP = 0x00000040 - SFP_ERROR_BIT_BAD_CABLE = 0x00000080 - - SFP_ERROR_BIT_TO_DESCRIPTION_DICT = { - SFP_ERROR_BIT_BLOCKING: SFP_ERROR_DESCRIPTION_BLOCKING, - SFP_ERROR_BIT_POWER_BUDGET_EXCEEDED: SFP_ERROR_DESCRIPTION_POWER_BUDGET_EXCEEDED, - SFP_ERROR_BIT_I2C_STUCK: SFP_ERROR_DESCRIPTION_I2C_STUCK, - SFP_ERROR_BIT_BAD_EEPROM: SFP_ERROR_DESCRIPTION_BAD_EEPROM, - SFP_ERROR_BIT_UNSUPPORTED_CABLE: SFP_ERROR_DESCRIPTION_UNSUPPORTED_CABLE, - SFP_ERROR_BIT_HIGH_TEMP: SFP_ERROR_DESCRIPTION_HIGH_TEMP, - SFP_ERROR_BIT_BAD_CABLE: SFP_ERROR_DESCRIPTION_BAD_CABLE - } - - # Port types that are used by the chassis API ChassisBase.get_port_or_cage_type() - # It's possible that multiple types are supported on one port. - # In that case, the result will be logical OR of all the supported types - # Check example in ChassisBase.get_port_or_cage_type() - SFP_PORT_TYPE_BIT_RJ45 = 0x00000001 - SFP_PORT_TYPE_BIT_SFP = 0x00000002 - SFP_PORT_TYPE_BIT_XFP = 0x00000004 - SFP_PORT_TYPE_BIT_SFP_PLUS = 0x00000008 - SFP_PORT_TYPE_BIT_QSFP = 0x00000010 - SFP_PORT_TYPE_BIT_CFP = 0x00000020 - SFP_PORT_TYPE_BIT_QSFP_PLUS = 0x00000040 - SFP_PORT_TYPE_BIT_QSFP28 = 0x00000080 - SFP_PORT_TYPE_BIT_SFP28 = 0x00000100 - SFP_PORT_TYPE_BIT_CFP2 = 0x00000200 - SFP_PORT_TYPE_BIT_QSFP56 = 0x00000400 - SFP_PORT_TYPE_BIT_QSFPDD = 0x00000800 - SFP_PORT_TYPE_BIT_OSFP = 0x00001000 - SFP_PORT_TYPE_BIT_SFP_DD = 0x00002000 - - def __init__(self): - # List of ThermalBase-derived objects representing all thermals - # available on the SFP - self._thermal_list = [] - self._xcvr_api_factory = XcvrApiFactory(self.read_eeprom, self.write_eeprom) - self._xcvr_api = None - - def get_num_thermals(self): - """ - Retrieves the number of thermals available on this SFP - - Returns: - An integer, the number of thermals available on this SFP - """ - return len(self._thermal_list) - - def get_all_thermals(self): - """ - Retrieves all thermals available on this SFP - - Returns: - A list of objects derived from ThermalBase representing all thermals - available on this SFP - """ - return self._thermal_list - - def get_thermal(self, index): - """ - Retrieves thermal unit represented by (0-based) index - - Args: - index: An integer, the index (0-based) of the thermal to - retrieve - - Returns: - An object derived from ThermalBase representing the specified thermal - """ - thermal = None - - try: - thermal = self._thermal_list[index] - except IndexError: - sys.stderr.write("THERMAL index {} out of range (0-{})\n".format( - index, len(self._thermal_list)-1)) - - return thermal - - 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 - type_abbrv_name |1*255VCHAR |type of SFP, abbreviated - hardware_rev |1*255VCHAR |hardware version of SFP - vendor_rev |1*255VCHAR |vendor revision 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 - ================================================================================ - """ - raise NotImplementedError - - 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. - ======================================================================== - """ - raise NotImplementedError - - 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. - ======================================================================== - """ - raise NotImplementedError - - def get_reset_status(self): - """ - Retrieves the reset status of SFP - - Returns: - A Boolean, True if reset enabled, False if disabled - """ - raise NotImplementedError - - def get_rx_los(self): - """ - Retrieves the RX LOS (loss-of-signal) status of SFP - - Returns: - A list of boolean values, representing the RX LOS status - of each available channel, value is True if SFP channel - has RX LOS, False if not. - E.g., for a tranceiver with four channels: [False, False, True, False] - Note : RX LOS status is latched until a call to get_rx_los or a reset. - """ - raise NotImplementedError - - def get_tx_fault(self): - """ - Retrieves the TX fault status of SFP - - Returns: - A list of boolean values, representing the TX fault status - of each available channel, value is True if SFP channel - has TX fault, False if not. - E.g., for a tranceiver with four channels: [False, False, True, False] - Note : TX fault status is lached until a call to get_tx_fault or a reset. - """ - raise NotImplementedError - - 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] - """ - raise NotImplementedError - - 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. - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - def get_temperature(self): - """ - Retrieves the temperature of this SFP - - Returns: - A float representing the current temperature in Celsius - """ - raise NotImplementedError - - - def get_voltage(self): - """ - Retrieves the supply voltage of this SFP - - Returns: - A float representing the supply voltage in mV - """ - raise NotImplementedError - - def get_tx_bias(self): - """ - Retrieves the TX bias current of all SFP channels - - Returns: - A list of floats, representing TX bias in mA - for each available channel - E.g., for a tranceiver with four channels: ['110.09', '111.12', '108.21', '112.09'] - """ - raise NotImplementedError - - def get_rx_power(self): - """ - Retrieves the received optical power of all SFP channels - - Returns: - A list of floats, representing received optical - power in mW for each available channel - E.g., for a tranceiver with four channels: ['1.77', '1.71', '1.68', '1.70'] - """ - raise NotImplementedError - - def get_tx_power(self): - """ - Retrieves the TX power of all SFP channels - - Returns: - A list of floats, representing TX power in mW - for each available channel - E.g., for a tranceiver with four channels: ['1.86', '1.86', '1.86', '1.86'] - """ - raise NotImplementedError - - def reset(self): - """ - Reset SFP and return all user module settings to their default srate. - - Returns: - A boolean, True if successful, False if not - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - def read_eeprom(self, offset, num_bytes): - """ - read eeprom specfic bytes beginning from a random offset with size as num_bytes - - Args: - offset : - Integer, the offset from which the read transaction will start - num_bytes: - Integer, the number of bytes to be read - - Returns: - bytearray, if raw sequence of bytes are read correctly from the offset of size num_bytes - None, if the read_eeprom fails - """ - raise NotImplementedError - - def write_eeprom(self, offset, num_bytes, write_buffer): - """ - write eeprom specfic bytes beginning from a random offset with size as num_bytes - and write_buffer as the required bytes - - Args: - offset : - Integer, the offset from which the read transaction will start - num_bytes: - Integer, the number of bytes to be written - write_buffer: - bytearray, raw bytes buffer which is to be written beginning at the offset - - Returns: - a Boolean, true if the write succeeded and false if it did not succeed. - """ - raise NotImplementedError - - def get_error_description(self): - """ - Retrives the error descriptions of the SFP module - - Returns: - String that represents the current error descriptions of vendor specific errors - In case there are multiple errors, they should be joined by '|', - like: "Bad EEPROM|Unsupported cable" - """ - raise NotImplementedError - - def refresh_xcvr_api(self): - """ - Updates the XcvrApi associated with this SFP - """ - self._xcvr_api = self._xcvr_api_factory.create_xcvr_api() - - def get_xcvr_api(self): - """ - Retrieves the XcvrApi associated with this SFP - - Returns: - An object derived from XcvrApi that corresponds to the SFP - """ - if self._xcvr_api is None: - self.refresh_xcvr_api() - return self._xcvr_api diff --git a/sonic_platform_base/sonic_eeprom/__init__.py b/sonic_platform_base/sonic_eeprom/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_eeprom/eeprom_base.py b/sonic_platform_base/sonic_eeprom/eeprom_base.py deleted file mode 100644 index 083d1cd1f..000000000 --- a/sonic_platform_base/sonic_eeprom/eeprom_base.py +++ /dev/null @@ -1,418 +0,0 @@ -# Copyright 2012 Cumulus Networks LLC, all rights reserved - -############################################################################# -# Base eeprom class containing the main logic for reading, writing, and -# setting the eeprom. The format definition is a list of tuples of: -# ('data name', 'data type', 'size in bytes') -# data type is one of 's', 'C', and 'x' (string, char, and ignore) -# 'burn' as a data name indicates the corresponding number of bytes are to -# be ignored - -from __future__ import print_function - -try: - import binascii - import os - import io - import struct - import fcntl -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - - -class EepromDecoder(object): - def __init__(self, path, format, start, status, readonly): - self.p = path - self.f = format - self.s = start - self.u = status - self.r = readonly - # Warning: the following members are deprecated, the parsed EEPROM data is stored in the - # Redis STATE_DB, cached data should be fetched from STATE_DB.EEPROM_INFO. - self.cache_name = None - self.cache_update_needed = False - self.lock_file = None - - def check_status(self): - if self.u != '': - F = None - try: - F = open(self.u, "r") - d = F.readline().rstrip() - except IOError as e: - raise IOError("Failed to check status : %s" % (str(e))) - finally: - if F is not None: - F.close() - return d - else: - return 'ok' - - def set_cache_name(self, name): - # Warning: this method is deprecated, the parsed EEPROM data is stored in the - # Redis STATE_DB, cached data should be fetched from STATE_DB.EEPROM_INFO. - - # before accessing the eeprom we acquire an exclusive lock on the eeprom file. - # this will prevent a race condition where multiple instances of this app - # could try to update the cache at the same time - self.cache_name = name - self.lock_file = open(self.p, 'r') - fcntl.flock(self.lock_file, fcntl.LOCK_EX) - - def is_read_only(self): - return self.r - - def decoder(self, s, t): - return t - - def encoder(self, I, v): - return v - - def checksum_field_size(self): - return 4 # default - - def is_checksum_field(self, I): - return I[0] == 'crc' # default - - def checksum_type(self): - return 'crc32' - - def encode_checksum(self, crc): - if self.checksum_field_size() == 4: - return struct.pack('>I', crc) - elif self.checksum_field_size() == 1: - return struct.pack('>B', crc) - print('checksum type not yet supported') - exit(1) - - def compute_2s_complement(self, e, size): - crc = 0 - loc = 0 - end = len(e) - while loc != end: - crc += int('0x' + binascii.b2a_hex(e[loc:loc+size]), 0) - loc += size - T = 1 << (size * 8) - return (T - crc) & (T - 1) - - def compute_dell_crc(self, message): - poly = 0x8005 - reg = 0x0000 - message += bytearray(b'\x00\x00') - for byte in message: - mask = 0x80 - while (mask > 0): - reg<<=1 - if byte & mask: - reg += 1 - mask>>=1 - if reg > 0xffff: - reg &= 0xffff - reg ^= poly - return reg - - def calculate_checksum(self, e): - if self.checksum_type() == 'crc32': - return binascii.crc32(e) & 0xffffffff - - if self.checksum_type() == '2s-complement': - size = self.checksum_field_size() - return self.compute_2s_complement(e, size) - - if self.checksum_type() == 'dell-crc': - return self.compute_dell_crc(e) - print('checksum type not yet supported') - exit(1) - - def is_checksum_valid(self, e): - offset = 0 - self.checksum_field_size() - crc = self.calculate_checksum(e[:offset]) - - loc = 0 - for I in self.f: - end = loc + I[2] - t = e[loc:end] - loc = end - if self.is_checksum_field(I): - i = self.decoder(I[0], t) - if int(i, 0) == crc: - return (True, crc) - else: - return (False, crc) - else: - continue - return (False, crc) - - def decode_eeprom(self, e): - loc = 0 - for I in self.f: - end = loc + I[2] - t = e[loc:end] - loc = end - if I[0] == 'burn': - continue - elif I[1] == 's': - i = t - else: - i = self.decoder(I[0], t) - print("%-20s: %s" %(I[0], i)) - - def set_eeprom(self, e, cmd_args): - line = '' - loc = 0 - ndict = {} - fields = list(I[0] for I in list(self.f)) - if len(cmd_args): - for arg in cmd_args[0].split(','): - k, v = arg.split('=') - k = k.strip() - v = v.strip() - if k not in fields: - print("Error: invalid field '%s'" %(k)) - exit(1) - ndict[k] = v - - for I in self.f: - # print the original value - end = loc + I[2] - sl = e[loc:end] - loc = end - if I[0] == 'burn': - #line += sl - # fill with zeros - line = line.ljust(len(line) + I[2], '\x00') - continue - elif I[1] == 's': - i = sl - else: - i = self.decoder(I[0], sl) - - if len(cmd_args) == 0: - if self.is_checksum_field(I): - print("%-20s: %s " %(I[0], i)) - continue - - # prompt for new value - v = raw_input("%-20s: [%s] " %(I[0], i)) - if v == '': - v = i - else: - if I[0] not in ndict.keys(): - v = i - else: - v = ndict[I[0]] - - line += self.encoder(I, v) - - # compute and append crc at the end - crc = self.encode_checksum(self.calculate_checksum(line)) - - line += crc - - return line - - def open_eeprom(self): - ''' - Open the EEPROM device file. - If a cache file exists, use that instead of the EEPROM. - ''' - using_eeprom = True - eeprom_file = self.p - try: - # Warning: cache file is deprecated, the parsed EEPROM data is stored in the - # Redis STATE_DB, cached data should be fetched from STATE_DB.EEPROM_INFO. This - # code need to be adjusted once cache file is completely removing from the system. - if os.path.isfile(self.cache_name): - eeprom_file = self.cache_name - using_eeprom = False - except Exception: - pass - self.cache_update_needed = using_eeprom - return io.open(eeprom_file, "rb") - - def read_eeprom(self): - sizeof_info = 0 - for I in self.f: - sizeof_info += I[2] - o = self.read_eeprom_bytes(sizeof_info) - return o - - def read_eeprom_bytes(self, byteCount, offset=0): - F = None - try: - F = self.open_eeprom() - F.seek(self.s + offset) - o = F.read(byteCount) - - # If we read from the cache file and the byte count isn't what we - # expect, the file may be corrupt. Delete it and try again, this - # time reading from the actual EEPROM. - if len(o) != byteCount and not self.cache_update_needed: - # Warning: cache file is deprecated, the parsed EEPROM data is stored in the - # Redis STATE_DB, cached data should be fetched from STATE_DB.EEPROM_INFO. This - # code needs to be adjusted once cache file is completely removed from the system. - os.remove(self.cache_name) - self.cache_update_needed = True - F.close() - F = self.open_eeprom() - F.seek(self.s + offset) - o = F.read(byteCount) - - if len(o) != byteCount: - raise RuntimeError("Expected to read %d bytes from %s, " - % (byteCount, self.p) + - "but only read %d" % (len(o))) - except IOError as e: - raise IOError("Failed to read eeprom : %s" % (str(e))) - finally: - if F is not None: - F.close() - - return bytearray(o) - - def read_eeprom_db(self): - return 0 - - def write_eeprom(self, e): - F = None - try: - F = open(self.p, "wb") - F.seek(self.s) - F.write(e) - except IOError as e: - raise IOError("Failed to write eeprom : %s" % (str(e))) - finally: - if F is not None: - F.close() - - self.write_cache(e) - - def write_cache(self, e): - # Warning: this method is deprecated, the parsed EEPROM data is stored in the - # Redis STATE_DB, cached data should be fetched from STATE_DB.EEPROM_INFO. - - if self.cache_name: - F = None - try: - F = open(self.cache_name, "wb") - F.seek(self.s) - F.write(e) - except IOError as e: - raise IOError("Failed to write cache : %s" % (str(e))) - finally: - if F is not None: - F.close() - - def update_cache(self, e): - # Warning: this method is deprecated, the parsed EEPROM data is stored in the - # Redis STATE_DB, cached data should be fetched from STATE_DB.EEPROM_INFO. - - if self.cache_update_needed: - self.write_cache(e) - fcntl.flock(self.lock_file, fcntl.LOCK_UN) - self.lock_file.close() - - def update_eeprom_db(self, e): - return 0 - - def diff_mac(self, mac1, mac2): - if mac1 == '' or mac2 == '': - return 0 - mac1_octets = [] - mac1_octets = mac1.split(':') - mac1val = int(mac1_octets[5], 16) | int(mac1_octets[4], 16) << 8 | int(mac1_octets[3], 16) << 16 - mac2_octets = [] - mac2_octets = mac2.split(':') - mac2val = int(mac2_octets[5], 16) | int(mac2_octets[4], 16) << 8 | int(mac2_octets[3], 16) << 16 - # check oui matches - if (mac1_octets[0] != mac2_octets[0] - or mac1_octets[1] != mac2_octets[1] - or mac1_octets[2] != mac2_octets[2]) : - return 0 - - if mac2val < mac1val: - return 0 - - return (mac2val - mac1val) - - def increment_mac(self, mac): - if mac != "": - mac_octets = [] - mac_octets = mac.split(':') - ret_mac = int(mac_octets[5], 16) | int(mac_octets[4], 16) << 8 | int(mac_octets[3], 16) << 16 - ret_mac = ret_mac + 1 - - if (ret_mac & 0xff000000): - print('Error: increment carries into OUI') - return '' - - mac_octets[5] = hex(ret_mac & 0xff)[2:].zfill(2) - mac_octets[4] = hex((ret_mac >> 8) & 0xff)[2:].zfill(2) - mac_octets[3] = hex((ret_mac >> 16) & 0xff)[2:].zfill(2) - - return ':'.join(mac_octets).upper() - - return '' - - @classmethod - def find_field(cls, e, name): - if not hasattr(cls, 'brd_fmt'): - raise RuntimeError("Class %s does not have brb_fmt" % cls) - if not e: - raise RuntimeError("EEPROM can not be empty") - brd_fmt = cls.brd_fmt - loc = 0 - for f in brd_fmt: - end = loc + f[2] - t = e[loc:end] - loc = end - if f[0] == name: - return t - - def base_mac_addr(self, e): - ''' - Returns the base MAC address found in the EEPROM. - - Sub-classes must override this method as reading the EEPROM - and finding the base MAC address entails platform specific - details. - - See also mgmtaddrstr() and switchaddrstr(). - ''' - print("ERROR: Platform did not implement base_mac_addr()") - raise NotImplementedError - - def mgmtaddrstr(self, e): - ''' - Returns the base MAC address to use for the Ethernet - management interface(s) on the CPU complex. - - By default this is the same as the base MAC address listed in - the EEPROM. - - See also switchaddrstr(). - ''' - return self.base_mac_addr(e) - - def switchaddrstr(self, e): - ''' - Returns the base MAC address to use for the switch ASIC - interfaces. - - By default this is *next* address after the base MAC address - listed in the EEPROM. - - See also mgmtaddrstr(). - ''' - return self.increment_mac(self.base_mac_addr(e)) - - def switchaddrrange(self, e): - # this function is in the base class only to catch errors - # the platform specific import should have an override of this method - # to provide the allocated mac range from syseeprom or flash sector or - # wherever that platform stores this info - print("Platform did not indicate allocated mac address range") - raise NotImplementedError - - def serial_number_str(self, e): - raise NotImplementedError("Platform did not indicate serial number") diff --git a/sonic_platform_base/sonic_eeprom/eeprom_dts.py b/sonic_platform_base/sonic_eeprom/eeprom_dts.py deleted file mode 100644 index a47d2f609..000000000 --- a/sonic_platform_base/sonic_eeprom/eeprom_dts.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2012 Cumulus Networks LLC, all rights reserved - -try: - import exceptions # Python 2 -except ImportError: - import builtins as exceptions # Python 3 -try: - import os - import binascii - import subprocess -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -i2c_root = '/sys/class/i2c-adapter/' -mtd_root = '/dev/mtd' -dts_root = '/proc/device-tree/' -sys_dev = '/sys/devices/' - -# -# This routine takes a token list containing the desired eeprom types -# (e.g. 'sfp', 'psu', 'board'), and returns a dict of {[dts path:(dev attrs)]} -# for the corresponding eeproms. For those accessible via i2c, the attrs -# will contain (i2c bus index, i2c device number). For those mounted to -# /dev/mtd, the attrs will be (mtd partition number). -# -def get_dev_attr_from_dtb(tokens): - - dts_paths = [] - i2c_devices = [] - sub_devices = [] - - eep_dict = {} - - # - # first try i2c - # - try: - ph = subprocess.Popen(['/bin/ls', '-R', dts_root], - stdout=subprocess.PIPE, - shell=False, stderr=subprocess.STDOUT) - cmdout = ph.communicate()[0] - ph.wait() - except OSError as e: - raise OSError("cannot access directory") - - lines = cmdout.splitlines() - for I in lines: - if not I.endswith(':') or 'i2c' not in I: - continue - - I = I.rstrip(':\n\r') - last = I.split('/')[-1] - if 'i2c' in last: - depth = I.count('i2c') - while len(sub_devices) < depth: - sub_devices.append([]) - sub_devices[depth-1].append(I) - elif 'eeprom' in last: - dts_paths.append(I) - - # re-order the device heirarchy and build the device list - for i in sub_devices: - for j in i: - i2c_devices.append(j) - - for eep in dts_paths: - instance = '' - if os.path.isfile('/'.join([eep, 'label'])): - F = open('/'.join([eep, 'label']), "rb") - instance = F.read().partition('_eeprom')[0] - F.close() - - # check for read-only - read_only = os.path.isfile('/'.join([eep, 'read-only'])) - - for t in tokens: - if t not in eep and t not in instance: - continue - - # get the i2c idx by matching the path prefix - i2c_idx = i2c_devices.index(eep.rsplit('/', 1)[0]) - - # read the reg - reg_path = '/'.join([eep, 'reg']) - F = open(reg_path, "rb") - o = F.read() - reg = binascii.b2a_hex(o)[-2:] - F.close() - - eep_dict[eep] = {'type': 'i2c', \ - 'dev-id': i2c_idx, \ - 'reg': reg, \ - 'ro': read_only} - break - - - # - # now try flash - # - try: - ph = subprocess.Popen(['/bin/grep', '-r', 'eeprom', dts_root], - stdout=subprocess.PIPE, - shell=False, stderr=subprocess.STDOUT) - cmdout = ph.communicate()[0] - ph.wait() - except OSError as e: - raise OSError("cannot access directory") - - lines = cmdout.splitlines() - for I in lines: - if 'flash' not in I or 'label' not in I: - continue - - eep = I.partition(dts_root)[2].rpartition('label')[0] - full_eep = '/'.join([dts_root, eep]) - F = open('/'.join([full_eep, 'label']), "rb") - instance = F.read().partition('_eeprom')[0] - F.close() - - read_only = os.path.isfile('/'.join([full_eep, 'read-only'])) - - for t in tokens: - if t not in instance: - continue - - mtd_n = eep.partition('partition@')[2].rstrip('/') - eep_dict[full_eep] = {'type': 'mtd', \ - 'dev-id': mtd_n, \ - 'ro': read_only} - - return eep_dict - - -def dev_attr_to_path(dev_attrs): - dev_path = '' - if dev_attrs['type'] == 'i2c': - dev_path = i2c_root + 'i2c-' + str(dev_attrs['dev-id']) + '/' + \ - str(dev_attrs['dev-id']) + '-00' + str(dev_attrs['reg']) + \ - '/' + 'eeprom' - elif dev_attrs['type'] == 'mtd': - dev_path = mtd_root + dev_attrs['dev-id'] - - return dev_path diff --git a/sonic_platform_base/sonic_eeprom/eeprom_tlvinfo.py b/sonic_platform_base/sonic_eeprom/eeprom_tlvinfo.py deleted file mode 100644 index f8dd32807..000000000 --- a/sonic_platform_base/sonic_eeprom/eeprom_tlvinfo.py +++ /dev/null @@ -1,780 +0,0 @@ -# Copyright 2012 Cumulus Networks LLC, all rights reserved - -############################################################################# -# Base eeprom class containing the main logic for reading, writing, and -# setting the eeprom. The format definition is a list of tuples of: -# ('data name', 'data type', 'size in bytes') -# data type is one of 's', 'C', and 'x' (string, char, and ignore) -# 'burn' as a data name indicates the corresponding number of bytes are to -# be ignored - -from __future__ import print_function - -try: - import sys - - import redis - - from . import eeprom_base # Dot module supports both Python 2 and Python 3 using explicit relative import methods -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -STATE_DB_INDEX = 6 - -# -# TlvInfo Format - This eeprom format was defined by Cumulus Networks -# and can be found here: -# -# -class TlvInfoDecoder(eeprom_base.EepromDecoder): - - # Header Field Constants - _TLV_INFO_ID_STRING = b"TlvInfo\x00" - _TLV_INFO_VERSION = 0x01 - _TLV_INFO_HDR_LEN = 11 - _TLV_INFO_MAX_LEN = 2048 - _TLV_TOTAL_LEN_MAX = _TLV_INFO_MAX_LEN - _TLV_INFO_HDR_LEN - _TLV_HDR_ENABLED = 1 - - # The Undefined TLV Type - _TLV_CODE_UNDEFINED = 0xFC - - # Default TLV Types - _TLV_CODE_PRODUCT_NAME = 0x21 - _TLV_CODE_PART_NUMBER = 0x22 - _TLV_CODE_SERIAL_NUMBER = 0x23 - _TLV_CODE_MAC_BASE = 0x24 - _TLV_CODE_MANUF_DATE = 0x25 - _TLV_CODE_DEVICE_VERSION = 0x26 - _TLV_CODE_LABEL_REVISION = 0x27 - _TLV_CODE_PLATFORM_NAME = 0x28 - _TLV_CODE_ONIE_VERSION = 0x29 - _TLV_CODE_MAC_SIZE = 0x2A - _TLV_CODE_MANUF_NAME = 0x2B - _TLV_CODE_MANUF_COUNTRY = 0x2C - _TLV_CODE_VENDOR_NAME = 0x2D - _TLV_CODE_DIAG_VERSION = 0x2E - _TLV_CODE_SERVICE_TAG = 0x2F - _TLV_CODE_VENDOR_EXT = 0xFD - _TLV_CODE_CRC_32 = 0xFE - - # By default disable the Quanta specific codes - _TLV_CODE_QUANTA_MAGIC = _TLV_CODE_UNDEFINED - _TLV_CODE_QUANTA_CRC = _TLV_CODE_UNDEFINED - _TLV_CODE_QUANTA_CARD_TYPE = _TLV_CODE_UNDEFINED - _TLV_CODE_QUANTA_HW_VERSION = _TLV_CODE_UNDEFINED - _TLV_CODE_QUANTA_SW_VERSION = _TLV_CODE_UNDEFINED - _TLV_CODE_QUANTA_MANUF_DATE = _TLV_CODE_UNDEFINED - _TLV_CODE_QUANTA_MODEL_NAME = _TLV_CODE_UNDEFINED - - # TLV Value Display Switch - _TLV_DISPLAY_VENDOR_EXT = True - - - def __init__(self, path, start, status, ro, max_len=_TLV_INFO_MAX_LEN): - super(TlvInfoDecoder, self).__init__(path, \ - None, \ - start, \ - status, \ - ro) - self.eeprom_start = start - self.eeprom_max_len = max_len - self._redis_client = None - - - def __print_db(self, code, num=0): - if not num: - field_name = self._redis_hget('EEPROM_INFO|{}'.format(hex(code)), 'Name') - if not field_name: - pass - else: - field_len = self._redis_hget('EEPROM_INFO|{}'.format(hex(code)), 'Len') - field_value = self._redis_hget('EEPROM_INFO|{}'.format(hex(code)), 'Value') - print("%-20s 0x%02X %3s %s" % (field_name, code, field_len, field_value)) - else: - for index in range(num): - field_name = self._redis_hget('EEPROM_INFO|{}'.format(hex(code)), 'Name_{}'.format(index)) - field_len = self._redis_hget('EEPROM_INFO|{}'.format(hex(code)), 'Len_{}'.format(index)) - field_value = self._redis_hget('EEPROM_INFO|{}'.format(hex(code)), 'Value_{}'.format(index)) - print("%-20s 0x%02X %3s %s" % (field_name, code, field_len, field_value)) - - - def decode_eeprom(self, e): - ''' - Decode and print out the contents of the EEPROM. - ''' - visitor = EepromDecodeVisitor() - self.visit_eeprom(e, visitor) - - - def set_eeprom(self, e, cmd_args): - ''' - Returns the new contents of the EEPROM. If command line arguments are supplied, - then those fields are overwritten or added to the existing EEPROM contents. If - not command line arguments are supplied, the user is prompted for the contents - of the EEPROM. - ''' - new_tlvs = bytearray() - (crc_is_valid, crc) = self.is_checksum_valid(e) - if crc_is_valid: - if self._TLV_HDR_ENABLED: - tlv_index = self._TLV_INFO_HDR_LEN - tlv_end = self._TLV_INFO_HDR_LEN + ((e[9] << 8) | e[10]) - else : - tlv_index = self.eeprom_start - tlv_end = self._TLV_INFO_MAX_LEN - - while tlv_index < len(e) and \ - tlv_index < tlv_end and \ - self.is_valid_tlv(e[tlv_index:]) and \ - e[tlv_index] != self._TLV_CODE_CRC_32 and \ - e[tlv_index] != self._TLV_CODE_QUANTA_CRC: - new_tlvs += e[tlv_index:tlv_index + 2 + e[tlv_index + 1]] - tlv_index += e[tlv_index+1] + 2 - - if len(cmd_args): - for arg_str in cmd_args: - for arg in arg_str.split(','): - k, v = arg.split('=') - k = int(k.strip(), 0) - v = v.strip() - new_tlv = self.encoder((k,), v) - (tlv_found, index) = self.get_tlv_index(new_tlvs, k) - if tlv_found: - new_tlvs = new_tlvs[:index] + new_tlv + \ - new_tlvs[index + 2 + new_tlvs[index + 1]:] - else: - new_tlvs += new_tlv - - else: - action = "a" - while action not in ['f', 'F']: - - action = raw_input("\n[a]dd, [m]odify, [d]elete, [f]inished: ") - if action in ['a', 'A', 'm', 'M']: - code = raw_input("Enter a TLV type code: ") - code = int(code, 0) - value = raw_input("Enter the value: ") - new_tlv = self.encoder((code,), value) - (tlv_found, index) = self.get_tlv_index(new_tlvs, code) - if tlv_found: - new_tlvs = new_tlvs[:index] + new_tlv + \ - new_tlvs[index + 2 + new_tlvs[index + 1]:] - else: - new_tlvs += new_tlv - elif action in ['d', 'D']: - code = raw_input("Enter a TLV type code: ") - code = int(code, 0) - (tlv_found, index) = self.get_tlv_index(new_tlvs, code) - if tlv_found: - new_tlvs = new_tlvs[:index] + \ - new_tlvs[index + 2 + new_tlvs[index + 1]:] - elif action in ['f', 'F']: - pass - else: - print("\nInvalid input, please enter 'a', 'm', 'd', or 'f'\n") - - if self._TLV_HDR_ENABLED: - new_tlvs_len = len(new_tlvs) + 6 - new_e = self._TLV_INFO_ID_STRING + bytearray([self._TLV_INFO_VERSION]) + \ - bytearray([(new_tlvs_len >> 8) & 0xFF]) + \ - bytearray([new_tlvs_len & 0xFF]) + new_tlvs - else: - new_e = new_tlvs - - if self._TLV_CODE_CRC_32 != self._TLV_CODE_UNDEFINED: - new_e = new_e + bytearray([self._TLV_CODE_CRC_32]) + bytearray([4]) - elif self._TLV_CODE_QUANTA_CRC != self._TLV_CODE_UNDEFINED: - new_e = new_e + bytearray([self._TLV_CODE_QUANTA_CRC]) + bytearray([2]) - else: - print("\nFailed to formulate new eeprom\n") - exit - new_e += self.encode_checksum(self.calculate_checksum(new_e)) - self.decode_eeprom(new_e) - if len(new_e) > min(self._TLV_INFO_MAX_LEN, self.eeprom_max_len): - sys.stderr.write("\nERROR: There is not enough room in the EEPROM to save data.\n") - exit(1) - return new_e - - - def is_valid_tlvinfo_header(self, e): - ''' - Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM - data passed in as a bytearray. - 1. Large enough to hold the header - 2. First 8 bytes contain null-terminated ASCII string "TlvInfo" - 3. Version byte is 1 - 4. Total length bytes contain value which is less than or equal - to the allowed maximum (2048-11) - ''' - return len(e) >= self._TLV_INFO_HDR_LEN and \ - e[0:8] == self._TLV_INFO_ID_STRING and \ - e[8] == self._TLV_INFO_VERSION and \ - ((e[9] << 8) | e[10]) <= self._TLV_TOTAL_LEN_MAX - - - def is_valid_tlv(self, e): - ''' - Perform basic sanity checks on a TLV field. The TLV is in the bytearray - provided. - 1. The TLV is at least 2 bytes long - 2. The length byte contains a value which does not cause the value - field to go beyond the length of the string. - ''' - return (len(e) >= 2 and (2 + e[1] <= len(e))) - - - def is_checksum_valid(self, e): - ''' - Validate the checksum in the provided TlvInfo EEPROM data. - ''' - if not self.is_valid_tlvinfo_header(e): - return (False, 0) - - offset = self._TLV_INFO_HDR_LEN + ((e[9] << 8) | e[10]) - if len(e) < offset or \ - e[offset-6] != self._TLV_CODE_CRC_32 or \ - e[offset-5] != 4: - return (False, 0) - - crc = self.calculate_checksum(e[:offset-4]) - tlv_crc = e[offset-4] << 24 | e[offset-3] << 16 | \ - e[offset-2] << 8 | e[offset-1] - if tlv_crc == crc: - return(True, crc) - - return (False, crc) - - - def read_eeprom(self): - ''' - Read the eeprom contents. This is performed in two steps. First - the 11 bytes of the TlvInfo structure (the header) are read and - sanity checked. Then using the total length field in the header, - the rest of the data is read from the EEPROM. - ''' - offset = 0 - if self._TLV_HDR_ENABLED: - h = self.read_eeprom_bytes(self._TLV_INFO_HDR_LEN) - offset = self._TLV_INFO_HDR_LEN - if len(h) != self._TLV_INFO_HDR_LEN: - raise RuntimeError("expected to read %d bytes from %s, " \ - %(self._TLV_INFO_HDR_LEN, self.p) + \ - "but only read %d" %(len(h),)) - if not self.is_valid_tlvinfo_header(h): - return h - sizeof_tlvs = (h[9] << 8) | h[10] - else: - h = "" - sizeof_tlvs = self._TLV_INFO_MAX_LEN - - t = self.read_eeprom_bytes(sizeof_tlvs, offset) - if len(t) != sizeof_tlvs: - raise RuntimeError("expected to read %d bytes from %s, " \ - %(sizeof_tlvs, self.p) + \ - "but only read %d" %(len(t))) - return h + t - - - def read_eeprom_db(self): - ''' - Print out the contents of the EEPROM from database - ''' - db_state = self._redis_hget('EEPROM_INFO|State', 'Initialized') - if db_state != '1': - return -1 - tlv_version = self._redis_hget('EEPROM_INFO|TlvHeader', 'Version') - if tlv_version: - print("TlvInfo Header:") - print(" Id String: %s" % self._redis_hget('EEPROM_INFO|TlvHeader', 'Id String')) - print(" Version: %s" % tlv_version) - print(" Total Length: %s" % self._redis_hget('EEPROM_INFO|TlvHeader', 'Total Length')) - - print("TLV Name Code Len Value") - print("-------------------- ---- --- -----") - - for index in range(self._TLV_CODE_PRODUCT_NAME, self._TLV_CODE_SERVICE_TAG + 1): - self.__print_db(index) - - try: - num_vendor_ext = int(self._redis_hget('EEPROM_INFO|{}'.format(hex(self._TLV_CODE_VENDOR_EXT)), 'Num_vendor_ext')) - except (ValueError, TypeError): - pass - else: - self.__print_db(self._TLV_CODE_VENDOR_EXT, num_vendor_ext) - - self.__print_db(self._TLV_CODE_CRC_32) - - print("") - - is_valid = self._redis_hget('EEPROM_INFO|Checksum', 'Valid') - if is_valid != '1': - print("(*** checksum invalid)") - else: - print("(checksum valid)") - - return 0 - - - def update_eeprom_db(self, e): - ''' - Decode the contents of the EEPROM and update the contents to database - ''' - visitor = EepromRedisVisitor(self) - self.visit_eeprom(e, visitor) - return 0 if visitor.error is None else -1 - - - def get_tlv_field(self, e, code): - ''' - Given an EEPROM bytearray the TLV field for the provided code is - returned. This routine validates the EEPROM data (checksum and - other sanity checks) and then searches for a TLV field with the - supplied type code. A tuple of two items is returned. The first - item is a boolean indicating success and, if True, the second - item is a 3 element list with the type (int), length (int), - and value (bytearray) of the requested TLV. - ''' - (is_valid, valid_crc) = self.is_checksum_valid(e) - if not is_valid: - return (False, None) - if self._TLV_HDR_ENABLED: - tlv_index = self._TLV_INFO_HDR_LEN - tlv_end = ((e[9] << 8) | e[10]) + self._TLV_INFO_HDR_LEN - else: - tlv_index = self.eeprom_start - tlv_end = self._TLV_INFO_MAX_LEN - while tlv_index < len(e) and tlv_index < tlv_end: - if not self.is_valid_tlv(e[tlv_index:]): - return (False, None) - if e[tlv_index] == code: - return (True, [e[tlv_index], e[tlv_index+1], \ - e[tlv_index+2:tlv_index+2+e[tlv_index+1]]]) - tlv_index += e[tlv_index+1] + 2 - return (False, None) - - - def get_tlv_index(self, e, code): - ''' - Given an EEPROM bytearray with just TLV fields (no TlvInfo header) - finds the index of the requested type code. This routine searches - for a TLV field with the supplied type code. A tuple of two items - is returned. The first item is a boolean indicating success and, - if True, the second item is the index in the supplied EEPROM bytearray - of the matching type code. - ''' - tlv_index = 0 - while tlv_index < len(e): - if not self.is_valid_tlv(e[tlv_index:]): - return (False, 0) - if e[tlv_index] == code: - return (True, tlv_index) - tlv_index += e[tlv_index+1] + 2 - return (False, 0) - - - def base_mac_addr(self, e): - ''' - Returns the value field of the MAC #1 Base TLV formatted as a string - of colon-separated hex digits. - ''' - (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_MAC_BASE) - if not is_valid or t[1] != 6: - return super(TlvInfoDecoder, self).switchaddrstr(e) - - return ":".join(["{:02x}".format(T) for T in t[2]]).upper() - - - def switchaddrrange(self, e): - ''' - Returns the value field of the MAC #1 Size TLV formatted as a decimal - string - ''' - (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_MAC_SIZE) - if not is_valid: - return super(TlvInfoDecoder, self).switchaddrrange(e) - - return str((t[2][0] << 8) | t[2][1]) - - - def modelstr(self, e): - ''' - Returns the value field of the Product Name TLV as a string - ''' - (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_PRODUCT_NAME) - if not is_valid: - return super(TlvInfoDecoder, self).modelstr(e) - - return t[2].decode("ascii") - - - def serial_number_str(self, e): - ''' - Returns the value field of the Serial Number TLV as a string - ''' - valid, t = self.get_tlv_field(e, self._TLV_CODE_SERIAL_NUMBER) - if not valid: - return super(TlvInfoDecoder, self).serial_number_str(e) - return t[2].decode("ascii") - - - def part_number_str(self, e): - ''' - Returns the value field of the Part Number TLV as a string - ''' - valid, t = self.get_tlv_field(e, self._TLV_CODE_PART_NUMBER) - if not valid: - return super(TlvInfoDecoder, self).part_number_str(e) - return t[2].decode("ascii") - - - def decoder(self, s, t): - ''' - Return a string representing the contents of the TLV field. The format of - the string is: - 1. The name of the field left justified in 20 characters - 2. The type code in hex right justified in 5 characters - 3. The length in decimal right justified in 4 characters - 4. The value, left justified in however many characters it takes - The vailidity of EEPROM contents and the TLV field has been verified - prior to calling this function. The 's' parameter is unused - ''' - if t[0] == self._TLV_CODE_PRODUCT_NAME: - name = "Product Name" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_PART_NUMBER: - name = "Part Number" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_SERIAL_NUMBER: - name = "Serial Number" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_MAC_BASE: - name = "Base MAC Address" - value = ":".join(["{:02x}".format(T) for T in t[2:8]]).upper() - elif t[0] == self._TLV_CODE_MANUF_DATE: - name = "Manufacture Date" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_DEVICE_VERSION: - name = "Device Version" - value = str(t[2]) - elif t[0] == self._TLV_CODE_LABEL_REVISION: - name = "Label Revision" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_PLATFORM_NAME: - name = "Platform Name" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_ONIE_VERSION: - name = "ONIE Version" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_MAC_SIZE: - name = "MAC Addresses" - value = str((t[2] << 8) | t[3]) - elif t[0] == self._TLV_CODE_MANUF_NAME: - name = "Manufacturer" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_MANUF_COUNTRY: - name = "Manufacture Country" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_VENDOR_NAME: - name = "Vendor Name" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_DIAG_VERSION: - name = "Diag Version" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_SERVICE_TAG: - name = "Service Tag" - value = t[2:2 + t[1]].decode("ascii") - elif t[0] == self._TLV_CODE_VENDOR_EXT: - name = "Vendor Extension" - value = "" - if self._TLV_DISPLAY_VENDOR_EXT: - for c in t[2:2 + t[1]]: - value += "0x%02X " % c - value = value.rstrip() - elif t[0] == self._TLV_CODE_CRC_32 and len(t) == 6: - name = "CRC-32" - value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) - # Quanta specific codes below here. - # These decodes are lifted from their U-Boot codes - elif t[0] == self._TLV_CODE_QUANTA_MAGIC and len(t) == 3: - name = "Magic Number" - value = "0x%02X" % t[2] - elif t[0] == self._TLV_CODE_QUANTA_CRC and len(t) == 4: - name = "QUANTA-CRC" - value = "0x%04X" % ((t[2] << 8) + t[3]) - elif t[0] == self._TLV_CODE_QUANTA_CARD_TYPE and len(t) == 6: - name = "Card Type" - value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) - elif t[0] == self._TLV_CODE_QUANTA_HW_VERSION and len(t) == 6: - name = "Hardware Version" - value = "%d.%d" % (t[2], t[3]) - elif t[0] == self._TLV_CODE_QUANTA_SW_VERSION and len(t) == 6: - name = "Software Version" - value = "%d.%d.%d.%d" % ((t[2] >> 4), (t[2] & 0xF), (t[3] >> 4), (t[3] & 0xF)) - elif t[0] == self._TLV_CODE_QUANTA_MANUF_DATE and len(t) == 6: - name = "Manufacture Date" - value = "%04d/%d/%d" % (((t[2] << 8) | t[3]), t[4], t[5]) - elif t[0] == self._TLV_CODE_QUANTA_MODEL_NAME: - name = "Model Name" - value = t[2:2 + t[1]].decode("ascii") - else: - name = "Unknown" - value = "" - for c in t[2:2 + t[1]]: - value += "0x%02X " % c - value = value.replace('\x00', '') - return name, value - - - def encoder(self, I, v): - ''' - Validate and encode the string 'v' into the TLV specified by 'I'. - I[0] is the TLV code. - ''' - try: - if I[0] == self._TLV_CODE_PRODUCT_NAME or \ - I[0] == self._TLV_CODE_PART_NUMBER or \ - I[0] == self._TLV_CODE_SERIAL_NUMBER or \ - I[0] == self._TLV_CODE_LABEL_REVISION or \ - I[0] == self._TLV_CODE_PLATFORM_NAME or \ - I[0] == self._TLV_CODE_ONIE_VERSION or \ - I[0] == self._TLV_CODE_MANUF_NAME or \ - I[0] == self._TLV_CODE_VENDOR_NAME or \ - I[0] == self._TLV_CODE_DIAG_VERSION or \ - I[0] == self._TLV_CODE_SERVICE_TAG: - errstr = "A string less than 256 characters" - if len(v) > 255: - raise - value = v.encode("ascii", "replace") - elif I[0] == self._TLV_CODE_DEVICE_VERSION: - errstr = "A number between 0 and 255" - num = int(v, 0) - if num < 0 or num > 255: - raise - value = bytearray([num]) - elif I[0] == self._TLV_CODE_MAC_SIZE: - errstr = "A number between 0 and 65535" - num = int(v, 0) - if num < 0 or num > 65535: - raise - value = bytearray([(num >> 8) & 0xFF, num & 0xFF]) - elif I[0] == self._TLV_CODE_MANUF_DATE: - errstr = 'MM/DD/YYYY HH:MM:SS' - date, time = v.split() - mo, da, yr = [int(i) for i in date.split('/')] - hr, mn, sc = [int(i) for i in time.split(':')] - if len(v) < 19 or \ - mo < 1 or mo > 12 or da < 1 or da > 31 or yr < 0 or yr > 9999 or \ - hr < 0 or hr > 23 or mn < 0 or mn > 59 or sc < 0 or sc > 59: - raise - value = v.encode("ascii", "replace") - elif I[0] == self._TLV_CODE_MAC_BASE: - errstr = 'XX:XX:XX:XX:XX:XX' - mac_digits = v.split(':') - if len(mac_digits) != 6: - raise - value = bytearray() - for c in mac_digits: - value += bytearray([int(c, 16)]) - elif I[0] == self._TLV_CODE_MANUF_COUNTRY: - errstr = 'CC, a two character ISO 3166-1 alpha-2 country code' - if len(v) < 2: - raise - value = v.encode("ascii", "replace") - elif I[0] == self._TLV_CODE_CRC_32: - value = bytearray() - # Disallow setting any Quanta specific codes - elif I[0] == self._TLV_CODE_QUANTA_MAGIC or \ - I[0] == self._TLV_CODE_QUANTA_CARD_TYPE or \ - I[0] == self._TLV_CODE_QUANTA_HW_VERSION or \ - I[0] == self._TLV_CODE_QUANTA_SW_VERSION or \ - I[0] == self._TLV_CODE_QUANTA_MANUF_DATE or \ - I[0] == self._TLV_CODE_QUANTA_MODEL_NAME: - raise Exception('quanta-read-only') - else: - errstr = '0xXX ... A list of space-separated hexidecimal numbers' - value = bytearray() - for c in v.split(): - value += bytearray([int(c, 0)]) - except Exception as inst: - if (len(inst.args) > 0) and (inst.args[0] == 'quanta-read-only'): - sys.stderr.write("Error: '" + "0x%02X" % (I[0],) + "' -- Unable to set the read-only Quanta codes.\n") - else: - sys.stderr.write("Error: '" + "0x%02X" % (I[0],) + "' correct format is " + errstr + "\n") - exit(0) - - return bytearray([I[0]]) + bytearray([len(value)]) + value - - - def is_checksum_field(self, I): - return False - - - def checksum_field_size(self): - return 4 - - - def checksum_type(self): - return 'crc32' - - @property - def redis_client(self): - """Handy property to get a redis client. Make sure only create the redis client once. - - Returns: - A redis client instance - """ - if not self._redis_client: - self._redis_client = redis.Redis(db=STATE_DB_INDEX) - return self._redis_client - - def _redis_hget(self, key, field): - value = self.redis_client.hget(key, field) - if value is not None: - value = value.decode().rstrip('\0') - return value - - def visit_eeprom(self, e, visitor): - """Visit the content of EEPROM data. - - Args: - e: the EEPROM data - visitor: A instance of EEPROM vistor, see an example at EepromDefaultVisitor - """ - if self._TLV_HDR_ENABLED : - if not self.is_valid_tlvinfo_header(e): - visitor.set_error('EEPROM does not contain data in a valid TlvInfo format.') - return - - total_len = (e[9] << 8) | e[10] - tlv_index = self._TLV_INFO_HDR_LEN - tlv_end = self._TLV_INFO_HDR_LEN + total_len - visitor.visit_header(e[0:7].decode("ascii"), int(e[8]), total_len) - else : - tlv_index = self.eeprom_start - tlv_end = self._TLV_INFO_MAX_LEN - visitor.visit_header(None, None, None) - - while (tlv_index + 2) < len(e) and tlv_index < tlv_end: - if not self.is_valid_tlv(e[tlv_index:]): - visitor.set_error('Invalid TLV field starting at EEPROM offset %d' % tlv_index) - break - tlv = e[tlv_index:tlv_index + 2 + e[tlv_index + 1]] - name, value = self.decoder(None, tlv) - visitor.visit_tlv(name, tlv[0], tlv[1], value) - - if e[tlv_index] == self._TLV_CODE_QUANTA_CRC or \ - e[tlv_index] == self._TLV_CODE_CRC_32: - break - tlv_index += e[tlv_index+1] + 2 - visitor.visit_end(e) - - -class EepromDefaultVisitor: - def visit_header(self, eeprom_id, version, header_length): - """Visit EEPROM header. If EEPROM header is not present, this method is still called, - but the input arguments will all be None. - - Args: - eeprom_id (str): EEPROM ID - version (int): EEPROM version - header_length (int): EEPROM header length - """ - pass - - def visit_tlv(self, name, code, length, value): - """Visit a TLV - - Args: - name (str): name of the TLV - code (int): code of the TLV - length (int): value length of the TLV - value (str): TLV value - """ - pass - - def visit_end(self, eeprom_data): - """The method will be called when visit EEPROM data finish - - Args: - eeprom_data: EEPROM data - """ - pass - - def set_error(self, error): - """Set error when visiting EEPROM data - - Args: - error (str): error message - """ - pass - - -class EepromDecodeVisitor(EepromDefaultVisitor): - def visit_header(self, eeprom_id, version, header_length): - if eeprom_id is not None: - print("TlvInfo Header:") - print(" Id String: %s" % eeprom_id) - print(" Version: %d" % version) - print(" Total Length: %d" % header_length) - print("TLV Name Code Len Value") - print("-------------------- ---- --- -----") - - def visit_tlv(self, name, code, length, value): - print("%-20s 0x%02X %3d %s" % (name, code, length, value)) - - def set_error(self, error): - print(error) - - -class EepromRedisVisitor(EepromDefaultVisitor): - def __init__(self, eeprom_object): - self.eeprom_object = eeprom_object - self.redis_client = eeprom_object.redis_client - self.vendor_ext_tlv_num = 0 - self.fvs = {} - self.error = None - - def visit_header(self, eeprom_id, version, header_length): - if eeprom_id is not None: - self.fvs['Id String'] = eeprom_id - self.fvs['Version'] = version - self.fvs['Total Length'] = header_length - self.redis_client.hmset("EEPROM_INFO|TlvHeader", self.fvs) - self.fvs.clear() - - def visit_tlv(self, name, code, length, value): - if code == self.eeprom_object._TLV_CODE_VENDOR_EXT: - vendor_index = str(self.vendor_ext_tlv_num) - self.fvs['Name_{}'.format(vendor_index)] = name - self.fvs['Len_{}'.format(vendor_index)] = length - self.fvs['Value_{}'.format(vendor_index)] = value - self.vendor_ext_tlv_num += 1 - else: - self.fvs['Name'] = name - self.fvs['Len'] = length - self.fvs['Value'] = value - self.redis_client.hmset('EEPROM_INFO|{}'.format(hex(code)), self.fvs) - self.fvs.clear() - - def visit_end(self, eeprom_data): - if self.vendor_ext_tlv_num > 0: - self.fvs['Num_vendor_ext'] = str(self.vendor_ext_tlv_num) - self.redis_client.hmset('EEPROM_INFO|{}'.format(hex(self.eeprom_object._TLV_CODE_VENDOR_EXT)), self.fvs) - self.fvs.clear() - - (is_valid, _) = self.eeprom_object.is_checksum_valid(eeprom_data) - if is_valid: - self.fvs['Valid'] = '1' - else: - self.fvs['Valid'] = '0' - - self.redis_client.hmset('EEPROM_INFO|Checksum', self.fvs) - self.fvs.clear() - - self.fvs['Initialized'] = '1' - self.redis_client.hmset('EEPROM_INFO|State', self.fvs) - - def set_error(self, error): - self.error = error - print(error) diff --git a/sonic_platform_base/sonic_pcie/__init__.py b/sonic_platform_base/sonic_pcie/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_pcie/pcie_base.py b/sonic_platform_base/sonic_pcie/pcie_base.py deleted file mode 100644 index 3155401ff..000000000 --- a/sonic_platform_base/sonic_pcie/pcie_base.py +++ /dev/null @@ -1,65 +0,0 @@ -# -# pcie_base.py -# -# Abstract base class for implementing platform-specific -# PCIE functionality for SONiC -# - -try: - import abc -except ImportError as e: - raise ImportError(str(e) + " - required module not found") - - -class PcieBase(object): - def __init__(self, path): - """ - Constructor - - Args: - pcieutil file and config file path - """ - - @abc.abstractmethod - def get_pcie_device(self): - """ - get current device pcie info - - Returns: - A list including pcie device info - """ - return [] - - @abc.abstractmethod - def get_pcie_check(self): - """ - Check Pcie device with config file - - Returns: - A list including pcie device and test result info - """ - return [] - - @abc.abstractmethod - def get_pcie_aer_stats(self, domain, bus, dev, fn): - """ - Returns a nested dictionary containing the AER stats belonging to a - PCIe device - - Args: - domain, bus, dev, fn: Domain, bus, device, function of the PCIe - device respectively - - Returns: - A nested dictionary where key is severity 'correctable', 'fatal' or - 'non_fatal', value is a dictionary of key, value pairs in the format: - {'AER Error type': Error count} - - Ex. {'correctable': {'BadDLLP': 0, 'BadTLP': 0}, - 'fatal': {'RxOF': 0, 'MalfTLP': 0}, - 'non_fatal': {'RxOF': 0, 'MalfTLP': 0}} - - For PCIe devices that do not support AER, the value for each - severity key is an empty dictionary. - """ - return {} diff --git a/sonic_platform_base/sonic_pcie/pcie_common.py b/sonic_platform_base/sonic_pcie/pcie_common.py deleted file mode 100644 index 127c614cd..000000000 --- a/sonic_platform_base/sonic_pcie/pcie_common.py +++ /dev/null @@ -1,146 +0,0 @@ -# pcie_common.py -# Common PCIE check interfaces for SONIC -# - -import os -import yaml -import subprocess -import re -import sys -from copy import deepcopy -try: - from .pcie_base import PcieBase -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - - -class PcieUtil(PcieBase): - """Platform-specific PCIEutil class""" - # got the config file path - def __init__(self, path): - self.config_path = path - self._conf_rev = None - - # load the config file - def load_config_file(self): - conf_rev = "_{}".format(self._conf_rev) if self._conf_rev else "" - config_file = "{}/pcie{}.yaml".format(self.config_path, conf_rev) - try: - with open(config_file) as conf_file: - self.confInfo = yaml.safe_load(conf_file) - except IOError as e: - print("Error: {}".format(str(e))) - print("Not found config file, please add a config file manually, or generate it by running [pcieutil pcie_generate]") - sys.exit() - - # load current PCIe device - def get_pcie_device(self): - pciDict = {} - pciList = [] - p1 = "^(\w+):(\w+)\.(\w)\s(.*)\s*\(*.*\)*" - p2 = "^.*:.*:.*:(\w+)\s*\(*.*\)*" - command1 = ["sudo", "lspci"] - command2 = ["sudo", "lspci", "-n"] - # run command 1 - proc1 = subprocess.Popen(command1, universal_newlines=True, stdout=subprocess.PIPE) - output1 = proc1.stdout.readlines() - (out, err) = proc1.communicate() - # run command 2 - proc2 = subprocess.Popen(command2, universal_newlines=True, stdout=subprocess.PIPE) - output2 = proc2.stdout.readlines() - (out, err) = proc2.communicate() - - if proc1.returncode > 0: - for line1 in output1: - print(line1.strip()) - return - elif proc2.returncode > 0: - for line2 in output2: - print(line2.strip()) - return - else: - for (line1, line2) in zip(output1, output2): - pciDict.clear() - match1 = re.search(p1, line1.strip()) - match2 = re.search(p2, line2.strip()) - if match1 and match2: - Bus = match1.group(1) - Dev = match1.group(2) - Fn = match1.group(3) - Name = match1.group(4) - Id = match2.group(1) - pciDict["name"] = Name - pciDict["bus"] = Bus - pciDict["dev"] = Dev - pciDict["fn"] = Fn - pciDict["id"] = Id - pciList.append(pciDict) - pciDict = deepcopy(pciDict) - else: - print("CAN NOT MATCH PCIe DEVICE") - return pciList - - # check the sysfs tree for each PCIe device - def check_pcie_sysfs(self, domain=0, bus=0, device=0, func=0): - dev_path = os.path.join('/sys/bus/pci/devices', '%04x:%02x:%02x.%d' % (domain, bus, device, func)) - if os.path.exists(dev_path): - return True - return False - - # check the current PCIe device with config file and return the result - def get_pcie_check(self): - self.load_config_file() - for item_conf in self.confInfo: - bus_conf = item_conf["bus"] - dev_conf = item_conf["dev"] - fn_conf = item_conf["fn"] - if self.check_pcie_sysfs(bus=int(bus_conf, base=16), device=int(dev_conf, base=16), func=int(fn_conf, base=16)): - item_conf["result"] = "Passed" - else: - item_conf["result"] = "Failed" - return self.confInfo - - # return AER stats of PCIe device - def get_pcie_aer_stats(self, domain=0, bus=0, dev=0, func=0): - aer_stats = {'correctable': {}, 'fatal': {}, 'non_fatal': {}} - dev_path = os.path.join('/sys/bus/pci/devices', '%04x:%02x:%02x.%d' % (domain, bus, dev, func)) - - # construct AER sysfs filepath - correctable_path = os.path.join(dev_path, "aer_dev_correctable") - fatal_path = os.path.join(dev_path, "aer_dev_fatal") - non_fatal_path = os.path.join(dev_path, "aer_dev_nonfatal") - - # update AER-correctable fields - if os.path.isfile(correctable_path): - with open(correctable_path, 'r') as fh: - lines = fh.readlines() - for line in lines: - correctable_field, value = line.split() - aer_stats['correctable'][correctable_field] = value - - # update AER-Fatal fields - if os.path.isfile(fatal_path): - with open(fatal_path, 'r') as fh: - lines = fh.readlines() - for line in lines: - fatal_field, value = line.split() - aer_stats['fatal'][fatal_field] = value - - # update AER-Non Fatal fields - if os.path.isfile(non_fatal_path): - with open(non_fatal_path, 'r') as fh: - lines = fh.readlines() - for line in lines: - non_fatal_field, value = line.split() - aer_stats['non_fatal'][non_fatal_field] = value - - return aer_stats - - # generate the config file with current pci device - def dump_conf_yaml(self): - curInfo = self.get_pcie_device() - conf_rev = "_{}".format(self._conf_rev) if self._conf_rev else "" - config_file = "{}/pcie{}.yaml".format(self.config_path, conf_rev) - with open(config_file, "w") as conf_file: - yaml.dump(curInfo, conf_file, default_flow_style=False) - return diff --git a/sonic_platform_base/sonic_sfp/__init__.py b/sonic_platform_base/sonic_sfp/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_sfp/bcmshell.py b/sonic_platform_base/sonic_sfp/bcmshell.py deleted file mode 100644 index 99e8082f3..000000000 --- a/sonic_platform_base/sonic_sfp/bcmshell.py +++ /dev/null @@ -1,501 +0,0 @@ -#------------------------------------------------------------------------------- -# -# Copyright 2012 Cumulus Networks, inc all rights reserved -# -#------------------------------------------------------------------------------- -# - -from __future__ import print_function - -try: - import sys - import os - import time - import socket - import re -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -#------------------------------------------------------------------------------- -# - -class bcmshell (object): - - """Simple expect like class that connects to a BCM diag shell, exported as a - socket fd by switchd, allowing users to run commands and extract delimited - output. bcmdiag opens the socket file, flushes the socket's read side and - issues commands via bcmdiag.run(). The command output, upto the diag shell - prompt, is read from the socket and returned to the caller.""" - - version = "1.0" - - #--------------- - # - def __init__(self, keepopen=False, timeout=10, opennow=False, logfileobj=None, - socketname="/var/run/docker-syncd/sswsyncd.socket", prompt='^drivshell>\s*$'): - """Constructor: - - keepopen - indicates that switchd socket should be kept open between - uses because the invoking application has a bunch of consecutive - activity. In this use case, the socket must be explicitly closed by - bcmshell.close() to allow multiplexing of multiple applications. - - timeout - the time, in seconds, that bcmshell.run() will sit on the - domain socket wait for read input. Note that as long as the socket is - handing us data, we'll keep reading for up seconds. - - logfileobj - a file object that should log all issued commands. None - disables command logging; sys.stdout logs every command to stdout. - logfileobj is flushed after every write. - - socketname - the name of the switchd socket file. - - prompt - the diag shell prompt that delimits the end of output""" - - if type(prompt) is not str: - raise SyntaxError("bcmshell constructor prompt expects an re string") - else: - self.re_prompt = re.compile(prompt, re.MULTILINE) - self.re_connectprompt = re.compile("bcmshell\r\n\s*" + prompt, re.MULTILINE) - - if timeout <= 0: - raise ValueError("bcmshell.timeout must be > 0") - else: - self.timeout = timeout - if timeout > 180: - sys.stderr.write("warning: bcmshell.timeout, %s, is > 180s\n" % - str(self.timeout)) - - if not os.access(socketname, os.F_OK): - raise ValueError("socket %s does not exist" % socketname) - elif not os.access(socketname, os.R_OK | os.W_OK): - raise ValueError("missing read/write permissions for %s" % socketname) - else: - self.socketname = socketname - - if logfileobj is None: - self.logfileobj = None - elif type(logfileobj) is not file: - raise TypeError("bcmshell.logfileobj must be a file object not %s" % - type(logfileobj)) - elif 'w' not in logfileobj.mode: - raise TypeError("bcmshell.logfileobj is not a writeable file object") - else: - self.logfileobj = logfileobj - - self.keepopen = keepopen - self.socketobj = None - self.buffer = '' - - # text editing tools - # - self.re_oneline = re.compile('\n\s+') - self.re_reg_parse_raw = re.compile('^[\w()]+\.(.+)\[.*=(.*)$') - self.re_reg_parse_fields = re.compile('^[\w()]+\.(.+)\[.*\<(.*)\>') - self.re_get_field = re.compile('^(.+)=(.+)') - self.re_table_header = re.compile('^.*:[ <]+', re.MULTILINE) - self.re_table_trailer = re.compile('[ >]+$', re.MULTILINE) - self.re_conv = re.compile(r'(\d+|\D+)') - - # interface name conversion - # - self.modname = dict() - for I in range(0, 63): - self.modname['xe' + str(I)] = 'swp' + str(I) - - # open socket if required - # - if opennow and keepopen: - self.__open__() - - #--------------- - # - def __del__(self): - - """Destructor: flush and close all files that we opened""" - - try: - self.close() - except Exception: - pass - - #--------------- - # - def __str__(self): - - """Return object state in human-readable form""" - - s = [] - s.append(repr(self)) - s.append('version: ' + self.version) - s.append('keepopen: ' + str(self.keepopen)) - s.append('timeout: ' + str(self.timeout) + ' seconds') - s.append('logfileobj: ' + str(self.logfileobj)) - s.append('socketname: ' + str(self.socketname)) - s.append('socketobj: ' + str(self.socketobj)) - s.append('prompt: \"' + str(self.re_prompt.pattern) + '\"') - s.append('buffer (last 100 chars): ' + str(self.buffer)[-100:]) - return '\n'.join(s) - - #--------------- - # - def getreg(self, reg, fields=False): - - """Get device register(s) by name. - - The general format in which registers are returned from the shell is - reg_name(N).M=V for raw values and reg_name(N).M= where N - is an array index, M is a module or port name, V is a value, and F is a - field name. Register/field values are all converted to unsigned - integers. There is a built in name converstion fucntion to change - Broadcom "xe*" port names to "swp*" names that match the kernel. - - bcmshell.getreg('reg_name') returns dict of lists of values. As an - optimization, if there is only one entry in the dict, only the list of - values is returned and if there is only one entry in each list, only the - values are returned - - Examples: - bcmshell.getreg('cmic_config') returns a value... - 1057759299. - - bcmshell.getreg('protocol_pkt_control') returns a list of values... - [0, 0, 0, ..., 0] - - bcmshell.getreg('egr_mtu') returns a dict of values.... - {'cpu0': 0x3fff, - 'xe0': 0x3fff, - ... - 'lb0': 0x3fff} - - bcmshell.getreg('pg_min_cell') returns a dict of lists of values.... - {'cpu0:'[0, 0, 0, 0, 0, 0, 0, 0], - 'xe0': [0, 0, 0, 0, 0, 0, 0, 0], - ... - 'lb0': [0, 0, 0, 0, 0, 0, 0, 0]} - - - bcmshell.getreg('reg_name', True) returns dict of lists of dicts of - field/values. The same optimizations used for raw values apply. - - Examples: - bcmshell.getreg('cmic_config', True) returns a dict of field/values... - {'IGNORE_MMU_BKP_TXDMA_PKT': 0, - 'EN_SER_INTERLEAVE_PARITY': 1, - 'MIIM_ADDR_MAP_ENABLE': 1, - 'IGNORE_MMU_BKP_REMOTE_PKT': 0, - ... - 'DMA_GARBAGE_COLLECT_EN': 0} - - bcmshell.getreg('protocol_pkt_control', True) returns - [{'SRP_PKT_TO_CPU':0, 'SRP_FWD_ACTION':0,... 'ARP_REPLY_DROP':0}, - {'SRP_PKT_TO_CPU':0, 'SRP_FWD_ACTION':0,... 'ARP_REPLY_DROP':0}, - ... - {'SRP_PKT_TO_CPU':0, 'SRP_FWD_ACTION':0,... 'ARP_REPLY_DROP':0}] - - bcmshell.getreg('egr_mtu', fields=True) returns a dict of dicts... - {'cpu0': {'MTU_SIZE',0x3fff, 'MTU_ENABLE',0}, - 'xe0': {'MTU_SIZE',0x3fff, 'MTU_ENABLE',0}, - ... - 'lb0': {'MTU_SIZE',0x3fff, 'MTU_ENABLE',0}} - - bcmshell.getreg('pg_min_cell') returns a dict of lists of values.... - {'cpu0:'[{'PG_MIN':0}, {'PG_MIN':0},... {'PG_MIN':0}], - 'xe0:'[{'PG_MIN':0}, {'PG_MIN':0},... {'PG_MIN':0}], - ... - 'lb0:'[{'PG_MIN':0}, {'PG_MIN':0},... {'PG_MIN':0}]} - """ - - # make sure everything is sane and read the register - # - if type(reg) is not str: - raise TypeError("expecting string argument to bmcdiag.getreg(reg)") - elif reg.find('\n') >= 0: - raise ValueError("unexpected newline in bmcdiag.getreg(%s)" % reg ) - elif reg.find('\s') >= 0: - raise ValueError("unexpected whitespace in bmcdiag.getreg(%s)" % reg) - - if fields: - t = self.run('getreg ' + reg) - else: - t = self.run('getreg raw ' + reg) - - if 'Syntax error parsing' in t: - raise RuntimeError('\"%s\" is not a register' % reg) - - # get the results into a list - # - t = self.re_oneline.sub('', t) - t = t.split('\n') - if t[-1] == '': - t.pop() - - # get the results into a dict (module) of lists (array) of values/fields - # - def __parse_reg__(text, fields=False): - if fields: - m = self.re_reg_parse_fields.search(text) - s = m.group(2).split(',') - t = dict([self.__get_field__(S) for S in s]) - else: - m = self.re_reg_parse_raw.search(text) - t = int(m.group(2), 16) - return(self.modname.get(m.group(1), m.group(1)), t) - - t = [__parse_reg__(T, fields) for T in t] - d = dict() - for I in t: - if I[0] in d: - d[I[0]].append(I[1]) - else: - d[I[0]] = [I[1]] - - # now optimize the return - # - for I in iter(d): - if len(d[I]) == 1: - d[I] = d[I][0] - - if len(d) == 1: - return d.values()[0] - else: - return d - - - #--------------- - # - def gettable(self, table, fields=False, start=None, entries=None): - - """Get device memory based table(s) by name. Tables are returned as a - list of value/field-dict. Table entry/field values are converted into - unsigned integers. If "fields" is set to True, we return a list of - dictionaries of field/value. - - Examples: - bcmshell.gettable('egr_ing_port') returns - [0, 0, 0, ... 0] - - bcmshell.gettable('egr_ing_port', True) returns - [{'HIGIG2': 0, 'PORT_TYPE': 0}, - {'HIGIG2': 0, 'PORT_TYPE': 0}, - {'HIGIG2': 0, 'PORT_TYPE': 0}, - ... - {'HIGIG2': 0, 'PORT_TYPE': 0}] - """ - - if type(table) is not str: - raise TypeError("bcmshell.gettable(table) expects string not %s" % - type(table)) - elif table.find('\n') >= 0: - raise ValueError("unexpected newline in bmcshell.gettable(%s)" % - table ) - elif table.find('\s') >= 0: - raise ValueError("unexpected whitespace in bmcshell.gettable(%s)" % - table) - - cmd = 'dump all' - if not fields: - cmd += ' raw' - cmd += " %s" % table - if start != None or entries != None: - cmd += " %d" % (start or 0) - cmd += " %d" % (entries or 1) - - t = self.run(cmd) - - if 'Unknown option or memory' in t: - raise RuntimeError('\"%s\" is not a table' % table) - - if 'out of range' in t: - err = table - if start != None or entries != None: - err += " %d" % (start or 0) - err += " %d" % (entries or 1) - raise IndexError('\"%s\" table index is out of range' % err) - - # get all of the return into a list - # - t = self.re_oneline.sub('', t) - t = self.re_table_header.sub('', t) - t = self.re_table_trailer.sub('', t) - t = t.split('\n') - if t[-1] == '': - t.pop() - - # parse the contents - # - def __parse_table__(text, fields=False): - if fields: - t = text.split(',') - v = [self.__get_field__(T) for T in t] - return dict(v) - else: - t = text.split() - v = 0 - for I in range(len(t)): - v += (int(t[I], 16) << (32 * I)) - return v - t = [__parse_table__(T, fields) for T in t] - - return t - - #--------------- - # - def cmd(self, cmd): - - """Run a command and print the results""" - - s = self.run(cmd) - if 'Unknown command:' in s: - raise ValueError(s) - print(s) - - - #--------------- - # - def prettyprint(self, d, level=0): - - """Print the structured output generated by getreg and gettable in a - human readable format""" - - s = level * 8 * " " - if type(d) is dict: - for I in sorted(d, key=self.__name_conv__): - if type(d[I]) is int: - print("%s %30s: " % (s, I), end=" ") - else: - print("%s %s:" % (s, I)) - self.prettyprint(d[I], (level + 1)) - elif type(d) is list: - for I in range(len(d)): - i = "[" + str(I) + "]" - if type(d[I]) is int or type(d[I]) is long: - print("%s %10s: " % (s, i), end=" ") - else: - print("%s %s:" % (s, i)) - self.prettyprint(d[I], (level + 1)) - else: - print("%s" % (hex(d))) - - - #--------------- - # - def close(self): - - """Close the socket object""" - - if self.socketobj is not None: - self.socketobj.shutdown(socket.SHUT_RDWR) - self.socketobj.close() - self.socketobj = None - - #--------------- - # - def run(self, cmd): - - """Issue the command to the diag shell and collect the return data until - we detect the prompt. cmd must be a string and must not include a - newline, i.e. we expect a single command to be run per call.""" - - if type(cmd) is not str: - raise TypeError("expecting string argument to bmcdiag.run(cmd)") - elif cmd.find('\n') >= 0: - raise ValueError("unexpected newline in bmcdiag.run(cmd)") - - self.__open__() - try: - self.socketobj.sendall(cmd + '\n') - except socket.error as err: - (errno, errstr) = err.args - raise IOError("unable to send command \"%s\", %s" % (cmd, errstr)) - - self.buffer = '' - self.socketobj.settimeout(self.timeout) - quitting_time = time.time() + self.timeout - while True: - try: - self.buffer += self.socketobj.recv(4096) - except socket.timeout: - raise RuntimeError("recv stalled for %d seconds" % self.timeout) - found = self.re_prompt.search(self.buffer) - if found: - break - if time.time() > quitting_time: - raise RuntimeError("accepting input for %d seconds" % self.timeout) - - if found.end(0) != len(self.buffer): - raise RuntimeError("prompt detected in the middle of input") - - if not self.keepopen: - self.close() - return self.buffer[:found.start(0)] - - #--------------- - # - def __name_conv__(self, s): - l = self.re_conv.findall(s) - for I in range(len(l)): - if l[I].isdigit(): - l[I] = int(l[I]) - return l - - #--------------- - # - def __get_field__(self, text): - m = self.re_get_field.search(text) - return (m.group(1), int(m.group(2), 16)) - - #--------------- - # - def __open__(self): - - """Open the bcm diag shell socket exported by switchd. Complete any - dangling input by issuing a newline and flush the read side in case the - last user left something lying around. No-op if the socket is already - open. NOTE: socket.connect is non-blocking, so we need to exchange - a command with the bcm diag shell to know that we've actually obtained - socket ownership.""" - - if self.socketobj is None: - timeout = self.timeout - while True: - try: - self.socketobj = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.socketobj.settimeout(self.timeout) - self.socketobj.connect(self.socketname) - except socket.error as err: - (errno, errstr) = err.args - if timeout == 0: - raise IOError("unable to open %s, %s" % (self.socketname, errstr)) - time.sleep(1) - timeout -= 1 - else: - break; - - - # flush out the socket in case it was left dirty - try: - self.socketobj.sendall('echo bcmshell\n') - quitting_time = time.time() + self.timeout - buf = '' - while True: - try: - buf += self.socketobj.recv(1024) - except socket.timeout: - raise IOError("unable to receive data from %s for %d seconds" % - (self.socketname, self.timeout)) - - found = self.re_connectprompt.search(buf) - if found: - break - if time.time() > quitting_time: - raise IOError("unable to flush %s for %d seconds" % - (self.socketname, self.timeout)) - - except socket.error as err: - (errno, errstr) = err.args - raise IOError("Socket error: unable to flush %s on open: %s" % (self.socketname, errstr)) - except IOError as e: - raise IOError("unable to flush %s on open: %s" % (self.socketname, e.message)) - except Exception: - raise IOError("unable to flush %s on open" % self.socketname) diff --git a/sonic_platform_base/sonic_sfp/inf8628.py b/sonic_platform_base/sonic_sfp/inf8628.py deleted file mode 100644 index 7c925edf3..000000000 --- a/sonic_platform_base/sonic_sfp/inf8628.py +++ /dev/null @@ -1,160 +0,0 @@ -#---------------------------------------------------------------------------- -# QSFP-DD 8X Transceiver (QSFP Double Density) -#---------------------------------------------------------------------------- - -from __future__ import print_function - -try: - from .sff8024 import type_of_transceiver # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import type_abbrv_name # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sffbase import sffbase # Dot module supports both Python 2 and Python 3 using explicit relative import methods -except ImportError as e: - raise ImportError ("%s - required module not found" % e) - -class inf8628InterfaceId(sffbase): - - def decode_revision_compliance(self, eeprom_data, offset, size): - return '%c.%c' % (eeprom_data[offset][0], eeprom_data[offset][1]) - - def decode_module_state(self, eeprom_data, offset, size): - module_state_byte = eeprom_data[offset] - module_state = int(module_state_byte, 16) & 14 - if module_state == 2: - return 'Low Power State' - elif module_state == 4: - return 'Power Up State' - elif module_state == 6: - return 'Ready State' - elif module_state == 8: - return 'Power Down State' - elif module_state == 10: - return 'Fault State' - return 'Unknown State %s' % module_state - - version = '1.0' - - interface_id = { - 'Identifier': - {'offset': 0, - 'size': 1, - 'type': 'enum', - 'decode': type_of_transceiver}, - 'Revision Compliance': - {'offset': 1, - 'type': 'func', - 'decode': {'func': decode_revision_compliance}}, - 'Module State': - {'offset': 3, - 'type': 'func', - 'decode': {'func': decode_module_state}}, - 'Interrupt Asserted': - {'offset': 3, - 'bit': 0, - 'type': 'bitvalue'}, - 'Vendor Name': - {'offset': 129, - 'size': 16, - 'type': 'str'}, - 'Vendor Part Number': - {'offset': 148, - 'size': 16, - 'type': 'str'}, - 'Vendor Revision': - {'offset': 164, - 'size': 2, - 'type': 'str'}, - 'Vendor Serial Number': - {'offset': 166, - 'size': 16, - 'type': 'str'}, - } - - sfp_type = { - 'type': - {'offset': 0, - 'size': 1, - 'type': 'enum', - 'decode': type_of_transceiver} - } - - sfp_type_abbrv_name = { - 'type_abbrv_name': - {'offset': 0, - 'size': 1, - 'type': 'enum', - 'decode': type_abbrv_name} - } - - vendor_name = { - 'Vendor Name': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_pn = { - 'Vendor PN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_rev = { - 'Vendor Rev': - {'offset': 0, - 'size': 2, - 'type': 'str'} - } - - vendor_sn = { - 'Vendor SN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - def __init__(self, eeprom_raw_data=None): - self.interface_data = None - start_pos = 0 - - if eeprom_raw_data is not None: - self.interface_data = sffbase.parse(self, - self.interface_id, - eeprom_raw_data, - start_pos) - - def parse(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.interface_id, eeprom_raw_data, start_pos) - - def parse_sfp_type(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_type, type_raw_data, start_pos) - - def parse_sfp_type_abbrv_name(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_type_abbrv_name, type_raw_data, start_pos) - - def parse_vendor_name(self, name_raw_data, start_pos): - return sffbase.parse(self, self.vendor_name, name_raw_data, start_pos) - - def parse_vendor_rev(self, rev_raw_data, start_pos): - return sffbase.parse(self, self.vendor_rev, rev_raw_data, start_pos) - - def parse_vendor_pn(self, pn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_pn, pn_raw_data, start_pos) - - def parse_vendor_sn(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_sn, sn_raw_data, start_pos) - - def dump_pretty(self): - if self.interface_data is None: - print('Object not initialized, nothing to print') - return - sffbase.dump_pretty(self, self.interface_data) - - def get_calibration_type(self): - return self.calibration_type - - def get_data(self): - return self.interface_data - - def get_data_pretty(self): - return sffbase.get_data_pretty(self, self.interface_data) diff --git a/sonic_platform_base/sonic_sfp/qsfp_dd.py b/sonic_platform_base/sonic_sfp/qsfp_dd.py deleted file mode 100644 index 3ded55332..000000000 --- a/sonic_platform_base/sonic_sfp/qsfp_dd.py +++ /dev/null @@ -1,742 +0,0 @@ -#---------------------------------------------------------------------------- -# QSFP-DD 8X Transceiver (QSFP Double Density) -#---------------------------------------------------------------------------- - -from __future__ import print_function - -try: - from .sff8024 import type_of_transceiver # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import type_abbrv_name # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import connector_dict # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import ext_type_of_transceiver # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import type_of_media_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import host_electrical_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import nm_850_media_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import sm_media_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import passive_copper_media_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import active_cable_media_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import base_t_media_interface # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from sonic_platform_base.sonic_sfp.sffbase import sffbase # Dot module supports both Python 2 and Python 3 using explicit relative import methods -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -#------------------------------------------------------------------------------ - -class qsfp_dd_InterfaceId(sffbase): - - def decode_revision_compliance(self, eeprom_data, offset, size): - # first nibble and second nibble represent the version - return '%c.%c' % (str((eeprom_data[offset][0] >> 4) & 0x0f), str((eeprom_data[offset][0] & 0x0f))) - - def decode_module_state(self, eeprom_data, offset, size): - module_state_byte = eeprom_data[offset] - # bits 1-3 - module_state = (int(module_state_byte, 16) >> 1) & 3 - if module_state == 1: - return 'Low Power state (Flat memory passive cable assemblies)' - elif module_state == 2: - return 'Power Up State' - elif module_state == 3: - return 'Ready State' - elif module_state == 4: - return 'Power Down State' - elif module_state == 5: - return 'Fault State' - return 'Unknown State %s' % module_state - - def decode_connector(self, eeprom_data, offset, size): - connector_id = eeprom_data[offset] - if connector_id in connector_dict.keys(): - return connector_dict[connector_id] - else: - return 'N/A' - - def decode_ext_id(self, eeprom_data, offset, size): - # bits 5-7 represent Module Card Power Class - ext_id_power_class_byte = eeprom_data[offset] - ext_id_power_class_code = (int(ext_id_power_class_byte, 16) >> 5) & 7 - # Max power is in multiply of 0.25W - ext_id_max_power_byte = eeprom_data[offset + 1] - ext_id_max_power_value = int(ext_id_max_power_byte, 16) - return ext_type_of_transceiver[str(ext_id_power_class_code)] + "({}W Max)".format(ext_id_max_power_value * 0.25) - - def decode_cable_len(self, eeprom_data, offset, size): - cable_byte = eeprom_data[offset] - # base length im meters 0-5 bits - base_len = int(cable_byte, 16) & 0x3f - # mult_code 6-7 bits - mult_code = (int(cable_byte, 16) >> 6) & 0x03 - if mult_code == 0: - mult = 0.1 - elif mult_code == 1: - mult = 1 - elif mult_code == 2: - mult = 10 - else: - mult = 100 - - return base_len * mult - - def decode_media_type(self, eeprom_data, offset, size): - media_type_code = eeprom_data[0] - - if media_type_code not in type_of_media_interface.keys(): - return None - - dict_name = type_of_media_interface[media_type_code] - - if dict_name == "nm_850_media_interface": - return nm_850_media_interface - elif dict_name == "sm_media_interface": - return sm_media_interface - elif dict_name == "passive_copper_media_interface": - return passive_copper_media_interface - elif dict_name == "active_cable_media_interface": - return active_cable_media_interface - elif dict_name == "base_t_media_interface": - return base_t_media_interface - else: - return None - - def parse_application(self, sfp_media_type_dict, host_interface, media_interface): - media_result = 'Unknown' - host_result = 'Unknown' - - if host_interface in host_electrical_interface: - host_result = host_electrical_interface[host_interface] - - if media_interface in sfp_media_type_dict.keys(): - media_result = sfp_media_type_dict[media_interface] - return host_result, media_result - - version = '1.0' - - connector = { - 'Connector': - {'offset':0, - 'type' : 'func', - 'decode': {'func': decode_connector}} - } - - sfp_type = { - 'type': - {'offset': 0, - 'size': 1, - 'type': 'enum', - 'decode': type_of_transceiver} - } - - ext_iden = { - 'Extended Identifier': - {'offset': 0, - 'type': 'func', - 'decode': {'func': decode_ext_id}} - } - - cable_len = { - 'Length Cable Assembly(m)': - {'offset': 0, - 'type': 'func', - 'decode': {'func': decode_cable_len}} - } - - rev_comp = { - 'Revision Compliance': - {'offset': 0, - 'type': 'func', - 'decode': {'func': decode_revision_compliance}} - } - - sfp_type_abbrv_name = { - 'type_abbrv_name': - {'offset': 0, - 'size': 1, - 'type': 'enum', - 'decode': type_abbrv_name} - } - - vendor_name = { - 'Vendor Name': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_pn = { - 'Vendor PN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_rev = { - 'Vendor Rev': - {'offset': 0, - 'size': 2, - 'type': 'str'} - } - - vendor_sn = { - 'Vendor SN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_oui = { - 'Vendor OUI': - {'offset':0, - 'size':3, - 'type' : 'hex'} - } - - qsfp_dd_dom_capability = { - 'Flat_MEM': - {'offset': 0, - 'bit': 7, - 'type': 'bitvalue'} - } - - vendor_date = { - 'VendorDataCode(YYYY-MM-DD Lot)': - {'offset':0, - 'size':8, - 'type': 'date'} - } - - def parse_sfp_type(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_type, type_raw_data, start_pos) - - def parse_sfp_type_abbrv_name(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_type_abbrv_name, type_raw_data, start_pos) - - def parse_vendor_name(self, name_raw_data, start_pos): - return sffbase.parse(self, self.vendor_name, name_raw_data, start_pos) - - def parse_vendor_rev(self, rev_raw_data, start_pos): - return sffbase.parse(self, self.vendor_rev, rev_raw_data, start_pos) - - def parse_vendor_pn(self, pn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_pn, pn_raw_data, start_pos) - - def parse_vendor_sn(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_sn, sn_raw_data, start_pos) - - def parse_vendor_date(self, date_raw_data, start_pos): - return sffbase.parse(self, self.vendor_date, date_raw_data, start_pos) - - def parse_vendor_oui(self, vendor_oui_data, start_pos): - return sffbase.parse(self, self.vendor_oui, vendor_oui_data, start_pos) - - def parse_connector(self, connector_data, start_pos): - return sffbase.parse(self, self.connector, connector_data, start_pos) - - def parse_ext_iden(self, ext_iden_data, start_pos): - return sffbase.parse(self, self.ext_iden, ext_iden_data, start_pos) - - def parse_cable_len(self, cable_len_data, start_pos): - return sffbase.parse(self, self.cable_len, cable_len_data, start_pos) - - def parse_dom_capability(self, dom_capability_raw_data, start_pos): - return sffbase.parse(self, self.qsfp_dd_dom_capability, dom_capability_raw_data, start_pos) - - def parse_media_type(self, qsfp_media_type_raw_data, start_pos): - return self.decode_media_type(qsfp_media_type_raw_data, start_pos, 1) - -class qsfp_dd_Dom(sffbase): - - version = '1.0' - - def calc_temperature(self, eeprom_data, offset, size): - try: - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - - result = (msb << 8) | (lsb & 0xff) - result = self.twos_comp(result, 16) - - result = float(result / 256.0) - retval = '%.4f' %result + 'C' - - except Exception as err: - retval = str(err) - - return retval - - - def calc_voltage(self, eeprom_data, offset, size): - try: - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - result = float(result * 0.0001) - retval = '%.4f' %result + 'Volts' - - except Exception as err: - retval = str(err) - - return retval - - - def calc_bias(self, eeprom_data, offset, size): - try: - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - result = float(result * 0.002) - retval = '%.4f' %result + 'mA' - - except Exception as err: - retval = str(err) - - return retval - - - def calc_tx_power(self, eeprom_data, offset, size): - try: - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - result = float(result * 0.0001) - retval = self.power_in_dbm_str(result) - - except Exception as err: - retval = str(err) - - return retval - - - def calc_rx_power(self, eeprom_data, offset, size): - try: - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - result = float(result * 0.0001) - retval = self.power_in_dbm_str(result) - - except Exception as err: - retval = str(err) - - return retval - - dom_channel_status = { - 'Status': - {'offset': 0, - 'bit': 3, - 'type': 'bitvalue'}} - - dom_channel_monitor_params = { - 'TX8Bias': - {'offset': 30, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX7Bias': - {'offset': 28, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX6Bias': - {'offset': 26, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX5Bias': - {'offset': 24, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX4Bias': - {'offset': 22, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX3Bias': - {'offset': 20, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX2Bias': - {'offset': 18, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX1Bias': - {'offset': 16, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'RX8Power': - {'offset': 46, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX7Power': - {'offset': 44, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX6Power': - {'offset': 42, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX5Power': - {'offset': 40, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX4Power': - {'offset': 38, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX3Power': - {'offset': 36, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX2Power': - {'offset': 34, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX1Power': - {'offset': 32, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'TX8Power': - {'offset': 14, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX7Power': - {'offset': 12, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX6Power': - {'offset': 10, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX5Power': - {'offset': 8, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX4Power': - {'offset': 6, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX3Power': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX2Power': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX1Power': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}} - } - - dom_tx_bias = { - 'TX8Bias': - {'offset': 14, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX7Bias': - {'offset': 12, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX6Bias': - {'offset': 10, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX5Bias': - {'offset': 8, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX4Bias': - {'offset': 6, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX3Bias': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX2Bias': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX1Bias': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}} - } - - dom_rx_power = { - 'RX8Power': - {'offset': 14, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX7Power': - {'offset': 12, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX6Power': - {'offset': 10, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX5Power': - {'offset': 8, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX4Power': - {'offset': 6, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX3Power': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX2Power': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX1Power': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}} - } - - dom_tx_power = { - 'TX8Power': - {'offset': 14, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX7Power': - {'offset': 12, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX6Power': - {'offset': 10, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX5Power': - {'offset': 8, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX4Power': - {'offset': 6, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX3Power': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX2Power': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX1Power': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}} - } - - dom_module_temperature = { - 'Temperature': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_temperature}} - } - - dom_module_voltage = { - 'Vcc': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_voltage}} - } - - dom_module_threshold_values = { - 'TempHighAlarm': - {'offset':0, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempLowAlarm': - {'offset':2, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempHighWarning': - {'offset':4, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempLowWarning': - {'offset':6, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'VccHighAlarm': - {'offset':8, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VccLowAlarm': - {'offset':10, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VccHighWarning': - {'offset':12, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VccLowWarning': - {'offset':14, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'RxPowerHighAlarm': - {'offset':64, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RxPowerLowAlarm': - {'offset':66, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RxPowerHighWarning': - {'offset':68, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RxPowerLowWarning': - {'offset':70, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'TxBiasHighAlarm': - {'offset':56, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxBiasLowAlarm': - {'offset':58, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxBiasHighWarning': - {'offset':60, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxBiasLowWarning': - {'offset':62, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxPowerHighAlarm': - {'offset':48, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'TxPowerLowAlarm': - {'offset':50, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'TxPowerHighWarning': - {'offset':52, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'TxPowerLowWarning': - {'offset':54, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}} - } - - def parse_temperature(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_temperature, eeprom_raw_data, - start_pos) - - def parse_voltage(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_voltage, eeprom_raw_data, - start_pos) - - def parse_channel_monitor_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_monitor_params, eeprom_raw_data, - start_pos) - - def parse_dom_tx_bias(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_bias, eeprom_raw_data, - start_pos) - - def parse_dom_rx_power(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_rx_power, eeprom_raw_data, - start_pos) - - def parse_dom_tx_power(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_power, eeprom_raw_data, - start_pos) - - def parse_module_threshold_values(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_threshold_values, eeprom_raw_data, - start_pos) - - def parse_dom_channel_status(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_status, eeprom_raw_data, - start_pos) - - def parse_dom_tx_fault(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_fault, eeprom_raw_data, - start_pos) - - def parse_dom_tx_disable (self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_disable, eeprom_raw_data, - start_pos) - diff --git a/sonic_platform_base/sonic_sfp/sff8024.py b/sonic_platform_base/sonic_sfp/sff8024.py deleted file mode 100644 index 19f81a31f..000000000 --- a/sonic_platform_base/sonic_sfp/sff8024.py +++ /dev/null @@ -1,358 +0,0 @@ -#---------------------------------------------------------------------------- -# SFF-8024 Rev 4.5 -#---------------------------------------------------------------------------- - -from __future__ import print_function - -type_of_transceiver = { - '00': 'Unknown or unspecified', - '01': 'GBIC', - '02': 'Module/connector soldered to motherboard', - '03': 'SFP/SFP+/SFP28', - '04': '300 pin XBI', - '05': 'XENPAK', - '06': 'XFP', - '07': 'XFF', - '08': 'XFP-E', - '09': 'XPAK', - '0a': 'X2', - '0b': 'DWDM-SFP/SFP+', - '0c': 'QSFP', - '0d': 'QSFP+ or later', - '0e': 'CXP or later', - '0f': 'Shielded Mini Multilane HD 4X', - '10': 'Shielded Mini Multilane HD 8X', - '11': 'QSFP28 or later', - '12': 'CXP2 (aka CXP28) or later', - '13': 'CDFP (Style 1/Style2)', - '14': 'Shielded Mini Multilane HD 4X Fanout Cable', - '15': 'Shielded Mini Multilane HD 8X Fanout Cable', - '16': 'CDFP (Style 3)', - '17': 'microQSFP', - '18': 'QSFP-DD Double Density 8X Pluggable Transceiver', - '19': 'OSFP 8X Pluggable Transceiver', - '1a': 'SFP-DD Double Density 2X Pluggable Transceiver' -} - -type_abbrv_name = { - '00': 'Unknown', - '01': 'GBIC', - '02': 'Soldered', - '03': 'SFP', - '04': 'XBI300', - '05': 'XENPAK', - '06': 'XFP', - '07': 'XFF', - '08': 'XFP-E', - '09': 'XPAK', - '0a': 'X2', - '0b': 'DWDM-SFP', - '0c': 'QSFP', - '0d': 'QSFP+', - '0e': 'CXP', - '0f': 'HD4X', - '10': 'HD8X', - '11': 'QSFP28', - '12': 'CXP2', - '13': 'CDFP-1/2', - '14': 'HD4X-Fanout', - '15': 'HD8X-Fanout', - '16': 'CDFP-3', - '17': 'MicroQSFP', - '18': 'QSFP-DD', - '19': 'OSFP-8X', - '1a': 'SFP-DD' -} - -connector_dict = { - '00': 'Unknown or unspecified', - '01': 'SC', - '02': 'FC Style 1 copper connector', - '03': 'FC Style 2 copper connector', - '04': 'BNC/TNC', - '05': 'FC coax headers', - '06': 'Fiberjack', - '07': 'LC', - '08': 'MT-RJ', - '09': 'MU', - '0a': 'SG', - '0b': 'Optical Pigtail', - '0c': 'MPO 1x12', - '0d': 'MPO 2x16', - '20': 'HSSDC II', - '21': 'Copper pigtail', - '22': 'RJ45', - '23': 'No separable connector', - '24': 'MXC 2x16', - '25': 'CS optical connector', - '26': 'SN optical connector', - '27': 'MPO 2x12', - '28': 'MPO 1x16', - } - -ext_type_of_transceiver = { - '0': 'Power Class 1', - '1': 'Power Class 2', - '2': 'Power Class 3', - '3': 'Power Class 4', - '4': 'Power Class 5', - '5': 'Power Class 6', - '6': 'Power Class 7', - '7': 'Power Class 8' - } - -type_of_media_interface = { - '00': 'Undefined', - '01': 'nm_850_media_interface', - '02': 'sm_media_interface', - '03': 'passive_copper_media_interface', - '04': 'active_cable_media_interface', - '05': 'base_t_media_interface', - } - -host_electrical_interface = { - '00': 'Undefined', - '01': '1000BASE -CX(Clause 39)', - '02': 'XAUI(Clause 47)', - '03': 'XFI (SFF INF-8071i)', - '04': 'SFI (SFF-8431)', - '05': '25GAUI C2M (Annex 109B)', - '06': 'XLAUI C2M (Annex 83B)', - '07': 'XLPPI (Annex 86A)', - '08': 'LAUI-2 C2M (Annex 135C)', - '09': '50GAUI-2 C2M (Annex 135E)', - '0a': '50GAUI-1 C2M (Annex 135G)', - '0b': 'CAUI-4 C2M (Annex 83E)', - '41': 'CAUI-4 C2M (Annex 83E) without FEC', - '42': 'CAUI-4 C2M (Annex 83E) with RS(528,514) FEC', - '0c': '100GAUI-4 C2M (Annex 135E)', - '0d': '100GAUI-2 C2M (Annex 135G)', - '0e': '200GAUI-8 C2M (Annex 120C)', - '0f': '200GAUI-4 C2M (Annex 120E)', - '10': '400GAUI-16 C2M (Annex 120C)', - '11': '400GAUI-8 C2M (Annex 120E)', - '13': '10GBASE-CX4 (Clause 54)', - '14': '25GBASE-CR CA-L (Clause 110)', - '15': '25GBASE-CR CA-S (Clause 110)', - '16': '25GBASE-CR CA-N (Clause 110)', - '17': '40GBASE-CR4 (Clause 85)', - '43': '50GBASE-CR2 with RS (Clause 91) FEC', - '44': '50GBASE-CR2 with BASE-R (Clause 74 Fire code) FEC', - '45': '50GBASE-CR2 with no FEC', - '18': '50GBASE-CR (Clause 126)', - '19': '100GBASE-CR10 (Clause 85)', - '1a': '100GBASE-CR4 (Clause 92)', - '1b': '100GBASE-CR2 (Clause 136)', - '1c': '200GBASE-CR4 (Clause 136)', - '1d': '400G CR8', - '1e': '1000BASE-T (Clause 40)', - '1f': '2.5GBASE-T (Clause 126)', - '20': '5GBASE-T (Clause 126)', - '21': '10GBASE-T (Clause 55)', - '22': '25GBASE-T (Clause 113)', - '23': '40GBASE-T (Clause 113)', - '24': '50GBASE-T (Placeholder)', - '25': '8GFC (FC-PI-4)', - '26': '10GFC (10GFC)', - '27': '16GFC (FC-PI-5)', - '28': '32GFC (FC-PI-6)', - '29': '64GFC (FC-PI-7)', - '2a': '128GFC (FC-PI-6P)', - '2b': '256GFC (FC-PI-7P)', - '2c': 'IB SDR (Arch.Spec.Vol.2)', - '2d': 'IB DDR (Arch.Spec.Vol.2)', - '2e': 'IB QDR (Arch.Spec.Vol.2)', - '2f': 'IB FDR (Arch.Spec.Vol.2)', - '30': 'IB EDR (Arch.Spec.Vol.2)', - '31': 'IB HDR (Arch.Spec.Vol.2)', - '32': 'IB NDR', - '33': 'E.96 (CPRI Specification V7.0)', - '34': 'E.99 (CPRI Specification V7.0)', - '35': 'E.119 (CPRI Specification V7.0)', - '36': 'E.238 (CPRI Specification V7.0)', - '37': 'OTL3.4 (ITU-T G.709/Y.1331 G.Sup58)', - '38': 'OTL4.10 (ITU-T G.709/Y.1331 G.Sup58)', - '39': 'OTL4.4 (ITU-T G.709/Y.1331 G.Sup58)', - '3a': 'OTLC.4 (ITU-T G.709.1/Y.1331 G.Sup58)', - '3b': 'FOIC1.4 (ITU-T G.709.1/Y.1331 G.Sup58)', - '3c': 'FOIC1.2 (ITU-T G.709.1/Y.1331 G.Sup58)', - '3d': 'FOIC2.8 (ITU-T G.709.1/Y.1331 G.Sup58)', - '3e': 'FOIC2.4 (ITU-T G.709.1/Y.1331 G.Sup58)', - '3f': 'FOIC4.16 (ITU-T G.709.1 G.Sup58)', - '40': 'FOIC4.8 (ITU-T G.709.1 G.Sup58)', - } - -nm_850_media_interface = { - '00': 'Undefined', - '01': '10GBASE-SW (Clause 52)', - '02': '10GBASE-SR (Clause 52)', - '03': '25GBASE-SR (Clause 112)', - '04': '40GBASE-SR4 (Clause 86)', - '05': '40GE SWDM4 MSA Spec', - '06': '40GE BiDi', - '07': '50GBASE-SR (Clause 138)', - '08': '100GBASE-SR10 (Clause 86)', - '09': '100GBASE-SR4 (Clause 95)', - '0a': '100GE SWDM4 MSA Spec', - '0b': '100GE BiDi', - '0c': '100GBASE-SR2 (Clause 138)', - '0d': '100G-SR (Placeholder)', - '0e': '200GBASE-SR4 (Clause 138)', - '0f': '400GBASE-SR16 (Clause 123)', - '10': '400GBASE-SR8 (Clause 138)', - '11': '400G-SR4 (Placeholder)', - '12': '800G-SR8 (Placeholder)', - '1a': '400GBASE-SR4.2 (Clause 150) (400GE BiDi)', - '13': '8GFC-MM (FC-PI-4)', - '14': '10GFC-MM (10GFC)', - '15': '16GFC-MM (FC-PI-5)', - '16': '32GFC-MM (FC-PI-6)', - '17': '64GFC-MM (FC-PI 7)', - '18': '128GFC-MM4 (FC-PI-6P)', - '19': '256GFC-MM4 (FC-PI-7P)', - } - -sm_media_interface = { - '00': 'Undefined', - '01': '10GBASE-LW (Cl 52)', - '02': '10GBASE-EW (Cl 52)', - '03': '10G-ZW', - '04': '10GBASE-LR (Cl 52)', - '05': '10GBASE-ER (Cl 52)', - '06': '10G-ZR', - '07': '25GBASE-LR (Cl 114)', - '08': '25GBASE-ER (Cl 114)', - '09': '40GBASE-LR4 (Cl 87)', - '0a': '40GBASE-FR (Cl 89)', - '0b': '50GBASE-FR (Cl 139)', - '0c': '50GBASE-LR (Cl 139)', - '40': '50GBASE-ER (Cl 139)', - '0d': '100GBASE-LR4 (Cl 88)', - '0e': '100GBASE-ER4 (Cl 88)', - '0f': '100G PSM4 MSA Spec', - '34': '100G CWDM4-OCP', - '10': '100G CWDM4 MSA Spec', - '11': '100G 4WDM-10 MSA Spec', - '12': '100G 4WDM-20 MSA Spec', - '13': '100G 4WDM-40 MSA Spec', - '14': '100GBASE-DR (Cl 140)', - '15': '100G-FR/100GBASE-FR1 (Cl 140)', - '16': '100G-LR/100GBASE-LR1 (Cl 140)', - '17': '200GBASE-DR4 (Cl 121)', - '18': '200GBASE-FR4 (Cl 122)', - '19': '200GBASE-LR4 (Cl 122)', - '41': '200GBASE-ER4 (Cl 122)', - '1a': '400GBASE-FR8 (Cl 122)', - '1b': '400GBASE-LR8 (Cl 122)', - '42': '400GBASE-ER8 (Cl 122)', - '1c': '400GBASE-DR4 (Cl 124)', - '1d': '400G-FR4/400GBASE-FR4 (Cl 151)', - '43': '400GBASE-LR4-6 (Cl 151)', - '1e': '400G-LR4-10', - '1f': '8GFC-SM (FC-PI-4)', - '20': '10GFC-SM (10GFC)', - '21': '16GFC-SM (FC-PI-5)', - '22': '32GFC-SM (FC-PI-6)', - '23': '64GFC-SM (FC-PI-7)', - '24': '128GFC-PSM4 (FC-PI-6P)', - '25': '256GFC-PSM4 (FC-PI-7P)', - '26': '128GFC-CWDM4 (FC-PI-6P)', - '27': '256GFC-CWDM4 (FC-PI-7P)', - '2c': '4I1-9D1F (G.959.1)', - '2d': '4L1-9C1F (G.959.1)', - '2e': '4L1-9D1F (G.959.1)', - '2f': 'C4S1-9D1F (G.695)', - '30': 'C4S1-4D1F (G.695)', - '31': '4I1-4D1F (G.959.1)', - '32': '8R1-4D1F (G.959.1)', - '33': '8I1-4D1F (G.959.1)', - '38': '10G-SR', - '39': '10G-LR', - '3a': '25G-SR', - '3b': '25G-LR', - '3c': '10G-LR-BiDi', - '3d': '25G-LR-BiDi', - '3e': '400ZR, DWDM, amplified', - '3f': '400ZR, Single Wavelength, Unamplified', - } - -passive_copper_media_interface = { - '00': 'Undefined', - '01': 'Copper cable', - '02': 'Passive Loopback module', - } - -active_cable_media_interface = { - '00': 'Undefined', - '01': 'Active Cable assembly with BER < 10^-12', - '02': 'Active Cable assembly with BER < 5x10^-5', - '03': 'Active Cable assembly with BER < 2.6x10^-4', - '04': 'Active Cable assembly with BER < 10^-6', - 'bf': 'Active Loopback module', - } - -base_t_media_interface = { - '00': 'Undefined', - '01': '1000BASE-T (Clause 40)', - '02': '2.5GBASE-T (Clause 126)', - '03': '5GBASE-T (Clause 126)', - '04': '10GBASE-T (Clause 55)', - } - -ext_specification_compliance = { - '00': 'Unspecified', - '01': '100G AOC (Active Optical Cable) or 25GAUI C2M AOC', - '02': '100GBASE-SR4 or 25GBASE-SR', - '03': '100GBASE-LR4 or 25GBASE-LR', - '04': '100GBASE-ER4 or 25GBASE-ER', - '05': '100GBASE-SR10', - '06': '100G CWDM4', - '07': '100G PSM4 Parallel SMF', - '08': '100G ACC (Active Copper Cable) or 25GAUI C2M ACC', - '09': 'Obsolete (assigned before 100G CWDM4 MSA required FEC)', - '0b': '100GBASE-CR4, 25GBASE-CR CA-25G-L or 50GBASE-CR2 with RS', - '0c': '25GBASE-CR CA-25G-S or 50GBASE-CR2 with BASE-R', - '0d': '25GBASE-CR CA-25G-N or 50GBASE-CR2 with no FEC', - '10': '40GBASE-ER4', - '11': '4 x 10GBASE-SR', - '12': '40G PSM4 Parallel SMF', - '13': 'G959.1 profile P1I1-2D1 (10709 MBd, 2km, 1310 nm SM)', - '14': 'G959.1 profile P1S1-2D2 (10709 MBd, 40km, 1550 nm SM)', - '15': 'G959.1 profile P1L1-2D2 (10709 MBd, 80km, 1550 nm SM)', - '16': '10GBASE-T with SFI electrical interface', - '17': '100G CLR4', - '18': '100G AOC or 25GAUI C2M AOC', - '19': '100G ACC or 25GAUI C2M ACC', - '1a': '100GE-DWDM2', - '1b': '100G 1550nm WDM', - '1c': '10GBASE-T Short Reach', - '1d': '5GBASE-T', - '1e': '2.5GBASE-T', - '1f': '40G SWDM4', - '20': '100G SWDM4', - '21': '100G PAM4 BiDi', - '22': '4WDM-10 MSA', - '23': '4WDM-20 MSA', - '24': '4WDM-40 MSA', - '25': '100GBASE-DR', - '26': '100G-FR or 100GBASE-FR1', - '27': '100G-LR or 100GBASE-LR1', - '30': 'Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below', - '31': 'Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below', - '32': 'Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below', - '33': 'Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for AOC, 10-5 for AUI, or below', - '40': '50GBASE-CR, 100GBASE-CR2, or 200GBASE-CR4', - '41': '50GBASE-SR, 100GBASE-SR2, or 200GBASE-SR4', - '42': '50GBASE-FR or 200GBASE-DR4', - '43': '200GBASE-FR4', - '44': '200G 1550 nm PSM4', - '45': '50GBASE-LR', - '46': '200GBASE-LR4', - '50': '64GFC EA', - '51': '64GFC SW', - '52': '64GFC LW', - '53': '128GFC EA', - '54': '128GFC SW', - '55': '128GFC LW' -} - diff --git a/sonic_platform_base/sonic_sfp/sff8436.py b/sonic_platform_base/sonic_sfp/sff8436.py deleted file mode 100644 index 3a3e86d24..000000000 --- a/sonic_platform_base/sonic_sfp/sff8436.py +++ /dev/null @@ -1,1738 +0,0 @@ -#---------------------------------------------------------------------------- -# SFF-8436 QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER -#---------------------------------------------------------------------------- - -from __future__ import print_function - -try: - import fcntl - import struct - import sys - import time - import os - import getopt - import types - from math import log10 - from .sff8024 import type_of_transceiver # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import type_abbrv_name # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import ext_specification_compliance # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sffbase import sffbase # Dot module supports both Python 2 and Python 3 using explicit relative import methods -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -class sff8436InterfaceId(sffbase): - - version = '1.0' - - specification_compliance = {'10/40G Ethernet Compliance Code': - {'offset':3, - 'size':1, - 'type' : 'bitmap', - 'decode' : { - '10GBase-LRM': - {'offset': 3, - 'bit': 6}, - '10GBase-LR': - {'offset': 3, - 'bit': 5}, - '10GBase-SR': - {'offset': 3, - 'bit': 4}, - '40GBASE-CR4': - {'offset': 3, - 'bit': 3}, - '40GBASE-SR4': - {'offset': 3, - 'bit': 2}, - '40GBASE-LR4': - {'offset': 3, - 'bit': 1}, - '40G Active Cable (XLPPI)': - {'offset': 3, - 'bit': 0}}}, - 'SONET Compliance codes': - {'offset':4, - 'size':1, - 'type' : 'bitmap', - 'decode' : { - '40G OTN (OTU3B/OTU3C)': - {'offset': 4, - 'bit': 3}, - 'OC 48, long reach': - {'offset': 4, - 'bit': 2}, - 'OC 48, intermediate reach': - {'offset': 4, - 'bit': 1}, - 'OC 48 short reach': - {'offset': 4, - 'bit': 0}}}, - 'SAS/SATA compliance codes': - {'offset': 5, - 'size' : 1, - 'type' : 'bitmap', - 'decode': { - 'SAS 6.0G': - {'offset': 5, - 'bit': 5}, - 'SAS 3.0G': - {'offset': 5, - 'bit': 4}}}, - 'Gigabit Ethernet Compliant codes': - {'offset': 6, - 'size' : 1, - 'type' : 'bitmap', - 'decode': { - '1000BASE-T': - {'offset': 6, - 'bit': 3}, - '1000BASE-CX': - {'offset': 6, - 'bit': 2}, - '1000BASE-LX': - {'offset': 6, - 'bit': 1}, - '1000BASE-SX': - {'offset': 6, - 'bit': 0}}}, - 'Fibre Channel link length/Transmitter Technology': - {'offset': 7, - 'size' : 2, - 'type' : 'bitmap', - 'decode': { - 'Very long distance (V)': - {'offset': 7, - 'bit': 7}, - 'Short distance (S)': - {'offset': 7, - 'bit': 6}, - 'Intermediate distance (I)': - {'offset': 7, - 'bit': 5}, - 'Long distance (L)': - {'offset': 7, - 'bit': 4}, - 'Medium (M)': - {'offset': 7, - 'bit': 3}, - 'Longwave laser (LC)': - {'offset': 7, - 'bit': 1}, - 'Electrical inter-enclosure (EL)': - {'offset': 7, - 'bit': 0}, - 'Electrical intra-enclosure': - {'offset': 8, - 'bit': 7}, - 'Shortwave laser w/o OFC (SN)': - {'offset': 8, - 'bit': 6}, - 'Shortwave laser w OFC (SL)': - {'offset': 8, - 'bit': 5}, - 'Longwave Laser (LL)': - {'offset': 8, - 'bit': 4}}}, - 'Fibre Channel transmission media': - {'offset': 8, - 'size' : 1, - 'type' : 'bitmap', - 'decode': { - 'Twin Axial Pair (TW)': - {'offset': 8, - 'bit': 7}, - 'Shielded Twisted Pair (TP)': - {'offset': 8, - 'bit': 6}, - 'Miniature Coax (MI)': - {'offset': 8, - 'bit': 5}, - 'Video Coax (TV)': - {'offset': 8, - 'bit': 4}, - 'Multi-mode 62.5m (M6)': - {'offset': 8, - 'bit': 3}, - 'Multi-mode 50m (M5)': - {'offset': 8, - 'bit': 2}, - 'Multi-mode 50um (OM3)': - {'offset': 8, - 'bit': 1}, - 'Single Mode (SM)': - {'offset': 8, - 'bit': 0}}}, - 'Fibre Channel Speed': - {'offset': 9, - 'size' : 1, - 'type' : 'bitmap', - 'decode': { - '1200 Mbytes/Sec': - {'offset': 9, - 'bit': 7}, - '800 Mbytes/Sec': - {'offset': 9, - 'bit': 6}, - '1600 Mbytes/Sec': - {'offset': 9, - 'bit': 5}, - '400 Mbytes/Sec': - {'offset': 9, - 'bit': 4}, - '200 Mbytes/Sec': - {'offset': 9, - 'bit': 2}, - '100 Mbytes/Sec': - {'offset': 9, - 'bit': 0}}}} - - ext_type_of_transceiver = { - '00': 'Power Class 1(1.5W max)', - '04': 'Power Class 1(1.5W max), CDR present in Tx', - '08': 'Power Class 1(1.5W max), CDR present in Rx', - '0c': 'Power Class 1(1.5W max), CDR present in Rx Tx', - '10': 'Power Class 1(1.5W max), CLEI present', - '14': 'Power Class 1(1.5W max), CLEI present, CDR present in Tx', - '18': 'Power Class 1(1.5W max), CLEI present, CDR present in Rx', - '1c': 'Power Class 1(1.5W max), CLEI present, CDR present in Rx Tx', - - '40': 'Power Class 2(2.0W max)', - '44': 'Power Class 2(2.0W max), CDR present in Rx', - '48': 'Power Class 2(2.0W max), CDR present in Tx', - '4c': 'Power Class 2(2.0W max), CDR present in Rx Tx', - '50': 'Power Class 2(2.0W max), CLEI present', - '54': 'Power Class 2(2.0W max), CLEI present, CDR present in Rx', - '58': 'Power Class 2(2.0W max), CLEI present, CDR present in Tx', - '5c': 'Power Class 2(2.0W max), CLEI present, CDR present in Rx Tx', - - '80': 'Power Class 3(2.5W max)', - '84': 'Power Class 3(2.5W max), CDR present in Rx', - '88': 'Power Class 3(2.5W max), CDR present in Tx', - '8c': 'Power Class 3(2.5W max), CDR present in Rx Tx', - '90': 'Power Class 3(2.5W max), CLEI present', - '94': 'Power Class 3(2.5W max), CLEI present, CDR present in Rx', - '98': 'Power Class 3(2.5W max), CLEI present, CDR present in Tx', - '9c': 'Power Class 3(2.5W max), CLEI present, CDR present in Rx Tx', - - 'c0': 'Power Class 4(3.5W max)', - 'c4': 'Power Class 4(3.5W max), CDR present in Rx', - 'c8': 'Power Class 4(3.5W max), CDR present in Tx', - 'cc': 'Power Class 4(3.5W max), CDR present in Rx Tx', - 'd0': 'Power Class 4(3.5W max), CLEI present', - 'd4': 'Power Class 4(3.5W max), CLEI present, CDR present in Rx', - 'd8': 'Power Class 4(3.5W max), CLEI present, CDR present in Tx', - 'dc': 'Power Class 4(3.5W max), CLEI present, CDR present in Rx Tx' - } - - connector = { - '00': 'Unknown or unspecified', - '01': 'SC', - '02': 'FC Style 1 copper connector', - '03': 'FC Style 2 copper connector', - '04': 'BNC/TNC', - '05': 'FC coax headers', - '06': 'Fiberjack', - '07': 'LC', - '08': 'MT-RJ', - '09': 'MU', - '0a': 'SG', - '0b': 'Optical Pigtail', - '0c': 'MPOx12', - '0d': 'MPOx16', - '20': 'HSSDC II', - '21': 'Copper pigtail', - '22': 'RJ45', - '23': 'No separable connector' - } - - encoding_codes = { - '00':'Unspecified', - '01': '8B10B', - '02': '4B5B', - '03': 'NRZ', - '04': 'SONET Scrambled', - '05': '64B66B', - '06': 'Manchester', - '07': '256B257B' - } - - rate_identifier = {'00':'QSFP+ Rate Select Version 1'} - - interface_id = {'Identifier': - {'offset':0, - 'size':1, - 'type' : 'enum', - 'decode' : type_of_transceiver}, - 'Extended Identifier': - {'offset':1, - 'size':1, - 'type' : 'enum', - 'decode': ext_type_of_transceiver}, - 'Connector': - {'offset':2, - 'size':1, - 'type' : 'enum', - 'decode': connector}, - 'Specification compliance': - {'offset' : 3, - 'type' : 'nested', - 'decode' : specification_compliance}, - 'Encoding': - {'offset':11, - 'size':1, - 'type' : 'enum', - 'decode' : encoding_codes}, - 'Nominal Bit Rate(100Mbs)': - {'offset': 12, - 'size':1, - 'type':'int'}, - 'Extended RateSelect Compliance': - {'offset':13, - 'size':1, - 'type' : 'enum', - 'decode' : rate_identifier}, - 'Length(km)': - {'offset':14, - 'size':1, - 'type':'int'}, - 'Length OM3(2m)': - {'offset':15, - 'size':1, - 'type':'int'}, - 'Length OM2(m)': - {'offset':16, - 'size':1, - 'type':'int'}, - 'Length OM1(m)': - {'offset':17, - 'size':1, - 'type':'int'}, - 'Length Cable Assembly(m)': - {'offset':18, - 'size':1, - 'type':'int'}, - # Device Tech - 'Vendor Name': - {'offset' : 20, - 'size': 16, - 'type': 'str'}, - 'Vendor OUI': - {'offset': 37, - 'size' : 3, - 'type' : 'hex'}, - 'Vendor PN': - {'offset': 40, - 'size' : 16, - 'type' : 'str'}, - 'Vendor Rev': - {'offset': 56, - 'size' : 2, - 'type' : 'str'}, - 'Vendor SN': - {'offset': 68, - 'size' : 16, - 'type' : 'str'}, - 'Vendor Date Code(YYYY-MM-DD Lot)': - {'offset': 84, - 'size' : 8, - 'type' : 'date'}, - 'Diagnostic Monitoring Type': - {'offset': 92, - 'size' : 1, - 'type' : 'bitmap', - 'decode': {}}, - 'Enhanced Options': - {'offset': 93, - 'size' : 1, - 'type' : 'bitmap', - 'decode': {}}} - - sfp_info_bulk = {'type': - {'offset':0, - 'size':1, - 'type' : 'enum', - 'decode' : type_of_transceiver}, - 'type_abbrv_name': - {'offset':0, - 'size':1, - 'type' : 'enum', - 'decode' : type_abbrv_name}, - 'Extended Identifier': - {'offset':1, - 'size':1, - 'type' : 'enum', - 'decode': ext_type_of_transceiver}, - 'Connector': - {'offset':2, - 'size':1, - 'type' : 'enum', - 'decode': connector}, - 'Specification compliance': - {'offset' : 3, - 'type' : 'nested', - 'decode' : specification_compliance}, - 'EncodingCodes': - {'offset':11, - 'size':1, - 'type' : 'enum', - 'decode' : encoding_codes}, - 'Nominal Bit Rate(100Mbs)': - {'offset': 12, - 'size':1, - 'type':'int'}, - 'RateIdentifier': - {'offset':13, - 'size':1, - 'type' : 'enum', - 'decode' : rate_identifier}, - 'Length(km)': - {'offset':14, - 'size':1, - 'type':'int'}, - 'Length OM3(2m)': - {'offset':15, - 'size':1, - 'type':'int'}, - 'Length OM2(m)': - {'offset':16, - 'size':1, - 'type':'int'}, - 'Length OM1(m)': - {'offset':17, - 'size':1, - 'type':'int'}, - 'Length Cable Assembly(m)': - {'offset':18, - 'size':1, - 'type':'int'} - } - - vendor_name = { - 'Vendor Name': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_pn = { - 'Vendor PN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_rev = { - 'Vendor Rev': - {'offset': 0, - 'size': 2, - 'type': 'str'} - } - - vendor_sn = { - 'Vendor SN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_oui = { - 'Vendor OUI': - {'offset':0, - 'size':3, - 'type' : 'hex'} - } - - vendor_date = { - 'VendorDataCode(YYYY-MM-DD Lot)': - {'offset':0, - 'size':8, - 'type': 'date'} - } - - sfp_ext_specification_compliance = { - 'Extended Specification compliance': - {'offset' : 0, - 'size':1, - 'type' : 'enum', - 'decode' : ext_specification_compliance} - } - - qsfp_dom_capability = { - 'Tx_power_support': - {'offset': 0, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx_power_support': - {'offset': 0, - 'bit': 3, - 'type': 'bitvalue'}, - 'Voltage_support': - {'offset': 0, - 'bit': 4, - 'type': 'bitvalue'}, - 'Temp_support': - {'offset': 0, - 'bit': 5, - 'type': 'bitvalue'} - } - - def __init__(self, eeprom_raw_data=None): - self.interface_data = None - start_pos = 128 - - if eeprom_raw_data != None: - self.interface_data = sffbase.parse(self, - self.interface_id, - eeprom_raw_data, - start_pos) - - def parse(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.interface_id, eeprom_raw_data, start_pos) - - def parse_sfp_info_bulk(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_info_bulk, type_raw_data, start_pos) - - def parse_vendor_name(self, name_raw_data, start_pos): - return sffbase.parse(self, self.vendor_name, name_raw_data, start_pos) - - def parse_vendor_rev(self, rev_raw_data, start_pos): - return sffbase.parse(self, self.vendor_rev, rev_raw_data, start_pos) - - def parse_vendor_pn(self, pn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_pn, pn_raw_data, start_pos) - - def parse_vendor_sn(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_sn, sn_raw_data, start_pos) - - def parse_vendor_date(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_date, sn_raw_data, start_pos) - - def parse_vendor_oui(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_oui, sn_raw_data, start_pos) - - def parse_ext_specification_compliance(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.sfp_ext_specification_compliance, sn_raw_data, start_pos) - - def parse_dom_capability(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.qsfp_dom_capability, sn_raw_data, start_pos) - - def dump_pretty(self): - if self.interface_data == None: - print('Object not initialized, nothing to print') - return - sffbase.dump_pretty(self, self.interface_data) - - def get_calibration_type(self): - return self.calibration_type - - def get_data(self): - return self.interface_data - - def get_data_pretty(self): - return sffbase.get_data_pretty(self, self.interface_data) - - -class sff8436Dom(sffbase): - - version = '1.0' - - def get_calibration_type(self): - return self._calibration_type - - def calc_temperature(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - - result = (msb << 8) | (lsb & 0xff) - result = self.twos_comp(result, 16) - - if cal_type == 1: - - # Internal calibration - - result = float(result / 256.0) - retval = '%.4f' %result + 'C' - elif cal_type == 2: - - # External calibration - - # T(C) = T_Slope * T_AD + T_Offset - off = self.dom_ext_calibration_constants['T_Slope']['offset'] - msb_t = int(eeprom_data[off], 16) - lsb_t = int(eeprom_data[off + 1], 16) - t_slope = (msb_t << 8) | (lsb_t & 0xff) - - off = self.dom_ext_calibration_constants['T_Offset']['offset'] - msb_t = int(eeprom_data[off], 16) - lsb_t = int(eeprom_data[off + 1], 16) - t_offset = (msb_t << 8) | (lsb_t & 0xff) - t_offset = self.twos_comp(t_offset, 16) - - result = t_slope * result + t_offset - result = float(result / 256.0) - retval = '%.4f' %result + 'C' - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_voltage(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - - # Internal Calibration - - result = float(result * 0.0001) - #print(indent, name, ' : %.4f' %result, 'Volts') - retval = '%.4f' %result + 'Volts' - elif cal_type == 2: - - # External Calibration - - # V(uV) = V_Slope * VAD + V_Offset - off = self.dom_ext_calibration_constants['V_Slope']['offset'] - msb_v = int(eeprom_data[off], 16) - lsb_v = int(eeprom_data[off + 1], 16) - v_slope = (msb_v << 8) | (lsb_v & 0xff) - - off = self.dom_ext_calibration_constants['V_Offset']['offset'] - msb_v = int(eeprom_data[off], 16) - lsb_v = int(eeprom_data[off + 1], 16) - v_offset = (msb_v << 8) | (lsb_v & 0xff) - v_offset = self.twos_comp(v_offset, 16) - - result = v_slope * result + v_offset - result = float(result * 0.0001) - #print(indent, name, ' : %.4f' %result, 'Volts') - retval = '%.4f' %result + 'Volts' - else: - #print(indent, name, ' : Unknown') - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_bias(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - # Internal Calibration - - result = float(result * 0.002) - #print(indent, name, ' : %.4f' %result, 'mA') - retval = '%.4f' %result + 'mA' - - elif cal_type == 2: - # External Calibration - - # I(uA) = I_Slope * I_AD + I_Offset - off = self.dom_ext_calibration_constants['I_Slope']['offset'] - msb_i = int(eeprom_data[off], 16) - lsb_i = int(eeprom_data[off + 1], 16) - i_slope = (msb_i << 8) | (lsb_i & 0xff) - - off = self.dom_ext_calibration_constants['I_Offset']['offset'] - msb_i = int(eeprom_data[off], 16) - lsb_i = int(eeprom_data[off + 1], 16) - i_offset = (msb_i << 8) | (lsb_i & 0xff) - i_offset = self.twos_comp(i_offset, 16) - - result = i_slope * result + i_offset - result = float(result * 0.002) - #print(indent, name, ' : %.4f' %result, 'mA') - retval = '%.4f' %result + 'mA' - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_tx_power(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - - result = float(result * 0.0001) - #print(indent, name, ' : ', power_in_dbm_str(result)) - retval = self.power_in_dbm_str(result) - - elif cal_type == 2: - - # TX_PWR(uW) = TX_PWR_Slope * TX_PWR_AD + TX_PWR_Offset - off = self.dom_ext_calibration_constants['TX_PWR_Slope']['offset'] - msb_tx_pwr = int(eeprom_data[off], 16) - lsb_tx_pwr = int(eeprom_data[off + 1], 16) - tx_pwr_slope = (msb_tx_pwr << 8) | (lsb_tx_pwr & 0xff) - - off = self.dom_ext_calibration_constants['TX_PWR_Offset']['offset'] - msb_tx_pwr = int(eeprom_data[off], 16) - lsb_tx_pwr = int(eeprom_data[off + 1], 16) - tx_pwr_offset = (msb_tx_pwr << 8) | (lsb_tx_pwr & 0xff) - tx_pwr_offset = self.twos_comp(tx_pwr_offset, 16) - - result = tx_pwr_slope * result + tx_pwr_offset - result = float(result * 0.0001) - retval = self.power_in_dbm_str(result) - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_rx_power(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - - # Internal Calibration - result = float(result * 0.0001) - #print(indent, name, " : ", power_in_dbm_str(result)) - retval = self.power_in_dbm_str(result) - - elif cal_type == 2: - - # External Calibration - - # RX_PWR(uW) = RX_PWR_4 * RX_PWR_AD + - # RX_PWR_3 * RX_PWR_AD + - # RX_PWR_2 * RX_PWR_AD + - # RX_PWR_1 * RX_PWR_AD + - # RX_PWR(0) - off = self.dom_ext_calibration_constants['RX_PWR_4']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_4 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_3']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_3 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_2']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_2 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_1']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_1 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_0']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_0 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - rx_pwr = (rx_pwr_4 * result) + (rx_pwr_3 * result) + (rx_pwr_2 * result) + (rx_pwr_1 * result) + rx_pwr_0 - - result = float(result * 0.0001) - #print(indent, name, " : ", power_in_dbm_str(result)) - retval = self.power_in_dbm_str(result) - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - dom_status_indicator = { - 'DataNotReady': - {'offset': 0, - 'bit': 0, - 'type': 'bitvalue'}, - 'IntL': - {'offset': 0, - 'bit': 1, - 'type': 'bitvalue'}, - 'FlatMem': - {'offset': 0, - 'bit': 2, - 'type': 'bitvalue'}} - - dom_channel_status = { - 'Tx4LOS': - {'offset': 3, - 'bit': 7, - 'type': 'bitvalue'}, - 'Tx3LOS': - {'offset': 3, - 'bit': 6, - 'type': 'bitvalue'}, - 'Tx2LOS': - {'offset': 3, - 'bit': 5, - 'type': 'bitvalue'}, - 'Tx1LOS': - {'offset': 3, - 'bit': 4, - 'type': 'bitvalue'}, - 'Rx4LOS': - {'offset': 3, - 'bit': 3, - 'type': 'bitvalue'}, - 'Rx3LOS': - {'offset': 3, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx2LOS': - {'offset': 3, - 'bit': 1, - 'type': 'bitvalue'}, - 'Rx1LOS': - {'offset': 3, - 'bit': 0, - 'type': 'bitvalue'}, - 'Tx4Fault': - {'offset': 4, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx3Fault': - {'offset': 4, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx2Fault': - {'offset': 4, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx1Fault': - {'offset': 4, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_tx_rx_los = {'Tx4LOS': - {'offset': 0, - 'bit': 7, - 'type': 'bitvalue'}, - 'Tx3LOS': - {'offset': 0, - 'bit': 6, - 'type': 'bitvalue'}, - 'Tx2LOS': - {'offset': 0, - 'bit': 5, - 'type': 'bitvalue'}, - 'Tx1LOS': - {'offset': 0, - 'bit': 4, - 'type': 'bitvalue'}, - 'Rx4LOS': - {'offset': 0, - 'bit': 3, - 'type': 'bitvalue'}, - 'Rx3LOS': - {'offset': 0, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx2LOS': - {'offset': 0, - 'bit': 1, - 'type': 'bitvalue'}, - 'Rx1LOS': - {'offset': 0, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_tx_fault = {'Tx4Fault': - {'offset': 0, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx3Fault': - {'offset': 0, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx2Fault': - {'offset': 0, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx1Fault': - {'offset': 0, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_module_monitor = { - 'TempHighAlarm': - {'offset': 6, - 'bit': 7, - 'type': 'bitvalue'}, - 'TempLowAlarm': - {'offset': 6, - 'bit': 6, - 'type': 'bitvalue'}, - 'TempHighWarning': - {'offset': 6, - 'bit': 5, - 'type': 'bitvalue'}, - 'TempLowWarning': - {'offset': 6, - 'bit': 4, - 'type': 'bitvalue'}, - 'InitCompleteFlag': - {'offset': 6, - 'bit': 0, - 'type': 'bitvalue'}, - 'VccHighAlarm': - {'offset': 7, - 'bit': 7, - 'type': 'bitvalue'}, - 'VccLowAlarm': - {'offset': 7, - 'bit': 6, - 'type': 'bitvalue'}, - 'VccHighWarning': - {'offset': 7, - 'bit': 5, - 'type': 'bitvalue'}, - 'VccLowWarning': - {'offset': 7, - 'bit': 4, - 'type': 'bitvalue'}} - - dom_channel_monitor = { - 'Rx1PowerHighAlarm': - {'offset': 9, - 'bit': 7, - 'type': 'bitvalue'}, - 'Rx1PowerLowAlarm': - {'offset': 9, - 'bit': 6, - 'type': 'bitvalue'}, - 'Rx1PowerHighWarning': - {'offset': 9, - 'bit': 5, - 'type': 'bitvalue'}, - 'Rx1PowerLowWarning': - {'offset': 9, - 'bit': 4, - 'type': 'bitvalue'}, - 'Rx2PowerHighAlarm': - {'offset': 9, - 'bit': 3, - 'type': 'bitvalue'}, - 'Rx2PowerLowAlarm': - {'offset': 9, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx2PowerHighWarning': - {'offset': 9, - 'bit': 1, - 'type': 'bitvalue'}, - 'Rx2PowerLowWarning': - {'offset': 9, - 'bit': 0, - 'type': 'bitvalue'}, - 'Rx3PowerHighAlarm': - {'offset': 10, - 'bit': 7, - 'type': 'bitvalue'}, - 'Rx3PowerLowAlarm': - {'offset': 10, - 'bit': 6, - 'type': 'bitvalue'}, - 'Rx3PowerHighWarning': - {'offset': 10, - 'bit': 5, - 'type': 'bitvalue'}, - 'Rx3PowerLowWarning': - {'offset': 10, - 'bit': 4, - 'type': 'bitvalue'}, - 'Rx4PowerHighAlarm': - {'offset': 10, - 'bit': 3, - 'type': 'bitvalue'}, - 'Rx4PowerLowAlarm': - {'offset': 10, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx4PowerHighWarning': - {'offset': 10, - 'bit': 1, - 'type': 'bitvalue'}, - 'Rx4PowerLowWarning': - {'offset': 10, - 'bit': 0, - 'type': 'bitvalue'}, - 'Tx1BiasHighAlarm': - {'offset': 11, - 'bit': 7, - 'type': 'bitvalue'}, - 'Tx1BiasLowAlarm': - {'offset': 11, - 'bit': 6, - 'type': 'bitvalue'}, - 'Tx1BiasHighWarning': - {'offset': 11, - 'bit': 5, - 'type': 'bitvalue'}, - 'Tx1BiasLowWarning': - {'offset': 11, - 'bit': 4, - 'type': 'bitvalue'}, - 'Tx2BiasHighAlarm': - {'offset': 11, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx2BiasLowAlarm': - {'offset': 11, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx2BiasHighWarning': - {'offset': 11, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx2BiasLowWarning': - {'offset': 11, - 'bit': 0, - 'type': 'bitvalue'}, - 'Tx3BiasHighAlarm': - {'offset': 12, - 'bit': 7, - 'type': 'bitvalue'}, - 'Tx3BiasLowAlarm': - {'offset': 12, - 'bit': 6, - 'type': 'bitvalue'}, - 'Tx3BiasHighWarning': - {'offset': 12, - 'bit': 5, - 'type': 'bitvalue'}, - 'Tx3BiasLowWarning': - {'offset': 12, - 'bit': 4, - 'type': 'bitvalue'}, - 'Tx4BiasHighAlarm': - {'offset': 12, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx4BiasLowAlarm': - {'offset': 12, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx4BiasHighWarning': - {'offset': 12, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx4BiasLowWarning': - {'offset': 12, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_module_monitor_values = { - 'Temperature': - {'offset':22, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'Vcc': - {'offset':26, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}} - - dom_channel_monitor_values = { - 'RX1Power': - {'offset':34, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RX2Power': - {'offset':36, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RX3Power': - {'offset':38, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RX4Power': - {'offset':40, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'TX1Bias': - {'offset':42, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TX2Bias': - {'offset':44, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TX3Bias': - {'offset':46, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TX4Bias': - {'offset':48, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}} - - dom_map = { - 'ModuleMonitorValues': - {'offset': 7, - 'size': 2, - 'type': 'nested', - 'decode': dom_module_monitor_values}, - 'ChannelMonitorValues': - {'offset': 10, - 'size': 2, - 'type': 'nested', - 'decode': dom_channel_monitor_values}} - -# new added parser for some specific values interested by SNMP -# TO DO: find a way to reuse the definitions in above code, need refactor - revision_compliance = { - '00': 'Revision not specified', - '01': 'SFF-8436 Rev 4.8', - '02': 'SFF-8436 Rev 4.8 with extra bytes support', - '03': 'SFF-8636 Rev 1.3', - '04': 'SFF-8636 Rev 1.4', - '05': 'SFF-8636 Rev 1.5', - '06': 'SFF-8636 Rev 2.0', - '07': 'SFF-8636 Rev 2.5' - } - - sfp_dom_rev = { - 'dom_rev': - {'offset': 0, - 'size': 1, - 'type': 'enum', - 'decode': revision_compliance} - } - - dom_module_temperature = { - 'Temperature': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_temperature}} - } - - dom_module_voltage = { - 'Vcc': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_voltage}} - } - - dom_channel_monitor_params = { - 'RX1Power': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX2Power': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX3Power': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX4Power': - {'offset': 6, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'TX1Bias': - {'offset': 8, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX2Bias': - {'offset': 10, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX3Bias': - {'offset': 12, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX4Bias': - {'offset': 14, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}} - } - - dom_channel_monitor_params_with_tx_power = { - 'RX1Power': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX2Power': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX3Power': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'RX4Power': - {'offset': 6, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}}, - 'TX1Bias': - {'offset': 8, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX2Bias': - {'offset': 10, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX3Bias': - {'offset': 12, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX4Bias': - {'offset': 14, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TX1Power': - {'offset': 16, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX2Power': - {'offset': 18, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX3Power': - {'offset': 20, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'TX4Power': - {'offset': 22, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}} - } - - dom_module_threshold_values = { - 'TempHighAlarm': - {'offset':0, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempLowAlarm': - {'offset':2, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempHighWarning': - {'offset':4, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempLowWarning': - {'offset':6, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'VccHighAlarm': - {'offset':16, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VccLowAlarm': - {'offset':18, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VccHighWarning': - {'offset':20, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VccLowWarning': - {'offset':22, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}} - - dom_channel_threshold_values = { - 'RxPowerHighAlarm': - {'offset':0, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RxPowerLowAlarm': - {'offset':2, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RxPowerHighWarning': - {'offset':4, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RxPowerLowWarning': - {'offset':6, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'TxBiasHighAlarm': - {'offset':8, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxBiasLowAlarm': - {'offset':10, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxBiasHighWarning': - {'offset':12, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxBiasLowWarning': - {'offset':14, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TxPowerHighAlarm': - {'offset':16, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'TxPowerLowAlarm': - {'offset':18, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'TxPowerHighWarning': - {'offset':20, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'TxPowerLowWarning': - {'offset':22, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}} - - dom_channel_monitor_masks = { - 'Rx1PowerHighAlarm': - {'offset':0, - 'bit': 7, - 'type': 'bitvalue'}, - 'Rx1PowerLowAlarm': - {'offset':0, - 'bit': 6, - 'type': 'bitvalue'}, - 'Rx1PowerHighWarning': - {'offset':0, - 'bit': 5, - 'type': 'bitvalue'}, - 'Rx1PowerLowWarning': - {'offset':0, - 'bit': 4, - 'type': 'bitvalue'}, - 'Rx2PowerHighAlarm': - {'offset':0, - 'bit': 3, - 'type': 'bitvalue'}, - 'Rx2PowerLowAlarm': - {'offset':0, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx2PowerHighWarning': - {'offset':0, - 'bit': 1, - 'type': 'bitvalue'}, - 'Rx2PowerLowWarning': - {'offset':0, - 'bit': 0, - 'type': 'bitvalue'}, - 'Rx3PowerHighAlarm': - {'offset':1, - 'bit': 7, - 'type': 'bitvalue'}, - 'Rx3PowerLowAlarm': - {'offset':1, - 'bit': 6, - 'type': 'bitvalue'}, - 'Rx3PowerHighWarning': - {'offset':1, - 'bit': 5, - 'type': 'bitvalue'}, - 'Rx3PowerLowWarning': - {'offset':1, - 'bit': 4, - 'type': 'bitvalue'}, - 'Rx4PowerHighAlarm': - {'offset':1, - 'bit': 3, - 'type': 'bitvalue'}, - 'Rx4PowerLowAlarm': - {'offset':1, - 'bit': 2, - 'type': 'bitvalue'}, - 'Rx4PowerHighWarning': - {'offset':1, - 'bit': 1, - 'type': 'bitvalue'}, - 'Rx4PowerLowWarning': - {'offset':1, - 'bit': 0, - 'type': 'bitvalue'}, - 'Tx1BiasHighAlarm': - {'offset':2, - 'bit': 7, - 'type': 'bitvalue'}, - 'Tx1BiasLowAlarm': - {'offset':2, - 'bit': 6, - 'type': 'bitvalue'}, - 'Tx1BiasHighWarning': - {'offset':2, - 'bit': 5, - 'type': 'bitvalue'}, - 'Tx1BiasLowWarning': - {'offset':2, - 'bit': 4, - 'type': 'bitvalue'}, - 'Tx2BiasHighAlarm': - {'offset':2, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx2BiasLowAlarm': - {'offset':2, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx2BiasHighWarning': - {'offset':2, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx2BiasLowWarning': - {'offset':2, - 'bit': 0, - 'type': 'bitvalue'}, - 'Tx3BiasHighAlarm': - {'offset':3, - 'bit': 7, - 'type': 'bitvalue'}, - 'Tx3BiasLowAlarm': - {'offset':3, - 'bit': 6, - 'type': 'bitvalue'}, - 'Tx3BiasHighWarning': - {'offset': 3, - 'bit': 5, - 'type': 'bitvalue'}, - 'Tx3BiasLowWarning': - {'offset': 3, - 'bit': 4, - 'type': 'bitvalue'}, - 'Tx4BiasHighAlarm': - {'offset': 3, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx4BiasLowAlarm': - {'offset': 3, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx4BiasHighWarning': - {'offset': 3, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx4BiasLowWarning': - {'offset': 3, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_tx_disable = { - 'Tx4Disable': - {'offset':0, - 'bit': 3, - 'type': 'bitvalue'}, - 'Tx3Disable': - {'offset':0, - 'bit': 2, - 'type': 'bitvalue'}, - 'Tx2Disable': - {'offset':0, - 'bit': 1, - 'type': 'bitvalue'}, - 'Tx1Disable': - {'offset':0, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_power_control = { - 'PowerSet': - {'offset': 0, - 'bit': 1, - 'type': 'bitvalue'}, - 'PowerOverRide': - {'offset': 0, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_threshold_map = { - 'ChannelThresholdValues': - {'offset': 11, - 'size': 2, - 'type': 'nested', - 'decode': dom_channel_threshold_values}, - 'ChannelMonitorMasks': - {'offset': 12, - 'size': 2, - 'type': 'nested', - 'decode': dom_channel_monitor_masks}, - 'ModuleThresholdValues': - {'offset': 13, - 'size': 2, - 'type': 'nested', - 'decode': dom_module_threshold_values}} - - dom_control_bytes_masks = { - 'TX4Disable': - {'offset': 0, - 'bit': 3, - 'type': 'bitvalue'}, - 'TX3Disable': - {'offset': 0, - 'bit': 2, - 'type': 'bitvalue'}, - 'TX2Disable': - {'offset': 0, - 'bit': 1, - 'type': 'bitvalue'}, - 'TX1Disable': - {'offset': 0, - 'bit': 0, - 'type': 'bitvalue'}, - # RxXRateSelect & Tx4RateSelect are not supported yet. - 'Rx4AppSelect': - {'offset': 3, - 'size': 1, - 'type': 'int'}, - 'Rx3AppSelect': - {'offset': 4, - 'size': 1, - 'type': 'int'}, - 'Rx2AppSelect': - {'offset': 5, - 'size': 1, - 'type': 'int'}, - 'Rx1AppSelect': - {'offset': 6, - 'size': 1, - 'type': 'int'}, - 'PowerSet': - {'offset': 7, - 'bit': 1, - 'type': 'bitvalue'}, - 'PowerOverride': - {'offset': 7, - 'bit': 0, - 'type': 'bitvalue'}, - } - - #SFF8436 Table 39, Option Values (Address 192-195) (Page 00) - #each field indicates whether that feature is supported on this module - dom_option_value_masks = { - 'RXOutputAmplitudeProgramming': - {'offset': 1, - 'bit': 0, - 'type': 'bitvalue'}, - 'RxSquelchDisable': - {'offset': 2, - 'bit': 3, - 'type': 'bitvalue'}, - 'RxOutputDisableCapable': - {'offset': 2, - 'bit': 2, - 'type': 'bitvalue'}, - 'TxSquelchDisable': - {'offset': 2, - 'bit': 1, - 'type': 'bitvalue'}, - 'TxSquelch': - {'offset': 2, - 'bit': 0, - 'type': 'bitvalue'}, - 'MemoryPage02Provided': - {'offset': 3, - 'bit': 7, - 'type': 'bitvalue'}, - 'MemoryPage01Provided': - {'offset': 3, - 'bit': 6, - 'type': 'bitvalue'}, - 'RATE_SELECT': - {'offset': 3, - 'bit': 5, - 'type': 'bitvalue'}, - 'TxDisable': - {'offset': 3, - 'bit': 4, - 'type': 'bitvalue'}, - 'TxFault': - {'offset': 3, - 'bit': 3, - 'type': 'bitvalue'}, - 'TxSquelch_OMA_or_ReducePave': - {'offset': 3, - 'bit': 2, - 'type': 'bitvalue'}, - 'TxLOS': - {'offset': 3, - 'bit': 1, - 'type': 'bitvalue'}, - } - - - def __init__(self, eeprom_raw_data=None, calibration_type=1): - self._calibration_type = calibration_type - start_pos = 0 - - if eeprom_raw_data != None: - self.dom_data = sffbase.parse(self, self.dom_map, - eeprom_raw_data, start_pos) - - def parse(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_map, eeprom_raw_data, - start_pos) - -# Parser functions for specific values interested by SNMP - def parse_sfp_dom_rev(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_dom_rev, type_raw_data, start_pos) - - def parse_temperature(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_temperature, eeprom_raw_data, - start_pos) - - def parse_voltage(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_voltage, eeprom_raw_data, - start_pos) - - def parse_channel_monitor_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_monitor_params, eeprom_raw_data, - start_pos) - - def parse_channel_monitor_params_with_tx_power(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_monitor_params_with_tx_power, eeprom_raw_data, - start_pos) - - def parse_module_threshold_values(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_threshold_values, eeprom_raw_data, - start_pos) - - def parse_channel_threshold_values(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_threshold_values, eeprom_raw_data, - start_pos) - - def parse_channel_monitor_mask(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_monitor_masks, eeprom_raw_data, - start_pos) - - def parse_control_bytes(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_control_bytes_masks, eeprom_raw_data, start_pos) - - def parse_module_monitor_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_monitor, eeprom_raw_data, - start_pos) - - def parse_option_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_option_value_masks, eeprom_raw_data, - start_pos) - - def parse_dom_status_indicator(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_status_indicator, eeprom_raw_data, - start_pos) - - def parse_dom_channel_status(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_status, eeprom_raw_data, - start_pos) - - def parse_dom_tx_rx_los(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_rx_los, eeprom_raw_data, - start_pos) - - def parse_dom_tx_fault(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_fault, eeprom_raw_data, - start_pos) - - def parse_dom_tx_disable (self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_tx_disable, eeprom_raw_data, - start_pos) - - def parse_dom_power_control(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_power_control, eeprom_raw_data, - start_pos) - - def dump_pretty(self): - if self.dom_data == None: - print('Object not initialized, nothing to print') - return - sffbase.dump_pretty(self, self.dom_data) - - def get_data(self): - return self.dom_data - - def get_data_pretty(self): - return sffbase.get_data_pretty(self, self.dom_data) diff --git a/sonic_platform_base/sonic_sfp/sff8472.py b/sonic_platform_base/sonic_sfp/sff8472.py deleted file mode 100644 index 46e0b318c..000000000 --- a/sonic_platform_base/sonic_sfp/sff8472.py +++ /dev/null @@ -1,1320 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright 2012 Cumulus Networks, inc all rights reserved -# -#-------------------------------------------------------------------------- - -from __future__ import print_function - -try: - import fcntl - import struct - import sys - import time - import os - import getopt - import types - from math import log10 - from .sff8024 import type_of_transceiver # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8024 import type_abbrv_name # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sffbase import sffbase # Dot module supports both Python 2 and Python 3 using explicit relative import methods -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -#------------------------------------------------------------------------------ - -class sff8472InterfaceId(sffbase): - """Parser and interpreter for Two wire Interface ID Data fields - - Address A0h - - Base types: - XXX - Complete documentation - - outtype - can be used to dictate the type of output you get - Mainly used with bitmap type. - if outtype == 'allbits': - parse gives all bitnames with values - if outtype == 'onbits': - parse gives all onbits with value = None - """ - - version = '1.0' - - transceiver_codes = { '10GEthernetComplianceCode': - {'offset':3, - 'size':1, - 'type' : 'bitmap', - 'decode' : {'10G Base-ER': - {'offset': 3, - 'bit': 7}, - '10G Base-LRM': - {'offset': 3, - 'bit': 6}, - '10G Base-LR': - {'offset': 3, - 'bit': 5}, - '10G Base-SR': - {'offset': 3, - 'bit': 4}}}, - 'InfinibandComplianceCode': - {'offset':3, - 'size':1, - 'type' : 'bitmap', - 'decode' : {'1X SX': - {'offset': 3, - 'bit': 3}, - '1X LX': - {'offset': 3, - 'bit': 2}, - '1X Copper Active': - {'offset': 3, - 'bit': 1}, - '1X Copper Passive': - {'offset': 3, - 'bit': 0}}}, - 'ESCONComplianceCodes': - {'offset':4, - 'size':1, - 'type' : 'bitmap', - 'decode' : {'ESCON MMF, 1310nm LED': - {'offset': 4, - 'bit': 7}, - 'ESCON SMF, 1310nm Laser': - {'offset': 4, - 'bit': 6}}}, - 'SONETComplianceCodes': - {'offset': 4, - 'size':2, - 'type' : 'bitmap', - 'decode' : { 'OC-192, short reach': - {'offset': 4, - 'bit': 5}, - 'SONET reach specifier bit 1': - {'offset': 4, - 'bit': 4}, - 'SONET reach specifier bit 2': - {'offset': 4, - 'bit': 3}, - 'OC-48, long reach': - {'offset': 4, - 'bit': 2}, - 'OC-48, intermediate reach': - {'offset': 4, - 'bit': 1}, - 'OC-48, short reach': - {'offset': 4, - 'bit': 0}, - 'OC-12, single mode, long reach': - {'offset': 5, - 'bit': 6}, - 'OC-12, single mode, inter reach': - {'offset': 5, - 'bit': 5}, - 'OC-12, short reach': - {'offset': 5, - 'bit': 4}, - 'OC-3, single mode, long reach': - {'offset': 5, - 'bit': 2}, - 'OC-3, single mode, inter reach': - {'offset': 5, - 'bit': 1}, - 'OC-3, short reach': - {'offset': 5, - 'bit': 0}}}, - 'EthernetComplianceCodes': - {'offset': 6, - 'size':2, - 'type' : 'bitmap', - 'decode' : { - 'BASE-PX': - {'offset': 6, - 'bit': 7}, - 'BASE-BX10': - {'offset': 6, - 'bit': 6}, - '100BASE-FX': - {'offset': 6, - 'bit': 5}, - '100BASE-LX/LX10': - {'offset': 6, - 'bit': 4}, - '1000BASE-T': - {'offset': 6, - 'bit': 3}, - '1000BASE-CX': - {'offset': 6, - 'bit': 2}, - '1000BASE-LX': - {'offset': 6, - 'bit': 1}, - '1000BASE-SX': - {'offset': 6, - 'bit': 0}}}, - 'FibreChannelLinkLength': - {'offset': 7, - 'size':2, - 'type' : 'bitmap', - 'decode' : - {'very long distance (V)': - {'offset': 7, - 'bit': 7}, - 'short distance (S)': - {'offset': 7, - 'bit': 6}, - 'Intermediate distance (I)': - {'offset': 7, - 'bit': 5}, - 'Long distance (L)': - {'offset': 7, - 'bit': 4}, - 'medium distance (M)': - {'offset': 7, - 'bit': 3}}}, - 'FibreChannelTechnology': - {'offset': 7, - 'size':2, - 'type' : 'bitmap', - 'decode' : - {'Shortwave laser, linear Rx (SA)': - {'offset': 7, - 'bit': 2}, - 'Longwave Laser (LC)': - {'offset': 7, - 'bit': 1}, - 'Electrical inter-enclosure (EL)': - {'offset': 7, - 'bit': 0}, - 'Electrical intra-enclosure (EL)': - {'offset': 8, - 'bit': 7}, - 'Shortwave laser w/o OFC (SN)': - {'offset': 8, - 'bit': 6}, - 'Shortwave laser with OFC (SL)': - {'offset': 8, - 'bit': 5}, - 'Longwave laser (LL)': - {'offset': 8, - 'bit': 4}}}, - 'SFP+CableTechnology': - {'offset': 7, - 'size':2, - 'type' : 'bitmap', - 'decode' : - {'Active Cable': - {'offset': 8, - 'bit': 3}, - 'Passive Cable': - {'offset': 8, - 'bit': 2}}}, - 'FibreChannelTransmissionMedia': - {'offset': 7, - 'size':2, - 'type' : 'bitmap', - 'decode' : - {'Twin Axial Pair (TW)': - {'offset': 9, - 'bit': 7}, - 'Twisted Pair (TP)': - {'offset': 9, - 'bit': 6}, - 'Miniature Coax (MI)': - {'offset': 9, - 'bit': 5}, - 'Video Coax (TV)': - {'offset': 9, - 'bit': 4}, - 'Multimode, 62.5um (M6)': - {'offset': 9, - 'bit': 3}, - 'Multimode, 50um (M5, M5E)': - {'offset': 9, - 'bit': 2}, - 'Single Mode (SM)': - {'offset': 9, - 'bit': 0}}}, - 'FibreChannelSpeed': - {'offset': 7, - 'size':2, - 'type': 'bitmap', - 'decode' : - {'1200 MBytes/sec': - {'offset': 10, - 'bit': 7}, - '800 MBytes/sec': - {'offset': 10, - 'bit': 6}, - '1600 MBytes/sec': - {'offset': 10, - 'bit': 5}, - '400 MBytes/sec': - {'offset': 10, - 'bit': 4}, - '200 MBytes/sec': - {'offset': 10, - 'bit': 2}, - '100 MBytes/sec': - {'offset': 10, - 'bit': 0}}}} - - exttypeoftransceiver = {'00': 'GBIC def not specified', - '01':'GBIC is compliant with MOD_DEF 1', - '02':'GBIC is compliant with MOD_DEF 2', - '03':'GBIC is compliant with MOD_DEF 3', - '04':'GBIC/SFP defined by twowire interface ID', - '05':'GBIC is compliant with MOD_DEF 5', - '06':'GBIC is compliant with MOD_DEF 6', - '07':'GBIC is compliant with MOD_DEF 7'} - - connector = {'00': 'Unknown', - '01': 'SC', - '02': 'Fibre Channel Style 1 copper connector', - '03': 'Fibre Channel Style 2 copper connector', - '04': 'BNC/TNC', - '05': 'Fibre Channel coaxial headers', - '06': 'FibreJack', - '07': 'LC', - '08': 'MT-RJ', - '09': 'MU', - '0a': 'SG', - '0b': 'Optical pigtail', - '0c': 'MPO Parallel Optic', - '20': 'HSSDCII', - '21': 'CopperPigtail', - '22': 'RJ45'} - - encoding_codes = {'00':'Unspecified', - '01':'8B/10B', - '02':'4B/5B', - '03':'NRZ', - '04':'Manchester', - '05': 'SONET Scrambled', - '06':'64B/66B'} - - rate_identifier = {'00':'Unspecified', - '01':'Defined for SFF-8079 (4/2/1G Rate_Select & AS0/AS1)', - '02': 'Defined for SFF-8431 (8/4/2G Rx Rate_Select only)', - '03':'Unspecified', - '04': 'Defined for SFF-8431 (8/4/2G Tx Rate_Select only)', - '05':'Unspecified', - '06':'Defined for SFF-8431 (8/4/2G Independent Rx & Tx Rate_select)', - '07':'Unspecified', - '08': 'Defined for FC-PI-5 (16/8/4G Rx Rate_select only) High=16G only, Low=8G/4G', - '09': 'Unspecified', - '0a': 'Defined for FC-PI-5 (16/8/4G Independent Rx, Tx Rate_select) High=16G only, Low=8G/4G'} - - - interface_id = {'TypeOfTransceiver': - {'offset':0, - 'size':1, - 'type' : 'enum', - 'decode' : type_of_transceiver}, - 'ExtIdentOfTypeOfTransceiver': - {'offset':1, - 'size':1, - 'type' : 'enum', - 'outlevel' : 2, - 'decode': exttypeoftransceiver}, - 'Connector': - {'offset':2, - 'size':1, - 'type' : 'enum', - 'decode': connector}, - 'EncodingCodes': - {'offset':11, - 'size':1, - 'type' : 'enum', - 'decode' : encoding_codes}, - 'VendorName': - {'offset' : 20, - 'size' : 16, - 'type' : 'str'}, - 'VendorOUI': - {'offset':37, - 'size':3, - 'type' : 'hex'}, - 'VendorPN': - {'offset':40, - 'size':16, - 'type' : 'str'}, - 'VendorSN': - {'offset':68, - 'size':16, - 'type' : 'str'}, - 'VendorRev': - {'offset':56, - 'size':4, - 'type' : 'str'}, - 'CalibrationType': - {'offset':92, - 'size':1, - 'type' : 'bitmap', - 'short_name' : 'calType', - 'decode' : {'Internally Calibrated': - {'offset': 92, - 'bit':5}, - 'Externally Calibrated': - {'offset': 92, - 'bit':4}, - }}, - 'ReceivedPowerMeasurementType': - {'offset':92, - 'size':1, - 'type' : 'bitmap', - 'decode' : {'Avg power': - {'offset': 92, - 'bit':3}, - 'OMA': - {'offset': 92, - 'bit':3, - 'value':0}}}, - 'RateIdentifier': - {'offset':13, - 'size':1, - 'type' : 'enum', - 'decode' : rate_identifier}, - 'TransceiverCodes': - {'offset' : 3, - 'type' : 'nested', - 'decode' : transceiver_codes}, - 'NominalSignallingRate(UnitsOf100Mbd)': - {'offset': 12, - 'size':1, - 'type':'int'}, - 'LengthSMFkm-UnitsOfKm': - {'offset':14, - 'size':1, - 'type':'int'}, - 'LengthSMF(UnitsOf100m)': - {'offset':15, - 'size':1, - 'type':'int'}, - 'Length50um(UnitsOf10m)': - {'offset':16, - 'size':1, - 'type':'int'}, - 'Length62.5um(UnitsOfm)': - {'offset':17, - 'size':1, - 'type':'int'}, - 'LengthCable(UnitsOfm)': - {'offset':18, - 'size':1, - 'type':'int'}, - 'LengthOM3(UnitsOf10m)': - {'offset':19, - 'size':1, - 'type':'int'}, - 'VendorDataCode(YYYY-MM-DD Lot)': - {'offset':84, - 'size':8, - 'type': 'date'}} - -# Parser for specific values that interested by SNMP - - sfp_info_bulk = {'type': - {'offset':0, - 'size':1, - 'type' : 'enum', - 'decode' : type_of_transceiver}, - 'type_abbrv_name': - {'offset':0, - 'size':1, - 'type' : 'enum', - 'decode' : type_abbrv_name}, - 'Extended Identifier': - {'offset':1, - 'size':1, - 'type' : 'enum', - 'decode': exttypeoftransceiver}, - 'Connector': - {'offset':2, - 'size':1, - 'type' : 'enum', - 'decode': connector}, - 'Specification compliance': - {'offset' : 3, - 'type' : 'nested', - 'decode' : transceiver_codes}, - 'EncodingCodes': - {'offset':11, - 'size':1, - 'type' : 'enum', - 'decode' : encoding_codes}, - 'NominalSignallingRate(UnitsOf100Mbd)': - {'offset': 12, - 'size':1, - 'type':'int'}, - 'RateIdentifier': - {'offset':13, - 'size':1, - 'type' : 'enum', - 'decode' : rate_identifier}, - 'LengthSMFkm-UnitsOfKm': - {'offset':14, - 'size':1, - 'type':'int'}, - 'LengthSMF(UnitsOf100m)': - {'offset':15, - 'size':1, - 'type':'int'}, - 'Length50um(UnitsOf10m)': - {'offset':16, - 'size':1, - 'type':'int'}, - 'Length62.5um(UnitsOfm)': - {'offset':17, - 'size':1, - 'type':'int'}, - 'LengthCable(UnitsOfm)': - {'offset':18, - 'size':1, - 'type':'int'}, - 'LengthOM3(UnitsOf10m)': - {'offset':19, - 'size':1, - 'type':'int'} - } - - vendor_name = { - 'Vendor Name': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_pn = { - 'Vendor PN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_rev = { - 'Vendor Rev': - {'offset': 0, - 'size': 4, - 'type': 'str'} - } - - vendor_sn = { - 'Vendor SN': - {'offset': 0, - 'size': 16, - 'type': 'str'} - } - - vendor_oui = { - 'Vendor OUI': - {'offset':0, - 'size':3, - 'type' : 'hex'} - } - - vendor_date = { - 'VendorDataCode(YYYY-MM-DD Lot)': - {'offset':0, - 'size':8, - 'type': 'date'} - } - - sfp_dom_capability = { - 'sff8472_dom_support': - {'offset': 0, - 'bit': 6, - 'type': 'bitvalue'} - } - - # Returns calibration type - def _get_calibration_type(self, eeprom_data): - try: - data = int(eeprom_data[92], 16) - if self.test_bit(data, 5) != 0: - return 1 # internally calibrated - elif self.test_bit(data, 4) != 0: - return 2 # externally calibrated - else: - return 0 # Could not find calibration type - except Exception: - return 0 - - def __init__(self, eeprom_raw_data=None): - self.interface_data = None - start_pos = 0 - - if eeprom_raw_data != None: - self.interface_data = sffbase.parse(self, - self.interface_id, - eeprom_raw_data, start_pos) - self.calibration_type = self._get_calibration_type( - eeprom_raw_data) - - def parse(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.interface_id, eeprom_raw_data, start_pos) - -#new parser functions for specific values that interested by SNMP - def parse_sfp_info_bulk(self, type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_info_bulk, type_raw_data, start_pos) - - def parse_vendor_name(self, name_raw_data, start_pos): - return sffbase.parse(self, self.vendor_name, name_raw_data, start_pos) - - def parse_vendor_rev(self, rev_raw_data, start_pos): - return sffbase.parse(self, self.vendor_rev, rev_raw_data, start_pos) - - def parse_vendor_pn(self, pn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_pn, pn_raw_data, start_pos) - - def parse_vendor_sn(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_sn, sn_raw_data, start_pos) - - def parse_vendor_date(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_date, sn_raw_data, start_pos) - - def parse_vendor_oui(self, sn_raw_data, start_pos): - return sffbase.parse(self, self.vendor_oui, sn_raw_data, start_pos) - - def parse_dom_capability(self, dom_type_raw_data, start_pos): - return sffbase.parse(self, self.sfp_dom_capability, dom_type_raw_data, start_pos) - - def dump_pretty(self): - if self.interface_data == None: - print('Object not initialized, nothing to print') - return - sffbase.dump_pretty(self, self.interface_data) - - def get_calibration_type(self): - return self.calibration_type - - def get_data(self): - return self.interface_data - - def get_data_pretty(self): - return sffbase.get_data_pretty(self, self.interface_data) - -class sff8472Dom(sffbase): - """Parser and interpretor for Diagnostics data fields at address A2h""" - - version = '1.0' - - dom_ext_calibration_constants = {'RX_PWR_4': - {'offset':56, - 'size':4}, - 'RX_PWR_3': - {'offset':60, - 'size':4}, - 'RX_PWR_2': - {'offset':64, - 'size':4}, - 'RX_PWR_1': - {'offset':68, - 'size':4}, - 'RX_PWR_0': - {'offset':72, - 'size':4}, - 'TX_I_Slope': - {'offset':76, - 'size':2}, - 'TX_I_Offset': - {'offset':78, - 'size':2}, - 'TX_PWR_Slope': - {'offset':80, - 'size':2}, - 'TX_PWR_Offset': - {'offset':82, - 'size':2}, - 'T_Slope': - {'offset':84, - 'size':2}, - 'T_Offset': - {'offset':86, - 'size':2}, - 'V_Slope': - {'offset':88, - 'size':2}, - 'V_Offset': - {'offset':90, - 'size':2}} - - - def get_calibration_type(self): - return self._calibration_type - - def calc_temperature(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - - result = (msb << 8) | (lsb & 0xff) - result = self.twos_comp(result, 16) - - if cal_type == 1: - - # Internal calibration - - result = float(result / 256.0) - retval = '%.4f' %result + 'C' - elif cal_type == 2: - - # External calibration - - # T(C) = T_Slope * T_AD + T_Offset - off = self.dom_ext_calibration_constants['T_Slope']['offset'] - msb_t = int(eeprom_data[off], 16) - lsb_t = int(eeprom_data[off + 1], 16) - t_slope = (msb_t << 8) | (lsb_t & 0xff) - - off = self.dom_ext_calibration_constants['T_Offset']['offset'] - msb_t = int(eeprom_data[off], 16) - lsb_t = int(eeprom_data[off + 1], 16) - t_offset = (msb_t << 8) | (lsb_t & 0xff) - t_offset = self.twos_comp(t_offset, 16) - - result = t_slope * result + t_offset - result = float(result / 256.0) - retval = '%.4f' %result + 'C' - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_voltage(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - - # Internal Calibration - - result = float(result * 0.0001) - #print(indent, name, ' : %.4f' %result, 'Volts') - retval = '%.4f' %result + 'Volts' - elif cal_type == 2: - - # External Calibration - - # V(uV) = V_Slope * VAD + V_Offset - off = self.dom_ext_calibration_constants['V_Slope']['offset'] - msb_v = int(eeprom_data[off], 16) - lsb_v = int(eeprom_data[off + 1], 16) - v_slope = (msb_v << 8) | (lsb_v & 0xff) - - off = self.dom_ext_calibration_constants['V_Offset']['offset'] - msb_v = int(eeprom_data[off], 16) - lsb_v = int(eeprom_data[off + 1], 16) - v_offset = (msb_v << 8) | (lsb_v & 0xff) - v_offset = self.twos_comp(v_offset, 16) - - result = v_slope * result + v_offset - result = float(result * 0.0001) - #print(indent, name, ' : %.4f' %result, 'Volts') - retval = '%.4f' %result + 'Volts' - else: - #print(indent, name, ' : Unknown') - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_bias(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - # Internal Calibration - - result = float(result * 0.002) - #print(indent, name, ' : %.4f' %result, 'mA') - retval = '%.4f' %result + 'mA' - - elif cal_type == 2: - # External Calibration - - # I(uA) = I_Slope * I_AD + I_Offset - off = self.dom_ext_calibration_constants['I_Slope']['offset'] - msb_i = int(eeprom_data[off], 16) - lsb_i = int(eeprom_data[off + 1], 16) - i_slope = (msb_i << 8) | (lsb_i & 0xff) - - off = self.dom_ext_calibration_constants['I_Offset']['offset'] - msb_i = int(eeprom_data[off], 16) - lsb_i = int(eeprom_data[off + 1], 16) - i_offset = (msb_i << 8) | (lsb_i & 0xff) - i_offset = self.twos_comp(i_offset, 16) - - result = i_slope * result + i_offset - result = float(result * 0.002) - #print(indent, name, ' : %.4f' %result, 'mA') - retval = '%.4f' %result + 'mA' - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - def calc_tx_power(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - - result = float(result * 0.0001) - #print(indent, name, ' : ', power_in_dbm_str(result)) - retval = self.power_in_dbm_str(result) - - elif cal_type == 2: - - # TX_PWR(uW) = TX_PWR_Slope * TX_PWR_AD + TX_PWR_Offset - off = self.dom_ext_calibration_constants['TX_PWR_Slope']['offset'] - msb_tx_pwr = int(eeprom_data[off], 16) - lsb_tx_pwr = int(eeprom_data[off + 1], 16) - tx_pwr_slope = (msb_tx_pwr << 8) | (lsb_tx_pwr & 0xff) - - off = self.dom_ext_calibration_constants['TX_PWR_Offset']['offset'] - msb_tx_pwr = int(eeprom_data[off], 16) - lsb_tx_pwr = int(eeprom_data[off + 1], 16) - tx_pwr_offset = (msb_tx_pwr << 8) | (lsb_tx_pwr & 0xff) - tx_pwr_offset = self.twos_comp(tx_pwr_offset, 16) - - result = tx_pwr_slope * result + tx_pwr_offset - result = float(result * 0.0001) - retval = self.power_in_dbm_str(result) - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - def calc_rx_power(self, eeprom_data, offset, size): - try: - cal_type = self.get_calibration_type() - - msb = int(eeprom_data[offset], 16) - lsb = int(eeprom_data[offset + 1], 16) - result = (msb << 8) | (lsb & 0xff) - - if cal_type == 1: - - # Internal Calibration - result = float(result * 0.0001) - #print(indent, name, " : ", power_in_dbm_str(result)) - retval = self.power_in_dbm_str(result) - - elif cal_type == 2: - - # External Calibration - - # RX_PWR(uW) = RX_PWR_4 * RX_PWR_AD + - # RX_PWR_3 * RX_PWR_AD + - # RX_PWR_2 * RX_PWR_AD + - # RX_PWR_1 * RX_PWR_AD + - # RX_PWR(0) - off = self.dom_ext_calibration_constants['RX_PWR_4']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_4 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_3']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_3 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_2']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_2 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_1']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_1 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - off = self.dom_ext_calibration_constants['RX_PWR_0']['offset'] - rx_pwr_byte3 = int(eeprom_data[off], 16) - rx_pwr_byte2 = int(eeprom_data[off + 1], 16) - rx_pwr_byte1 = int(eeprom_data[off + 2], 16) - rx_pwr_byte0 = int(eeprom_data[off + 3], 16) - rx_pwr_0 = (rx_pwr_byte3 << 24) | (rx_pwr_byte2 << 16) | (rx_pwr_byte1 << 8) | (rx_pwr_byte0 & 0xff) - - rx_pwr = (rx_pwr_4 * result) + (rx_pwr_3 * result) + (rx_pwr_2 * result) + (rx_pwr_1 * result) + rx_pwr_0 - - result = float(result * 0.0001) - #print(indent, name, " : ", power_in_dbm_str(result)) - retval = self.power_in_dbm_str(result) - else: - retval = 'Unknown' - except Exception as err: - retval = str(err) - - return retval - - - dom_aw_thresholds = { 'TempHighAlarm': - {'offset':0, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempLowAlarm': - {'offset':2, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempHighWarning': - {'offset':4, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'TempLowWarning': - {'offset':6, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'VoltageHighAlarm': - {'offset':8, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VoltageLowAlarm': - {'offset':10, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VoltageHighWarning': - {'offset':12, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'VoltageLowWarning': - {'offset':14, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'BiasHighAlarm': - {'offset':16, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'BiasLowAlarm': - {'offset':18, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'BiasHighWarning': - {'offset':20, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'BiasLowWarning': - {'offset':22, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TXPowerHighAlarm': - {'offset':24, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'TXPowerLowAlarm': - {'offset':26, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'TXPowerHighWarning': - {'offset':28, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'TXPowerLowWarning': - {'offset':30, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'RXPowerHighAlarm': - {'offset':32, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RXPowerLowAlarm': - {'offset':34, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RXPowerHighWarning': - {'offset':36, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}, - 'RXPowerLowWarning': - {'offset':38, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}} - - dom_monitor = {'Temperature': - {'offset':96, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_temperature}}, - 'Vcc': - {'offset':98, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_voltage}}, - 'TXBias': - {'offset':100, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_bias}}, - 'TXPower': - {'offset':102, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_tx_power}}, - 'RXPower': - {'offset':104, - 'size':2, - 'type': 'func', - 'decode': { 'func':calc_rx_power}}} - - dom_status_control = { 'TXDisableState': - {'offset': 110, - 'bit': 7, - 'type': 'bitvalue'}, - 'SoftTXDisableSelect': - {'offset': 110, - 'bit': 6, - 'type': 'bitvalue'}, - 'RS1State': - {'offset': 110, - 'bit': 5, - 'type': 'bitvalue'}, - 'RateSelectState': - {'offset': 110, - 'bit': 4, - 'type': 'bitvalue'}, - 'SoftRateSelect': - {'offset': 110, - 'bit': 3, - 'type': 'bitvalue'}, - 'TXFaultState': - {'offset': 110, - 'bit': 2, - 'type': 'bitvalue'}, - 'RXLOSState': - {'offset': 110, - 'bit': 1, - 'type': 'bitvalue'}, - 'DataReadyBarState': - {'offset': 110, - 'bit': 0, - 'type': 'bitvalue'}} - - dom_alarm_flags = {'TempHighAlarm': - {'offset':112, - 'bit':7, - 'type': 'bitvalue'}, - 'TempLowAlarm': - {'offset':112, - 'bit':6, - 'type': 'bitvalue'}, - 'VccHighAlarm': - {'offset':112, - 'bit':5, - 'type': 'bitvalue'}, - 'VccLowAlarm': - {'offset':112, - 'bit':4, - 'type': 'bitvalue'}, - 'TXBiasHighAlarm': - {'offset':112, - 'bit':3, - 'type': 'bitvalue'}, - 'TXBiasLowAlarm': - {'offset':112, - 'bit':2, - 'type': 'bitvalue'}, - 'TXPowerHighAlarm': - {'offset':112, - 'bit':1, - 'type': 'bitvalue'}, - 'TXPowerLowAlarm': - {'offset':112, - 'bit':0, - 'type': 'bitvalue'}, - 'RXPowerHighAlarm': - {'offset':113, - 'bit':7, - 'type': 'bitvalue'}, - 'RXPowerLowAlarm': - {'offset':113, - 'bit':6, - 'type': 'bitvalue'}} - - dom_warning_flags = { 'TempHighWarning': - {'offset':116, - 'bit':7, - 'type': 'bitvalue'}, - 'TempLowWarning': - {'offset':116, - 'bit':6, - 'type': 'bitvalue'}, - 'VccHighWarning': - {'offset':116, - 'bit':5, - 'type': 'bitvalue'}, - 'VccLowWarning': - {'offset':116, - 'bit':4, - 'type': 'bitvalue'}, - 'TXBiasHighWarning': - {'offset':116, - 'bit':3, - 'type': 'bitvalue'}, - 'TXBiasLowWarning': - {'offset':116, - 'bit':2, - 'type': 'bitvalue'}, - 'TXPowerHighWarning': - {'offset':116, - 'bit':1, - 'type': 'bitvalue'}, - 'TXPowerLowWarning': - {'offset':116, - 'bit':0, - 'type': 'bitvalue'}, - 'RXPowerHighWarning': - {'offset':117, - 'bit':7, - 'type': 'bitvalue'}, - 'RXPowerLowWarning': - {'offset':117, - 'bit':6, - 'type': 'bitvalue'}} - - dom_map = {'AwThresholds': - {'offset' : 0, - 'size' : 40, - 'type' : 'nested', - 'decode' : dom_aw_thresholds}, - 'MonitorData': - {'offset':96, - 'size':10, - 'type' : 'nested', - 'decode': dom_monitor}, - 'StatusControl': - {'offset':110, - 'size':1, - 'type' : 'nested', - 'decode':dom_status_control}, - 'AlarmFlagStatus': - {'offset':112, - 'size':2, - 'type' : 'nested', - 'decode':dom_alarm_flags}, - 'WarningFlagStatus': - {'offset':112, - 'size':2, - 'type' : 'nested', - 'decode':dom_warning_flags}} - -# parsers for specific values that interested by SNMP - dom_module_temperature = { - 'Temperature': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_temperature}} - } - - dom_module_voltage = { - 'Vcc': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func':calc_voltage}} - } - - dom_channel_monitor_params = { - 'TXBias': - {'offset': 0, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_bias}}, - 'TXPower': - {'offset': 2, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_tx_power}}, - 'RXPower': - {'offset': 4, - 'size': 2, - 'type': 'func', - 'decode': {'func': calc_rx_power}} - } - dom_module_monitor = { - 'TempHighAlarm': - {'offset':0, - 'bit':7, - 'type': 'bitvalue'}, - 'TempLowAlarm': - {'offset':0, - 'bit':6, - 'type': 'bitvalue'}, - 'TempHighWarning': - {'offset': 4, - 'bit': 7, - 'type': 'bitvalue'}, - 'TempLowWarning': - {'offset': 4, - 'bit': 6, - 'type': 'bitvalue'}, - 'VccHighAlarm': - {'offset': 0, - 'bit': 5, - 'type': 'bitvalue'}, - 'VccLowAlarm': - {'offset': 0, - 'bit': 4, - 'type': 'bitvalue'}, - 'VccHighWarning': - {'offset': 4, - 'bit': 5, - 'type': 'bitvalue'}, - 'VccLowWarning': - {'offset': 4, - 'bit': 4, - 'type': 'bitvalue'}} - - dom_channel_thresh_monitor_params = { - 'BiasHighAlarm': - {'offset':0, - 'bit':3, - 'type': 'bitvalue'}, - 'BiasLowAlarm': - {'offset':0, - 'bit':2, - 'type': 'bitvalue'}, - 'BiasHighWarning': - {'offset':4, - 'bit':3, - 'type': 'bitvalue'}, - 'BiasLowWarning': - {'offset':4, - 'bit':2, - 'type': 'bitvalue'}, - 'TxPowerHighAlarm': - {'offset':0, - 'bit':1, - 'type': 'bitvalue'}, - 'TxPowerLowAlarm': - {'offset':0, - 'bit':0, - 'type': 'bitvalue'}, - 'TxPowerHighWarning': - {'offset':4, - 'bit':1, - 'type': 'bitvalue'}, - 'TxPowerLowWarning': - {'offset':4, - 'bit':0, - 'type': 'bitvalue'}, - 'RxPowerHighAlarm': - {'offset':1, - 'bit':7, - 'type': 'bitvalue'}, - 'RxPowerLowAlarm': - {'offset':1, - 'bit':6, - 'type': 'bitvalue'}, - 'RxPowerHighWarning': - {'offset':5, - 'bit':7, - 'type': 'bitvalue'}, - 'RxPowerLowWarning': - {'offset':5, - 'bit':6, - 'type': 'bitvalue'} - } - - def __init__(self, eeprom_raw_data=None, calibration_type=0): - self._calibration_type = calibration_type - start_pos = 0 - - if eeprom_raw_data != None: - self.dom_data = sffbase.parse(self, self.dom_map, - eeprom_raw_data, start_pos) - - def parse(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_map, eeprom_raw_data, start_pos) - -# parser functions for specific values interested by SNMP - def parse_temperature(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_temperature, eeprom_raw_data, - start_pos) - - def parse_voltage(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_voltage, eeprom_raw_data, - start_pos) - - def parse_channel_monitor_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_monitor_params, eeprom_raw_data, - start_pos) - - def parse_module_monitor_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_module_monitor, eeprom_raw_data, - start_pos) - - def parse_channel_thresh_monitor_params(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_channel_thresh_monitor_params, eeprom_raw_data, - start_pos) - - def parse_alarm_warning_threshold(self, eeprom_raw_data, start_pos): - return sffbase.parse(self, self.dom_aw_thresholds, eeprom_raw_data, - start_pos) - - def dump_pretty(self): - if self.dom_data == None: - print('Object not initialized, nothing to print') - return - sffbase.dump_pretty(self, self.dom_data) - - - def get_data(self): - return self.dom_data - - - def get_data_pretty(self): - return sffbase.get_data_pretty(self, self.dom_data) - diff --git a/sonic_platform_base/sonic_sfp/sffbase.py b/sonic_platform_base/sonic_sfp/sffbase.py deleted file mode 100644 index 35237f8bf..000000000 --- a/sonic_platform_base/sonic_sfp/sffbase.py +++ /dev/null @@ -1,248 +0,0 @@ -#---------------------------------------------------------------------------- -# sffbase class for sff8436 and sff8472 -#---------------------------------------------------------------------------- - - - -try: - import fcntl - import struct - import sys - import time - import binascii - import os - import getopt - import types - from math import log10 -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -class sffbase(object): - """Class to parse and interpret sff8436 and sff8472 spec for - diagnostically monitoring interfaces of optical transceivers""" - - _indent = '\t' - - def inc_indent(self): - self._indent += '\t' - - def dec_indent(self): - self._indent = self._indent[:-1] - - # Convert Hex to String - def convert_hex_to_string(self, arr, start, end): - try: - ret_str = '' - for n in range(start, end): - ret_str += arr[n] - return binascii.unhexlify(ret_str).decode("utf-8", "ignore").strip() - except Exception as err: - return str(err) - - # Convert Date to String - def convert_date_to_string(self, eeprom_data, offset, size): - try: - year_offset = 0 - month_offset = 2 - day_offset = 4 - lot_offset = 6 - - date = self.convert_hex_to_string(eeprom_data, offset, offset + size) - retval = "20"+ date[year_offset:month_offset] + "-" + \ - date[month_offset:day_offset] + "-" + \ - date[day_offset:lot_offset] + " " + \ - date[lot_offset:size] - except Exception as err: - retval = str(err) - return retval - - def test_bit(self, n, bitpos): - try: - mask = 1 << bitpos - if (n & mask) == 0: - return 0 - else: - return 1 - except Exception: - return -1 - - def twos_comp(self, num, bits): - try: - if ((num & (1 << (bits - 1))) != 0): - num = num - (1 << bits) - return num - except Exception: - return 0 - - def mw_to_dbm(self, mW): - if mW == 0: - return float("-inf") - elif mW < 0: - return float("NaN") - return 10. * log10(mW) - - - def power_in_dbm_str(self, mW): - return "%.4f%s" % (self.mw_to_dbm(mW), "dBm") - - # Parse sff base elements - def parse_sff_element(self, eeprom_data, eeprom_ele, start_pos): - value = None - offset = eeprom_ele.get('offset') + start_pos - size = eeprom_ele.get('size') - type = eeprom_ele.get('type') - decode = eeprom_ele.get('decode'); - - if type == 'enum': - # Get the matched value - value = decode.get(str(eeprom_data[offset]), 'Unknown') - - elif type == 'bitmap': - # Get the 'on' bitname - bitvalue_dict = {} - for bitname, bitinfo in sorted(decode.items()): - bitinfo_offset = bitinfo.get('offset') + start_pos - bitinfo_pos = bitinfo.get('bit') - bitinfo_value = bitinfo.get('value') - data = int(eeprom_data[bitinfo_offset], 16) - bit_value = self.test_bit(data, bitinfo_pos) - if bitinfo_value != None: - if bit_value == bitinfo_value: - value = bitname - break - elif bit_value == 1: - value = bitname - break - - elif type == 'bitvalue': - # Get the value of the bit - bitpos = eeprom_ele.get('bit') - data = int(eeprom_data[offset], 16) - bitval = self.test_bit(data, bitpos) - value = ['Off', 'On'][bitval] - - elif type == 'func': - # Call the decode func to get the value - value = decode['func'](self, eeprom_data, - offset, size) - - elif type == 'str': - value = self.convert_hex_to_string(eeprom_data, offset, - offset + size) - - elif type == 'int': - value = int(eeprom_data[offset], 16) - - elif type == 'date': - value = self.convert_date_to_string(eeprom_data, offset, - size) - - elif type == 'hex': - value = '-'.join(eeprom_data[offset:offset+size]) - - return value - - # Recursively parses sff data into dictionary - def parse_sff(self, eeprom_map, eeprom_data, start_pos): - outdict = {} - for name, meta_data in sorted(eeprom_map.items()): - type = meta_data.get('type') - - # Initialize output value - value_dict = {} - value_dict['outtype'] = meta_data.get('outtype') - value_dict['short_name'] = meta_data.get('short_name') - - if type != 'nested': - data = self.parse_sff_element(eeprom_data, - meta_data, start_pos) - else: - nested_map = meta_data.get('decode') - data = self.parse_sff(nested_map, - eeprom_data, start_pos) - - if data != None: - value_dict['value'] = data - outdict[name] = value_dict - - return outdict - - - # Main sff parser function - def parse(self, eeprom_map, eeprom_data, start_pos): - """ Example Return format: - {'version': '1.0', 'data': {'Length50um(UnitsOf10m)': - {'outtype': None, 'value': 8, 'short_name': None}, - 'TransceiverCodes': {'outtype': None, 'value': - {'10GEthernetComplianceCode': {'outtype': None, 'value': - '10G Base-SR', 'short_name': None}}, 'short_name': None}, - 'ExtIdentOfTypeOfTransceiver': {'outtype': None, 'value': - 'GBIC/SFP func defined by two-wire interface ID', 'short_name': - None}, 'Length62.5um(UnitsOfm)': {'outtype': None,""" - - outdict = {} - return_dict = {} - - outdict = self.parse_sff(eeprom_map, eeprom_data, start_pos) - - return_dict['version'] = self.version - return_dict['data'] = outdict - - return return_dict - - - # Returns sff parsed data in a pretty dictionary format - def get_data_pretty_dict(self, indict): - outdict = {} - - for elem, elem_val in sorted(indict.items()): - value = elem_val.get('value') - if type(value) == dict: - outdict[elem] = sffbase.get_data_pretty_dict( - self, value) - else: - outdict[elem] = value - - return outdict - - def get_data_pretty(self, indata): - """Example Return format: - {'version': '1.0', 'data': {'Length50um(UnitsOf10m)': 8, - 'TransceiverCodes': {'10GEthernetComplianceCode': - '10G Base-SR'}, 'ExtIdentOfTypeOfTransceiver': 'GBIC/SFP func - defined by two-wire interface ID', 'Length62.5um(UnitsOfm)': 3, - 'VendorPN': 'FTLX8571D3BNL', 'RateIdentifier': 'Unspecified', - 'NominalSignallingRate(UnitsOf100Mbd)': 103, 'VendorOUI': ..}} - {'version': '1.0', 'data': {'AwThresholds': - {'TXPowerLowWarning': '-5.0004 dBm', 'TempHighWarning': - '88.0000C', 'RXPowerHighAlarm': '0.0000 dBm', - 'TXPowerHighAlarm': '-0.7998 dBm', 'RXPowerLowAlarm': - '-20.0000 dBm', 'RXPowerHighWarning': '-1.0002 dBm', - 'VoltageLowAlarm': '2.9000Volts'""" - - return_dict = {} - - return_dict['version'] = indata.get('version') - return_dict['data'] = self.get_data_pretty_dict(indata.get( - 'data')) - return return_dict - - # Dumps dict in pretty format - def dump_pretty(self, indict): - for elem, elem_val in sorted(indict.items()): - if type(elem_val) == dict: - print(self._indent, elem, ': ') - self.inc_indent() - sff8472.dump_pretty(self, elem_val) - self.dec_indent() - elif type(elem_val) == list: - if len(elem_val) == 1: - print(self._indent, elem, ': ', elem_val.pop()) - else: - print(self._indent, elem, ': ') - self.inc_indent() - for e in elem_val: - print(self._indent, e) - self.dec_indent() - else: - print(self._indent, elem, ': ', elem_val) diff --git a/sonic_platform_base/sonic_sfp/sfputilbase.py b/sonic_platform_base/sonic_sfp/sfputilbase.py deleted file mode 100644 index 760ababa1..000000000 --- a/sonic_platform_base/sonic_sfp/sfputilbase.py +++ /dev/null @@ -1,1430 +0,0 @@ -# sfputilbase.py -# -# Base class for creating platform-specific SFP transceiver interfaces for SONiC -# - -from __future__ import print_function - -try: - import abc - import os - import re - import sys - from collections import OrderedDict - - from natsort import natsorted - from portconfig import get_port_config - from sonic_py_common import device_info - from sonic_py_common.interface import backplane_prefix, inband_prefix, recirc_prefix - - from sonic_eeprom import eeprom_dts - from .sff8472 import sff8472InterfaceId # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8472 import sff8472Dom # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8436 import sff8436InterfaceId # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .sff8436 import sff8436Dom # Dot module supports both Python 2 and Python 3 using explicit relative import methods - from .inf8628 import inf8628InterfaceId # Dot module supports both Python 2 and Python 3 using explicit relative import methods -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) - -# Global Variable -PLATFORM_JSON = 'platform.json' -PORT_CONFIG_INI = 'port_config.ini' - -# 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_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 = 1 - -# 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 and width for values in DOM info 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_CHANNL_MON_OFFSET = 34 -QSFP_CHANNL_MON_WIDTH = 16 -QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 -QSFP_MODULE_THRESHOLD_OFFSET = 128 -QSFP_MODULE_THRESHOLD_WIDTH = 24 -QSFP_CHANNL_THRESHOLD_OFFSET = 176 -QSFP_CHANNL_THRESHOLD_WIDTH = 24 -QSFP_CHANNL_MON_MASK_OFFSET = 242 -QSFP_CHANNL_MON_MASK_WIDTH = 4 - -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_MODULE_THRESHOLD_OFFSET = 112 -SFP_MODULE_THRESHOLD_WIDTH = 5 -SFP_CHANNL_THRESHOLD_OFFSET = 112 -SFP_CHANNL_THRESHOLD_WIDTH = 6 - -qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', - 'Length OM2(m)', 'Length OM1(m)', - 'Length Cable Assembly(m)') - -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') - -qsfp_dom_capability_tup = ('Tx_power_support', 'Rx_power_support', - 'Voltage_support', 'Temp_support') - -# Add an EOL to prevent this being viewed as string instead of list -sfp_dom_capability_tup = ('sff8472_dom_support', 'EOL') - -class SfpUtilError(Exception): - """Base class for exceptions in this module.""" - pass - - -class DeviceTreeError(SfpUtilError): - """Exception raised when unable to find SFP device attributes in the device tree.""" - def __init__(self, value): - self.value = value - - def __str__(self): - return repr(self.value) - - -class SfpUtilBase(object): - """ Abstract base class for SFP utility. This class - provides base EEPROM read attributes and methods common - to most platforms.""" - - __metaclass__ = abc.ABCMeta - - IDENTITY_EEPROM_ADDR = 0x50 - DOM_EEPROM_ADDR = 0x51 - SFP_DEVICE_TYPE = "24c02" - - # List to specify filter for sfp_ports - # Needed by platforms like dni-6448 which - # have only a subset of ports that support sfp - sfp_ports = [] - - # List of logical port names available on a system - """ ["swp1", "swp5", "swp6", "swp7", "swp8" ...] """ - logical = [] - - # Mapping of logical port names available on a system to ASIC num - logical_to_asic = {} - - # dicts for easier conversions between logical, physical and bcm ports - logical_to_bcm = {} - logical_to_physical = {} - - """ - phytab_mappings stores mapping between logical, physical and bcm ports - from /var/lib/cumulus/phytab - For a normal non-ganged port: - "swp8": {"bcmport": "xe4", "physicalport": [8], "phyid": ["0xb"]} - - For a ganged 40G/4 port: - "swp1": {"bcmport": "xe0", "physicalport": [1, 2, 3, 4], "phyid": ["0x4", "0x5", "0x6", "0x7"]} - - For ganged 4x10G port: - "swp52s0": {"bcmport": "xe51", "physicalport": [52], "phyid": ["0x48"]}, - "swp52s1": {"bcmport": "xe52", "physicalport": [52], "phyid": ["0x49"]}, - "swp52s2": {"bcmport": "xe53", "physicalport": [52], "phyid": ["0x4a"]}, - "swp52s3": {"bcmport": "xe54", "physicalport": [52], "phyid": ["0x4b"]}, - """ - phytab_mappings = {} - - physical_to_logical = {} - physical_to_phyaddrs = {} - - port_to_i2cbus_mapping = None - - @abc.abstractproperty - def port_start(self): - """ Starting index of physical port range """ - pass - - @abc.abstractproperty - def port_end(self): - """ Ending index of physical port range """ - pass - - @abc.abstractproperty - def qsfp_ports(self): - """ QSFP Ports """ - pass - - @property - def osfp_ports(self): - """ OSFP/QSFP-DD Ports """ - return [] - - @abc.abstractproperty - def port_to_eeprom_mapping(self): - """ Dictionary where key = physical port index (integer), - value = path to SFP EEPROM device file (string) """ - pass - - def __init__(self): - pass - - def _get_bcm_port(self, port_num): - bcm_port = None - - logical_port = self.physical_to_logical.get(port_num) - if logical_port is not None and len(logical_port) > 0: - bcm_port = self.logical_to_bcm.get(logical_port[0]) - - if bcm_port is None: - bcm_port = "xe%d" % (port_num - 1) - - return bcm_port - - def _get_port_i2c_adapter_id(self, port_num): - if len(self.port_to_i2cbus_mapping) == 0: - return -1 - - return self.port_to_i2cbus_mapping.get(port_num, -1) - - # Adds new sfp device on i2c adapter/bus via i2c bus new_device - # sysfs attribute - def _add_new_sfp_device(self, sysfs_sfp_i2c_adapter_path, devaddr): - try: - sysfs_nd_path = "%s/new_device" % sysfs_sfp_i2c_adapter_path - - # Write device address to new_device file - nd_file = open(sysfs_nd_path, "w") - nd_str = "%s %s" % (self.SFP_DEVICE_TYPE, hex(devaddr)) - nd_file.write(nd_str) - nd_file.close() - - except Exception as err: - print("Error writing to new device file: %s" % str(err)) - return 1 - else: - return 0 - - # Deletes sfp device on i2c adapter/bus via i2c bus delete_device - # sysfs attribute - def _delete_sfp_device(self, sysfs_sfp_i2c_adapter_path, devaddr): - try: - sysfs_nd_path = "%s/delete_device" % sysfs_sfp_i2c_adapter_path - - # Write device address to delete_device file - nd_file = open(sysfs_nd_path, "w") - nd_file.write(devaddr) - nd_file.close() - except Exception as err: - print("Error writing to new device file: %s" % str(err)) - return 1 - else: - return 0 - - # Returns 1 if SFP EEPROM found. Returns 0 otherwise - def _sfp_eeprom_present(self, sysfs_sfp_i2c_client_eeprompath, offset): - """Tries to read the eeprom file to determine if the - device/sfp is present or not. If sfp present, the read returns - valid bytes. If not, read returns error 'Connection timed out""" - - if not os.path.exists(sysfs_sfp_i2c_client_eeprompath): - return False - else: - try: - with open(sysfs_sfp_i2c_client_eeprompath, mode="rb", buffering=0) as sysfsfile: - sysfsfile.seek(offset) - sysfsfile.read(1) - except IOError: - return False - except Exception: - return False - else: - return True - - def _get_port_eeprom_path(self, port_num, devid): - sysfs_i2c_adapter_base_path = "/sys/class/i2c-adapter" - - if port_num in self.port_to_eeprom_mapping.keys(): - sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[port_num] - else: - sysfs_i2c_adapter_base_path = "/sys/class/i2c-adapter" - - i2c_adapter_id = self._get_port_i2c_adapter_id(port_num) - if i2c_adapter_id is None: - print("Error getting i2c bus num") - return None - - # Get i2c virtual bus path for the sfp - sysfs_sfp_i2c_adapter_path = "%s/i2c-%s" % (sysfs_i2c_adapter_base_path, - str(i2c_adapter_id)) - - # If i2c bus for port does not exist - if not os.path.exists(sysfs_sfp_i2c_adapter_path): - print("Could not find i2c bus %s. Driver not loaded?" % sysfs_sfp_i2c_adapter_path) - return None - - sysfs_sfp_i2c_client_path = "%s/%s-00%s" % (sysfs_sfp_i2c_adapter_path, - str(i2c_adapter_id), - hex(devid)[-2:]) - - # If sfp device is not present on bus, Add it - if not os.path.exists(sysfs_sfp_i2c_client_path): - ret = self._add_new_sfp_device( - sysfs_sfp_i2c_adapter_path, devid) - if ret != 0: - print("Error adding sfp device") - return None - - sysfs_sfp_i2c_client_eeprom_path = "%s/eeprom" % sysfs_sfp_i2c_client_path - - return sysfs_sfp_i2c_client_eeprom_path - - # Read out any bytes from any offset - def _read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): - eeprom_raw = [] - for i in range(0, num_bytes): - eeprom_raw.append("0x00") - - try: - sysfsfile_eeprom.seek(offset) - raw = sysfsfile_eeprom.read(num_bytes) - except IOError: - print("Error: reading EEPROM sysfs file") - return None - - try: - # raw is changed to bytearray to support both python 2 and 3. - raw = bytearray(raw) - for n in range(0, num_bytes): - eeprom_raw[n] = hex(raw[n])[2:].zfill(2) - except Exception: - return None - - return eeprom_raw - - # Read eeprom - def _read_eeprom_devid(self, port_num, devid, offset, num_bytes = 256): - sysfs_sfp_i2c_client_eeprom_path = self._get_port_eeprom_path(port_num, devid) - - if not self._sfp_eeprom_present(sysfs_sfp_i2c_client_eeprom_path, offset): - return None - - try: - sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path) - return None - - eeprom_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, offset, num_bytes) - - try: - sysfsfile_eeprom.close() - except Exception: - return None - - return eeprom_raw - - def _write_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes, write_buffer): - try: - sysfsfile_eeprom.seek(offset) - sysfsfile_eeprom.write(write_buffer) - except IOError: - print("Error: writing EEPROM sysfs file") - return False - - return True - - def _write_eeprom_devid(self, port_num, devid, offset, num_bytes, write_buffer): - sysfs_sfp_i2c_client_eeprom_path = self._get_port_eeprom_path(port_num, devid) - - if not self._sfp_eeprom_present(sysfs_sfp_i2c_client_eeprom_path, offset): - return False - - try: - sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="wb", buffering=0) - except IOError: - print("Error: trying to open sysfs file for writing %s" % sysfs_sfp_i2c_client_eeprom_path) - return False - - result = self._write_eeprom_specific_bytes(sysfsfile_eeprom, offset, num_bytes, write_buffer) - - try: - sysfsfile_eeprom.close() - except Exception: - return False - - return True - - def _is_valid_port(self, port_num): - if port_num >= self.port_start and port_num <= self.port_end: - return True - - return False - - def read_porttab_mappings(self, porttabfile, asic_inst=0): - logical = [] - logical_to_bcm = {} - logical_to_physical = {} - physical_to_logical = {} - last_fp_port_index = 0 - last_portname = "" - first = 1 - port_pos_in_file = 0 - parse_fmt_port_config_ini = False - parse_fmt_platform_json = False - - parse_fmt_port_config_ini = (os.path.basename(porttabfile) == PORT_CONFIG_INI) - parse_fmt_platform_json = (os.path.basename(porttabfile) == PLATFORM_JSON) - - (platform, hwsku) = device_info.get_platform_and_hwsku() - if(parse_fmt_platform_json): - ports, _, _ = get_port_config(hwsku, platform) - if not ports: - print('Failed to get port config', file=sys.stderr) - sys.exit(1) - else: - logical_list = [] - for intf in ports.keys(): - logical_list.append(intf) - - logical = natsorted(logical_list, key=lambda y: y.lower()) - logical_to_bcm, logical_to_physical, physical_to_logical = OrderedDict(), OrderedDict(), OrderedDict() - - for intf_name in logical: - bcm_port = str(port_pos_in_file) - logical_to_bcm[intf_name] = "xe"+ bcm_port - - if 'index' in ports[intf_name].keys(): - fp_port_index = int(ports[intf_name]['index']) - logical_to_physical[intf_name] = [fp_port_index] - - if physical_to_logical.get(fp_port_index) is None: - physical_to_logical[fp_port_index] = [intf_name] - else: - physical_to_logical[fp_port_index].append(intf_name) - - # Mapping of logical port names available on a system to ASIC instance - self.logical_to_asic[intf_name] = asic_inst - port_pos_in_file +=1 - - self.logical = logical - self.logical_to_bcm = logical_to_bcm - self.logical_to_physical = logical_to_physical - self.physical_to_logical = physical_to_logical - - """ - print("logical: {}".format(self.logical)) - print("logical to bcm: {}".format(self.logical_to_bcm)) - print("logical to physical: {}".format(self.logical_to_physical)) - print("physical to logical: {}".format( self.physical_to_logical)) - """ - return None - - - try: - f = open(porttabfile) - except Exception: - raise - - # Read the porttab file and generate dicts - # with mapping for future reference. - # - # TODO: Refactor this to use the portconfig.py module that now - # exists as part of the sonic-config-engine package. - title = [] - for line in f: - line.strip() - if re.search("^#", line) is not None: - # The current format is: # name lanes alias index speed - # Where the ordering of the columns can vary - title = line.split()[1:] - continue - - # Parsing logic for 'port_config.ini' file - if (parse_fmt_port_config_ini): - # bcm_port is not explicitly listed in port_config.ini format - # Currently we assume ports are listed in numerical order according to bcm_port - # so we use the port's position in the file (zero-based) as bcm_port - portname = line.split()[0] - - # Ignore if this is an internal backplane interface and Inband interface - if portname.startswith((backplane_prefix(), inband_prefix(), recirc_prefix())): - continue - - bcm_port = str(port_pos_in_file) - - if "index" in title: - fp_port_index = int(line.split()[title.index("index")]) - # Leave the old code for backward compatibility - elif "asic_port_name" not in title and len(line.split()) >= 4: - fp_port_index = int(line.split()[3]) - else: - fp_port_index = portname.split("Ethernet").pop() - fp_port_index = int(fp_port_index.split("s").pop(0))/4 - else: # Parsing logic for older 'portmap.ini' file - (portname, bcm_port) = line.split("=")[1].split(",")[:2] - - fp_port_index = portname.split("Ethernet").pop() - fp_port_index = int(fp_port_index.split("s").pop(0))/4 - - if ((len(self.sfp_ports) > 0) and (fp_port_index not in self.sfp_ports)): - continue - - if first == 1: - # Initialize last_[physical|logical]_port - # to the first valid port - last_fp_port_index = fp_port_index - last_portname = portname - first = 0 - - logical.append(portname) - - # Mapping of logical port names available on a system to ASIC instance - self.logical_to_asic[portname] = asic_inst - - logical_to_bcm[portname] = "xe" + bcm_port - logical_to_physical[portname] = [fp_port_index] - if physical_to_logical.get(fp_port_index) is None: - physical_to_logical[fp_port_index] = [portname] - else: - physical_to_logical[fp_port_index].append(portname) - - last_fp_port_index = fp_port_index - last_portname = portname - - port_pos_in_file += 1 - - self.logical.extend(logical) - self.logical_to_bcm.update(logical_to_bcm) - self.logical_to_physical.update(logical_to_physical) - self.physical_to_logical.update(physical_to_logical) - - """ - print("logical: " + self.logical) - print("logical to bcm: " + self.logical_to_bcm) - print("logical to physical: " + self.logical_to_physical) - print("physical to logical: " + self.physical_to_logical) - """ - - def read_all_porttab_mappings(self, platform_dir, num_asic_inst): - # In multi asic scenario, get all the port_config files for different asics - for inst in range(num_asic_inst): - port_map_dir = os.path.join(platform_dir, str(inst)) - port_map_file = os.path.join(port_map_dir, PORT_CONFIG_INI) - if os.path.exists(port_map_file): - self.read_porttab_mappings(port_map_file, inst) - else: - port_json_file = os.path.join(port_map_dir, PLATFORM_JSON) - if os.path.exists(port_json_file): - self.read_porttab_mappings(port_json_file, inst) - - def read_phytab_mappings(self, phytabfile): - logical = [] - phytab_mappings = {} - physical_to_logical = {} - physical_to_phyaddrs = {} - - try: - f = open(phytabfile) - except Exception: - raise - - # Read the phytab file and generate dicts - # with mapping for future reference. - # XXX: move the phytabfile - # parsing stuff to a separate module, or reuse - # if something already exists - for line in f: - line = line.strip() - line = re.sub(r"\s+", " ", line) - if len(line) < 4: - continue - if re.search("^#", line) is not None: - continue - (phy_addr, logical_port, bcm_port, type) = line.split(" ", 3) - - if re.match("xe", bcm_port) is None: - continue - - lport = re.findall("swp(\d+)s*(\d*)", logical_port) - if lport is not None: - lport_tuple = lport.pop() - physical_port = int(lport_tuple[0]) - else: - physical_port = logical_port.split("swp").pop() - physical_port = int(physical_port.split("s").pop(0)) - - # Some platforms have a list of physical sfp ports - # defined. If such a list exists, check to see if this - # port is blacklisted - if ((len(self.sfp_ports) > 0) and (physical_port not in self.sfp_ports)): - continue - - if logical_port not in logical: - logical.append(logical_port) - - if phytab_mappings.get(logical_port) is None: - phytab_mappings[logical_port] = {} - phytab_mappings[logical_port]['physicalport'] = [] - phytab_mappings[logical_port]['phyid'] = [] - phytab_mappings[logical_port]['type'] = type - - # If the port is 40G/4 ganged, there will be multiple - # physical ports corresponding to the logical port. - # Generate the next physical port number in the series - # and append it to the list - tmp_physical_port_list = phytab_mappings[logical_port]['physicalport'] - if (type == "40G/4" and physical_port in tmp_physical_port_list): - # Aha!...ganged port - new_physical_port = tmp_physical_port_list[-1] + 1 - else: - new_physical_port = physical_port - - if (new_physical_port not in phytab_mappings[logical_port]['physicalport']): - phytab_mappings[logical_port]['physicalport'].append(new_physical_port) - phytab_mappings[logical_port]['phyid'].append(phy_addr) - phytab_mappings[logical_port]['bcmport'] = bcm_port - - # Store in physical_to_logical dict - if physical_to_logical.get(new_physical_port) is None: - physical_to_logical[new_physical_port] = [] - physical_to_logical[new_physical_port].append(logical_port) - - # Store in physical_to_phyaddrs dict - if physical_to_phyaddrs.get(new_physical_port) is None: - physical_to_phyaddrs[new_physical_port] = [] - physical_to_phyaddrs[new_physical_port].append(phy_addr) - - self.logical = logical - self.phytab_mappings = phytab_mappings - self.physical_to_logical = physical_to_logical - self.physical_to_phyaddrs = physical_to_phyaddrs - - """ - pp = pprint.PrettyPrinter(indent=4) - pp.pprint(self.phytab_mappings) - - print("logical: " + self.logical) - print("logical to bcm: " + self.logical_to_bcm) - print("phytab mappings: " + self.phytab_mappings) - print("physical to logical: " + self.physical_to_logical) - print("physical to phyaddrs: " + self.physical_to_phyaddrs) - """ - - def get_physical_to_logical(self, port_num): - """Returns list of logical ports for the given physical port""" - - return self.physical_to_logical.get(port_num) - - def get_logical_to_physical(self, logical_port): - """Returns list of physical ports for the given logical port""" - - return self.logical_to_physical[logical_port] - - def is_logical_port(self, port): - if port in self.logical: - return 1 - else: - return 0 - - def get_asic_id_for_logical_port(self, logical_port): - """Returns the asic_id list of physical ports for the given logical port""" - return self.logical_to_asic.get(logical_port) - - def is_logical_port_ganged_40_by_4(self, logical_port): - physical_port_list = self.logical_to_physical[logical_port] - if len(physical_port_list) > 1: - return 1 - else: - return 0 - - def is_physical_port_ganged_40_by_4(self, port_num): - logical_port = self.get_physical_to_logical(port_num) - if logical_port is not None: - return self.is_logical_port_ganged_40_by_4(logical_port[0]) - - return 0 - - def get_physical_port_phyid(self, physical_port): - """Returns list of phyids for a physical port""" - - return self.physical_to_phyaddrs[physical_port] - - def get_40_by_4_gangport_phyid(self, logical_port): - """ Return the first ports phyid. One use case for - this is to address the gang port in single mode """ - - phyid_list = self.phytab_mappings[logical_port]['phyid'] - if phyid_list is not None: - return phyid_list[0] - - def is_valid_sfputil_port(self, port): - if port.startswith(""): - if self.is_logical_port(port): - return 1 - else: - return 0 - else: - return 0 - - def read_port_mappings(self): - if self.port_to_eeprom_mapping is None or self.port_to_i2cbus_mapping is None: - self.read_port_to_eeprom_mapping() - self.read_port_to_i2cbus_mapping() - - def read_port_to_eeprom_mapping(self): - eeprom_dev = "/sys/class/eeprom_dev" - self.port_to_eeprom_mapping = {} - for eeprom_path in [os.path.join(eeprom_dev, x) for x in os.listdir(eeprom_dev)]: - eeprom_label = open(os.path.join(eeprom_path, "label"), "r").read().strip() - if eeprom_label.startswith("port"): - port = int(eeprom_label[4:]) - self.port_to_eeprom_mapping[port] = os.path.join(eeprom_path, "device", "eeprom") - - def read_port_to_i2cbus_mapping(self): - if self.port_to_i2cbus_mapping is not None and len(self.port_to_i2cbus_mapping) > 0: - return - - self.eep_dict = eeprom_dts.get_dev_attr_from_dtb(['sfp']) - if len(self.eep_dict) == 0: - return - - # XXX: there should be a cleaner way to do this. - i2cbus_list = [] - self.port_to_i2cbus_mapping = {} - s = self.port_start - for sfp_sysfs_path, attrs in sorted(self.eep_dict.items()): - i2cbus = attrs.get("dev-id") - if i2cbus is None: - raise DeviceTreeError("No 'dev-id' attribute found in attr: %s" % repr(attrs)) - if i2cbus in i2cbus_list: - continue - i2cbus_list.append(i2cbus) - self.port_to_i2cbus_mapping[s] = i2cbus - s += 1 - if s > self.port_end: - break - - def get_eeprom_raw(self, port_num, num_bytes=256): - # Read interface id EEPROM at addr 0x50 - return self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 0, num_bytes) - - def get_eeprom_dom_raw(self, port_num): - if port_num in self.osfp_ports: - return None - if port_num in self.qsfp_ports: - # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw - return None - else: - # Read dom eeprom at addr 0x51 - return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 0) - - def get_eeprom_dict(self, port_num): - """Returns dictionary of interface and dom data. - format: { : {'interface': {'version' : '1.0', 'data' : {...}}, - 'dom' : {'version' : '1.0', 'data' : {...}}}} - """ - - sfp_data = {} - - eeprom_ifraw = self.get_eeprom_raw(port_num) - eeprom_domraw = self.get_eeprom_dom_raw(port_num) - - if eeprom_ifraw is None: - return None - - if port_num in self.osfp_ports: - sfpi_obj = inf8628InterfaceId(eeprom_ifraw) - if sfpi_obj is not None: - sfp_data['interface'] = sfpi_obj.get_data_pretty() - return sfp_data - elif port_num in self.qsfp_ports: - sfpi_obj = sff8436InterfaceId(eeprom_ifraw) - if sfpi_obj is not None: - sfp_data['interface'] = sfpi_obj.get_data_pretty() - # For Qsfp's the dom data is part of eeprom_if_raw - # The first 128 bytes - - sfpd_obj = sff8436Dom(eeprom_ifraw) - if sfpd_obj is not None: - sfp_data['dom'] = sfpd_obj.get_data_pretty() - - return sfp_data - else: - sfpi_obj = sff8472InterfaceId(eeprom_ifraw) - if sfpi_obj is not None: - sfp_data['interface'] = sfpi_obj.get_data_pretty() - cal_type = sfpi_obj.get_calibration_type() - - if eeprom_domraw is not None: - sfpd_obj = sff8472Dom(eeprom_domraw, cal_type) - if sfpd_obj is not None: - sfp_data['dom'] = sfpd_obj.get_data_pretty() - - return sfp_data - - # Read out SFP type, vendor name, PN, REV, SN from eeprom. - def get_transceiver_info_dict(self, port_num): - transceiver_info_dict = {} - compliance_code_dict = {} - dom_capability_dict = {} - - # 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 port_num in self.osfp_ports: - offset = 0 - vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP - - sfpi_obj = inf8628InterfaceId() - if sfpi_obj is None: - print("Error: sfp_object open failed") - return None - - file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): - print("Error, file not exist %s" % file_path) - return None - - try: - sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % file_path) - return None - - sfp_type_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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 None - - sfp_vendor_name_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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 None - - sfp_vendor_pn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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 None - - sfp_vendor_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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 None - - sfp_vendor_sn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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 None - - sfp_type_abbrv_name_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) - if sfp_type_abbrv_name_raw is not None: - sfp_type_abbrv_name = sfpi_obj.parse_sfp_type_abbrv_name(sfp_type_abbrv_name_raw, 0) - else: - return None - - try: - sysfsfile_eeprom.close() - except IOError: - print("Error: closing sysfs file %s" % file_path) - return None - - transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] - transceiver_info_dict['type_abbrv_name'] = sfp_type_abbrv_name['data']['type_abbrv_name']['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'] - # Below part is added to avoid fail the xcvrd, shall be implemented later - transceiver_info_dict['vendor_oui'] = 'N/A' - transceiver_info_dict['vendor_date'] = 'N/A' - transceiver_info_dict['connector'] = 'N/A' - transceiver_info_dict['encoding'] = 'N/A' - transceiver_info_dict['ext_identifier'] = 'N/A' - transceiver_info_dict['ext_rateselect_compliance'] = 'N/A' - transceiver_info_dict['cable_type'] = 'N/A' - transceiver_info_dict['cable_length'] = 'N/A' - transceiver_info_dict['specification_compliance'] = '{}' - transceiver_info_dict['nominal_bit_rate'] = 'N/A' - transceiver_info_dict['application_advertisement'] = 'N/A' - transceiver_info_dict['dom_capability'] = '{}' - - else: - file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): - print("Error, file not exist %s" % file_path) - return None - - try: - sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % file_path) - return None - - if port_num in self.qsfp_ports: - # Check for QSA adapter - byte0 = self._read_eeprom_specific_bytes(sysfsfile_eeprom, 0, 1)[0] - is_qsfp = (byte0 != '03' and byte0 != '0b') - else: - is_qsfp = False - - if is_qsfp: - offset = 128 - vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP - cable_length_width = XCVR_CABLE_LENGTH_WIDTH_QSFP - interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP - sfp_type = 'QSFP' - - sfpi_obj = sff8436InterfaceId() - if sfpi_obj is None: - print("Error: sfp_object open failed") - return None - - else: - offset = 0 - vendor_rev_width = XCVR_HW_REV_WIDTH_SFP - cable_length_width = XCVR_CABLE_LENGTH_WIDTH_SFP - interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP - sfp_type = 'SFP' - - sfpi_obj = sff8472InterfaceId() - if sfpi_obj is None: - print("Error: sfp_object open failed") - return None - - sfp_interface_bulk_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_INTFACE_BULK_OFFSET), interface_info_bulk_width) - if sfp_interface_bulk_raw is not None: - sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) - else: - return None - - sfp_vendor_name_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_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 None - - sfp_vendor_pn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_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 None - - sfp_vendor_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_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 None - - sfp_vendor_sn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_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 None - - sfp_vendor_oui_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_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 None - - sfp_vendor_date_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) - if sfp_vendor_date_raw is not None: - sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) - else: - return None - - sfp_dom_capability_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) - if sfp_dom_capability_raw is not None: - sfp_dom_capability_data = sfpi_obj.parse_dom_capability(sfp_dom_capability_raw, 0) - else: - return None - - try: - sysfsfile_eeprom.close() - except IOError: - print("Error: closing sysfs file %s" % file_path) - return None - - transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] - transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['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['cable_type'] = "Unknown" - transceiver_info_dict['cable_length'] = "Unknown" - transceiver_info_dict['application_advertisement'] = 'N/A' - - if sfp_type == 'QSFP': - 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'] - transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) - - for key in qsfp_dom_capability_tup: - if key in sfp_dom_capability_data['data']: - dom_capability_dict[key] = "yes" if sfp_dom_capability_data['data'][key]['value'] == 'on' else "no" - transceiver_info_dict['dom_capability'] = str(dom_capability_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) - - for key in sfp_dom_capability_tup: - if key in sfp_dom_capability_data['data']: - dom_capability_dict[key] = "yes" if sfp_dom_capability_data['data'][key]['value'] == 'on' else "no" - transceiver_info_dict['dom_capability'] = str(dom_capability_dict) - - transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) - - return transceiver_info_dict - - def get_transceiver_dom_info_dict(self, port_num): - transceiver_dom_info_dict = {} - - dom_info_dict_keys = ['temperature', 'voltage', 'rx1power', - 'rx2power', 'rx3power', 'rx4power', - 'tx1bias', 'tx2bias', 'tx3bias', - 'tx4bias', 'tx1power', 'tx2power', - 'tx3power', 'tx4power', - ] - transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') - - if port_num in self.osfp_ports: - # Below part is added to avoid fail xcvrd, shall be implemented later - transceiver_dom_info_dict['temperature'] = 'N/A' - transceiver_dom_info_dict['voltage'] = 'N/A' - transceiver_dom_info_dict['rx1power'] = 'N/A' - transceiver_dom_info_dict['rx2power'] = 'N/A' - transceiver_dom_info_dict['rx3power'] = 'N/A' - transceiver_dom_info_dict['rx4power'] = 'N/A' - transceiver_dom_info_dict['tx1bias'] = 'N/A' - transceiver_dom_info_dict['tx2bias'] = 'N/A' - transceiver_dom_info_dict['tx3bias'] = 'N/A' - transceiver_dom_info_dict['tx4bias'] = 'N/A' - transceiver_dom_info_dict['tx1power'] = 'N/A' - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' - - elif port_num in self.qsfp_ports: - offset = 0 - offset_xcvr = 128 - file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): - return None - - try: - sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % file_path) - return None - - sfpd_obj = sff8436Dom() - if sfpd_obj is None: - return None - - sfpi_obj = sff8436InterfaceId() - if sfpi_obj is None: - return None - - # 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(sysfsfile_eeprom, (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) - if qsfp_dom_capability_raw is not None: - qspf_dom_capability_data = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) - else: - return None - - dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) - else: - return None - - dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) - else: - return None - - qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) - if qsfp_dom_rev_raw is not None: - qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) - else: - return None - - transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] - transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] - - # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 - # and claimed that it support tx_power with one indicator bit. - dom_channel_monitor_data = {} - qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] - qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] - if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): - dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_CHANNL_MON_OFFSET), QSFP_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) - else: - return None - - transceiver_dom_info_dict['tx1power'] = 'N/A' - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' - else: - dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) - else: - return None - - 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'] - - try: - sysfsfile_eeprom.close() - except IOError: - print("Error: closing sysfs file %s" % file_path) - return None - - 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']['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'] - - else: - offset = 256 - file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): - return None - - try: - sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % file_path) - return None - - sfpd_obj = sff8472Dom() - if sfpd_obj is None: - return None - dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) - else: - return None - - dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) - else: - return None - - dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (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) - else: - return None - - try: - sysfsfile_eeprom.close() - except IOError: - print("Error: closing sysfs file %s" % file_path) - return None - - 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['rx2power'] = 'N/A' - transceiver_dom_info_dict['rx3power'] = 'N/A' - transceiver_dom_info_dict['rx4power'] = 'N/A' - transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] - transceiver_dom_info_dict['tx2bias'] = 'N/A' - transceiver_dom_info_dict['tx3bias'] = 'N/A' - transceiver_dom_info_dict['tx4bias'] = 'N/A' - transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' - - return transceiver_dom_info_dict - def get_transceiver_dom_threshold_info_dict(self, port_num): - transceiver_dom_threshold_info_dict = {} - - dom_info_dict_keys = ['temphighalarm', 'temphighwarning', - 'templowalarm', 'templowwarning', - 'vcchighalarm', 'vcchighwarning', - 'vcclowalarm', 'vcclowwarning', - 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', - 'txpowerhighalarm', 'txpowerhighwarning', - 'txpowerlowalarm', 'txpowerlowwarning', - 'txbiashighalarm', 'txbiashighwarning', - 'txbiaslowalarm', 'txbiaslowwarning' - ] - transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') - - if port_num in self.osfp_ports: - # Below part is added to avoid fail xcvrd, shall be implemented later - return transceiver_dom_threshold_info_dict - - elif port_num in self.qsfp_ports: - file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): - return None - - try: - sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % file_path) - return None - - sfpd_obj = sff8436Dom() - if sfpd_obj is None: - return None - - # Dom Threshold data starts from offset 384 - # Revert offset back to 0 once data is retrieved - offset = 384 - dom_module_threshold_raw = self._read_eeprom_specific_bytes( - sysfsfile_eeprom, - (offset + QSFP_MODULE_THRESHOLD_OFFSET), - QSFP_MODULE_THRESHOLD_WIDTH) - if dom_module_threshold_raw is not None: - dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) - else: - return None - - dom_channel_threshold_raw = self._read_eeprom_specific_bytes( - sysfsfile_eeprom, - (offset + QSFP_CHANNL_THRESHOLD_OFFSET), - QSFP_CHANNL_THRESHOLD_WIDTH) - if dom_channel_threshold_raw is not None: - dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) - else: - return None - - try: - sysfsfile_eeprom.close() - except IOError: - print("Error: closing sysfs file %s" % file_path) - return None - - # Threshold Data - transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] - transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] - transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] - transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] - transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] - transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] - transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] - transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] - transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] - transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] - - else: - offset = 256 - file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) - if not self._sfp_eeprom_present(file_path, 0): - return None - - try: - sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % file_path) - return None - - sfpd_obj = sff8472Dom() - if sfpd_obj is None: - return None - - dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, - (offset + SFP_MODULE_THRESHOLD_OFFSET), - SFP_MODULE_THRESHOLD_WIDTH) - if dom_module_threshold_raw is not None: - dom_module_threshold_data = sfpd_obj.parse_module_monitor_params(dom_module_threshold_raw, 0) - else: - return None - - dom_channel_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, - (offset + SFP_CHANNL_THRESHOLD_OFFSET), - SFP_CHANNL_THRESHOLD_WIDTH) - if dom_channel_threshold_raw is not None: - dom_channel_threshold_data = sfpd_obj.parse_channel_thresh_monitor_params(dom_channel_threshold_raw, 0) - else: - return None - - try: - sysfsfile_eeprom.close() - except IOError: - print("Error: closing sysfs file %s" % file_path) - return None - - # Threshold Data - transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] - transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] - transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] - transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] - transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] - transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] - transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] - transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] - transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['BiasHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['BiasLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['BiasHighWarning']['value'] - transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['BiasLowWarning']['value'] - transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] - - return transceiver_dom_threshold_info_dict - - @abc.abstractmethod - def get_presence(self, port_num): - """ - :param port_num: Integer, index of physical port - :returns: Boolean, True if tranceiver is present, False if not - """ - return - - @abc.abstractmethod - def get_low_power_mode(self, port_num): - """ - :param port_num: Integer, index of physical port - :returns: Boolean, True if low-power mode enabled, False if disabled - """ - return - - @abc.abstractmethod - def set_low_power_mode(self, port_num, lpmode): - """ - :param port_num: Integer, index of physical port - :param lpmode: Boolean, True to enable low-power mode, False to disable it - :returns: Boolean, True if low-power mode set successfully, False if not - """ - return - - @abc.abstractmethod - def reset(self, port_num): - """ - :param port_num: Integer, index of physical port - :returns: Boolean, True if reset successful, False if not - """ - return - - @abc.abstractmethod - def get_transceiver_change_event(self, timeout=0): - """ - :param timeout in milliseconds. The method is a blocking call. When timeout is - zero, it only returns when there is change event, i.e., transceiver plug-in/out - event. When timeout is non-zero, the function can also return when the timer expires. - When timer expires, the return status is True and events is empty. - :returns: (status, events) - :status: Boolean, True if call successful and no system level event/error occurred, - False if call not success or system level event/error occurred. - :events: dictionary for physical port index and the SFP status, - status='1' represent plug in, '0' represent plug out like {'0': '1', '31':'0'} - when it comes to system level event/error, the index will be '-1', - and status can be 'system_not_ready', 'system_become_ready', 'system_fail', - like {'-1':'system_not_ready'}. - """ - return - diff --git a/sonic_platform_base/sonic_sfp/sfputilhelper.py b/sonic_platform_base/sonic_sfp/sfputilhelper.py deleted file mode 100644 index 7504729c7..000000000 --- a/sonic_platform_base/sonic_sfp/sfputilhelper.py +++ /dev/null @@ -1,130 +0,0 @@ -# sfputilbase.py -# -# Base class for creating platform-specific SFP transceiver interfaces for SONiC -# - -from __future__ import print_function - -try: - import os - import re - import sys - from collections import OrderedDict - - from natsort import natsorted - from portconfig import get_port_config - from sonic_py_common import device_info, multi_asic - from sonic_py_common.interface import backplane_prefix, inband_prefix, recirc_prefix - -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) - -# Global Variable -PLATFORM_JSON = 'platform.json' -PORT_CONFIG_INI = 'port_config.ini' -ASIC_NAME_PREFIX = 'asic' - -class SfpUtilHelper(object): - # List to specify filter for sfp_ports - # Needed by platforms like dni-6448 which - # have only a subset of ports that support sfp - sfp_ports = [] - - # List of logical port names available on a system - """ ["swp1", "swp5", "swp6", "swp7", "swp8" ...] """ - logical = [] - - # Mapping of logical port names available on a system to ASIC num - logical_to_asic = {} - - # dicts for easier conversions between logical, physical and bcm ports - logical_to_physical = {} - - physical_to_logical = {} - physical_to_phyaddrs = {} - - def __init__(self): - pass - - def read_porttab_mappings(self, porttabfile, asic_inst=0): - logical = [] - logical_to_physical = {} - physical_to_logical = {} - fp_port_index = 1 - - (platform, hwsku) = device_info.get_platform_and_hwsku() - - asic_name = None - if multi_asic.is_multi_asic(): - asic_name = ASIC_NAME_PREFIX + str(asic_inst) - - ports, _, _ = get_port_config(hwsku, platform, asic_name=asic_name) - - if not ports: - ports, _, _ = get_port_config(hwsku, platform, porttabfile) - if not ports: - print('Failed to get port config', file=sys.stderr) - sys.exit(1) - - logical_list = [] - for intf in ports.keys(): - logical_list.append(intf) - - # Ignore if this is an internal backplane interface and Inband interface - logical = [name for name in logical_list - if not name.startswith((backplane_prefix(), inband_prefix(), recirc_prefix()))] - logical = natsorted(logical, key=lambda y: y.lower()) - logical_to_physical, physical_to_logical = OrderedDict(), OrderedDict() - - for intf_name in logical: - if 'index' in ports[intf_name].keys(): - fp_port_index = int(ports[intf_name]['index']) - logical_to_physical[intf_name] = [fp_port_index] - - if physical_to_logical.get(fp_port_index) is None: - physical_to_logical[fp_port_index] = [intf_name] - else: - physical_to_logical[fp_port_index].append(intf_name) - - # Mapping of logical port names available on a system to ASIC instance - self.logical_to_asic[intf_name] = asic_inst - - self.logical.extend(logical) - self.logical = list(set(self.logical)) - self.logical_to_physical.update(logical_to_physical) - self.physical_to_logical.update(physical_to_logical) - - return None - - - def read_all_porttab_mappings(self, platform_dir, num_asic_inst): - # In multi asic scenario, get all the port_config files for different asic - for inst in range(num_asic_inst): - port_map_dir = os.path.join(platform_dir, str(inst)) - port_map_file = os.path.join(port_map_dir, PORT_CONFIG_INI) - if os.path.exists(port_map_file): - self.read_porttab_mappings(port_map_file, inst) - else: - port_json_file = os.path.join(platform_dir, PLATFORM_JSON) - if os.path.exists(port_json_file): - self.read_porttab_mappings(port_json_file, inst) - - def get_physical_to_logical(self, port_num): - """Returns list of logical ports for the given physical port""" - - return self.physical_to_logical.get(port_num) - - def get_logical_to_physical(self, logical_port): - """Returns list of physical ports for the given logical port""" - - return self.logical_to_physical[logical_port] - - def is_logical_port(self, port): - if port in self.logical: - return 1 - else: - return 0 - - def get_asic_id_for_logical_port(self, logical_port): - """Returns the asic_id list of physical ports for the given logical port""" - return self.logical_to_asic.get(logical_port) diff --git a/sonic_platform_base/sonic_ssd/__init__.py b/sonic_platform_base/sonic_ssd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_ssd/ssd_base.py b/sonic_platform_base/sonic_ssd/ssd_base.py deleted file mode 100644 index 2c80d621f..000000000 --- a/sonic_platform_base/sonic_ssd/ssd_base.py +++ /dev/null @@ -1,75 +0,0 @@ -# -# ssd_base.py -# -# Base class for implementing common SSD health features -# - - -class SsdBase(object): - """ - Base class for interfacing with a SSD - """ - def __init__(self, diskdev): - """ - Constructor - - Args: - diskdev: Linux device name to get parameters for - """ - pass - - def get_health(self): - """ - Retrieves current disk health in percentages - - Returns: - A float number of current ssd health - e.g. 83.5 - """ - raise NotImplementedError - - def get_temperature(self): - """ - Retrieves current disk temperature in Celsius - - Returns: - A float number of current temperature in Celsius - e.g. 40.1 - """ - raise NotImplementedError - - def get_model(self): - """ - Retrieves model for the given disk device - - Returns: - A string holding disk model as provided by the manufacturer - """ - raise NotImplementedError - - def get_firmware(self): - """ - Retrieves firmware version for the given disk device - - Returns: - A string holding disk firmware version as provided by the manufacturer - """ - raise NotImplementedError - - def get_serial(self): - """ - Retrieves serial number for the given disk device - - Returns: - A string holding disk serial number as provided by the manufacturer - """ - raise NotImplementedError - - def get_vendor_output(self): - """ - Retrieves vendor specific data for the given disk device - - Returns: - A string holding some vendor specific disk information - """ - raise NotImplementedError diff --git a/sonic_platform_base/sonic_ssd/ssd_generic.py b/sonic_platform_base/sonic_ssd/ssd_generic.py deleted file mode 100644 index 7c387816d..000000000 --- a/sonic_platform_base/sonic_ssd/ssd_generic.py +++ /dev/null @@ -1,208 +0,0 @@ -# -# ssd_generic.py -# -# Generic implementation of the SSD health API -# SSD models supported: -# - InnoDisk -# - StorFly -# - Virtium - -try: - import re - import subprocess - from .ssd_base import SsdBase -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -SMARTCTL = "smartctl {} -a" -INNODISK = "iSmart -d {}" -VIRTIUM = "SmartCmd -m {}" - -NOT_AVAILABLE = "N/A" - -# Set Vendor Specific IDs -INNODISK_HEALTH_ID = 169 -INNODISK_TEMPERATURE_ID = 194 - -class SsdUtil(SsdBase): - """ - Generic implementation of the SSD health API - """ - model = NOT_AVAILABLE - serial = NOT_AVAILABLE - firmware = NOT_AVAILABLE - temperature = NOT_AVAILABLE - health = NOT_AVAILABLE - ssd_info = NOT_AVAILABLE - vendor_ssd_info = NOT_AVAILABLE - - def __init__(self, diskdev): - self.vendor_ssd_utility = { - "Generic" : { "utility" : SMARTCTL, "parser" : self.parse_generic_ssd_info }, - "InnoDisk" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, - "M.2" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, - "StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, - "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info } - } - - self.dev = diskdev - # Generic part - self.fetch_generic_ssd_info(diskdev) - self.parse_generic_ssd_info() - - # Known vendor part - if self.model: - vendor = self._parse_vendor() - if vendor: - self.fetch_vendor_ssd_info(diskdev, vendor) - self.parse_vendor_ssd_info(vendor) - else: - # No handler registered for this disk model - pass - else: - # Failed to get disk model - self.model = "Unknown" - - def _execute_shell(self, cmd): - process = subprocess.Popen(cmd.split(), universal_newlines=True, stdout=subprocess.PIPE) - output, error = process.communicate() - return output - - def _parse_re(self, pattern, buffer): - res_list = re.findall(pattern, buffer) - return res_list[0] if res_list else NOT_AVAILABLE - - def _parse_vendor(self): - model_short = self.model.split()[0] - if model_short in self.vendor_ssd_utility: - return model_short - elif self.model.startswith('VSF'): - return 'Virtium' - else: - return None - - def fetch_generic_ssd_info(self, diskdev): - self.ssd_info = self._execute_shell(self.vendor_ssd_utility["Generic"]["utility"].format(diskdev)) - - # Health and temperature values may be overwritten with vendor specific data - def parse_generic_ssd_info(self): - if "nvme" in self.dev: - self.model = self._parse_re('Model Number:\s*(.+?)\n', self.ssd_info) - - health_raw = self._parse_re('Percentage Used\s*(.+?)\n', self.ssd_info) - if health_raw == NOT_AVAILABLE: - self.health = NOT_AVAILABLE - else: - health_raw = health_raw.split()[-1] - self.health = 100 - float(health_raw.strip('%')) - - temp_raw = self._parse_re('Temperature\s*(.+?)\n', self.ssd_info) - if temp_raw == NOT_AVAILABLE: - self.temperature = NOT_AVAILABLE - else: - temp_raw = temp_raw.split()[-2] - self.temperature = float(temp_raw) - else: - self.model = self._parse_re('Device Model:\s*(.+?)\n', self.ssd_info) - - health_raw = self._parse_re('Remaining_Lifetime_Perc\s*(.+?)\n', self.ssd_info) - if health_raw == NOT_AVAILABLE: - self.health = NOT_AVAILABLE - else: - self.health = health_raw.split()[-1] - - temp_raw = self._parse_re('Temperature_Celsius\s*(.+?)\n', self.ssd_info) - if temp_raw == NOT_AVAILABLE: - self.temperature = NOT_AVAILABLE - else: - self.temperature = temp_raw.split()[-6] - - self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) - self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) - - def parse_innodisk_info(self): - if self.vendor_ssd_info: - self.health = self._parse_re('Health:\s*(.+?)%', self.vendor_ssd_info) - self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info) - else: - if self.health == NOT_AVAILABLE: - health_raw = self.parse_id_number(INNODISK_HEALTH_ID) - self.health = health_raw.split()[-1] - if self.temperature == NOT_AVAILABLE: - temp_raw = self.parse_id_number(INNODISK_TEMPERATURE_ID) - self.temperature = temp_raw.split()[-6] - - def parse_virtium_info(self): - if self.vendor_ssd_info: - self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) - nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) - avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) - try: - self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance)) - except (ValueError, ZeroDivisionError): - pass - - def fetch_vendor_ssd_info(self, diskdev, model): - self.vendor_ssd_info = self._execute_shell(self.vendor_ssd_utility[model]["utility"].format(diskdev)) - - def parse_vendor_ssd_info(self, model): - self.vendor_ssd_utility[model]["parser"]() - - def get_health(self): - """ - Retrieves current disk health in percentages - - Returns: - A float number of current ssd health - e.g. 83.5 - """ - return self.health - - def get_temperature(self): - """ - Retrieves current disk temperature in Celsius - - Returns: - A float number of current temperature in Celsius - e.g. 40.1 - """ - return self.temperature - - def get_model(self): - """ - Retrieves model for the given disk device - - Returns: - A string holding disk model as provided by the manufacturer - """ - return self.model - - def get_firmware(self): - """ - Retrieves firmware version for the given disk device - - Returns: - A string holding disk firmware version as provided by the manufacturer - """ - return self.firmware - - def get_serial(self): - """ - Retrieves serial number for the given disk device - - Returns: - A string holding disk serial number as provided by the manufacturer - """ - return self.serial - - def get_vendor_output(self): - """ - Retrieves vendor specific data for the given disk device - - Returns: - A string holding some vendor specific disk information - """ - return self.vendor_ssd_info - - def parse_id_number(self, id): - return self._parse_re('{}\s*(.+?)\n'.format(id), self.ssd_info) diff --git a/sonic_platform_base/sonic_thermal_control/__init__.py b/sonic_platform_base/sonic_thermal_control/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_thermal_control/thermal_action_base.py b/sonic_platform_base/sonic_thermal_control/thermal_action_base.py deleted file mode 100644 index ee5373794..000000000 --- a/sonic_platform_base/sonic_thermal_control/thermal_action_base.py +++ /dev/null @@ -1,17 +0,0 @@ -from .thermal_json_object import ThermalJsonObject - - -class ThermalPolicyActionBase(ThermalJsonObject): - """ - Base class for thermal action. Once all thermal conditions in a thermal policy are matched, - all predefined thermal action will be executed. - """ - def execute(self, thermal_info_dict): - """ - Take action when thermal condition matches. For example, adjust speed of fan or shut - down the switch. - :param thermal_info_dict: A dictionary stores all thermal information. - :return: - """ - raise NotImplementedError - diff --git a/sonic_platform_base/sonic_thermal_control/thermal_condition_base.py b/sonic_platform_base/sonic_thermal_control/thermal_condition_base.py deleted file mode 100644 index 2196efad1..000000000 --- a/sonic_platform_base/sonic_thermal_control/thermal_condition_base.py +++ /dev/null @@ -1,14 +0,0 @@ -from .thermal_json_object import ThermalJsonObject - - -class ThermalPolicyConditionBase(ThermalJsonObject): - """ - Base class for thermal condition - """ - def is_match(self, thermal_info_dict): - """ - Indicate if this condition is matched. - :param thermal_info_dict: A dictionary stores all thermal information. - :return: True if condition matched else False. - """ - raise NotImplementedError diff --git a/sonic_platform_base/sonic_thermal_control/thermal_info_base.py b/sonic_platform_base/sonic_thermal_control/thermal_info_base.py deleted file mode 100644 index 32aa06ee0..000000000 --- a/sonic_platform_base/sonic_thermal_control/thermal_info_base.py +++ /dev/null @@ -1,15 +0,0 @@ -from .thermal_json_object import ThermalJsonObject - - -class ThermalPolicyInfoBase(object): - """ - Base class for thermal information - """ - def collect(self, chassis): - """ - Collect thermal information for thermal policy. - :param chassis: The chassis object. - :return: - """ - raise NotImplementedError - diff --git a/sonic_platform_base/sonic_thermal_control/thermal_json_object.py b/sonic_platform_base/sonic_thermal_control/thermal_json_object.py deleted file mode 100644 index 243d337ed..000000000 --- a/sonic_platform_base/sonic_thermal_control/thermal_json_object.py +++ /dev/null @@ -1,72 +0,0 @@ -class ThermalJsonObject(object): - """ - Base class for thermal json object. - """ - # JSON field definition - JSON_FIELD_TYPE = 'type' - - # Dictionary of ThermalJsonObject-derived class representing all thermal json types - _object_type_dict = {} - - def load_from_json(self, json_obj): - """ - Initialize this object by a json object. The json object is read from policy json file. - Derived class can define any field in policy json file and interpret them in this function. - :param json_obj: A json object representing an object. - :return: - """ - pass - - def __eq__(self, other): - """ - Compare input object with this object, return True if equal. Subclass should override this - if necessary. - :param other: Object to compare with. - :return: True if equal else False - """ - return self.__class__ == other.__class__ - - @classmethod - def register_concrete_type(cls, type_name, object_type): - """ - Register a concrete class by type name. The concrete class must derive from - ThermalJsonObject. - :param type_name: Name of the class. - :param object_type: A concrete class. - :return: - """ - if type_name not in cls._object_type_dict: - cls._object_type_dict[type_name] = object_type - else: - raise Exception('ThermalJsonObject type {} already exists'.format(type_name)) - - @classmethod - def get_type(cls, json_obj): - """ - Get a concrete class by json object. The json object represents an object and must - have a 'type' field. This function returns a pre-registered concrete class if the specific - 'type' is found. - :param json_obj: A json object representing an action. - :return: A concrete class if requested type exists; Otherwise None. - """ - if ThermalJsonObject.JSON_FIELD_TYPE in json_obj: - type_str = json_obj[ThermalJsonObject.JSON_FIELD_TYPE] - if type_str in cls._object_type_dict: - return cls._object_type_dict[type_str] - else: - raise Exception('ThermalJsonObject type {} not found'.format(type_str) ) - - raise Exception('Invalid policy file, {} field must be presented'.format(ThermalJsonObject.JSON_FIELD_TYPE)) - - -def thermal_json_object(type_name): - """ - Decorator to auto register a ThermalJsonObject-derived class - :param type_name: Type name of the concrete class which corresponding to the 'type' field of - a condition, action or info. - :return: Wrapper function - """ - def wrapper(object_type): - ThermalJsonObject.register_concrete_type(type_name, object_type) - return object_type - return wrapper diff --git a/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py b/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py deleted file mode 100644 index 6292978fb..000000000 --- a/sonic_platform_base/sonic_thermal_control/thermal_manager_base.py +++ /dev/null @@ -1,232 +0,0 @@ -import json -from .thermal_policy import ThermalPolicy -from .thermal_json_object import ThermalJsonObject - - -class ThermalManagerBase(object): - """ - Base class of ThermalManager representing a manager to control all thermal policies. - """ - # JSON field definition. - JSON_FIELD_POLICIES = 'policies' - JSON_FIELD_INFO_TYPES = 'info_types' - JSON_FIELD_POLICY_NAME = 'name' - JSON_FIELD_THERMAL_ALGORITHM = "thermal_control_algorithm" - JSON_FIELD_FAN_SPEED_WHEN_SUSPEND = "fan_speed_when_suspend" - JSON_FIELD_RUN_AT_BOOT_UP = "run_at_boot_up" - JSON_FIELD_INTERVAL = "interval" - - # Dictionary of ThermalPolicy objects. - _policy_dict = {} - - # Dictionary of thermal information objects. A thermal information object is used by Thermal Policy - _thermal_info_dict = {} - - _fan_speed_when_suspend = None - - _run_thermal_algorithm_at_boot_up = None - - _interval = 60 - - _running = True - - @classmethod - def initialize(cls): - """ - Initialize thermal manager, including register thermal condition types and thermal action types - and any other vendor specific initialization. - :return: - """ - pass - - @classmethod - def deinitialize(cls): - """ - Destroy thermal manager, including any vendor specific cleanup. The default behavior of this function - is a no-op. - :return: - """ - pass - - @classmethod - def stop(cls): - """ - Stop thermal manager. - :return: - """ - cls._running = False - - @classmethod - def start_thermal_control_algorithm(cls): - """ - Start vendor specific thermal control algorithm. The default behavior of this function is a no-op. - :return: - """ - pass - - @classmethod - def stop_thermal_control_algorithm(cls): - """ - Stop vendor specific thermal control algorithm. The default behavior of this function is a no-op. - :return: - """ - pass - - @classmethod - def load(cls, policy_file_name): - """ - Load all thermal policies from JSON policy file. An example looks like: - { - "thermal_control_algorithm": { - "run_at_boot_up": "false", - "fan_speed_when_suspend": "60" - }, - "info_types": [ - { - "type": "fan_info" # collect fan information for each iteration - }, - { - "type": "psu_info" # collect psu information for each iteration - } - ], - "policies": [ - { - "name": "any fan absence", # if any fan absence, set all fan speed to 100% and disable thermal control algorithm - "conditions": [ - { - "type": "fan.any.absence" # see sonic-platform-daemons.sonic-thermalctld.thermal_policy.thermal_conditions - } - ], - "actions": [ - { - "type": "fan.all.set_speed", # see sonic-platform-daemons.sonic-thermalctld.thermal_policy.thermal_actions - "speed": "100" - }, - { - "type": "thermal_control.control", - "status": "false" - } - ] - }, - { - "name": "all fan absence", # if all fan absence, shutdown the switch - "conditions": [ - { - "type": "fan.all.absence" - } - ], - "actions": [ - { - "type": "switch.shutdown" - } - ] - } - ], - "interval": "30", - } - :param policy_file_name: Path of JSON policy file. - :return: - """ - with open(policy_file_name, 'r') as policy_file: - json_obj = json.load(policy_file) - if cls.JSON_FIELD_POLICIES in json_obj: - json_policies = json_obj[cls.JSON_FIELD_POLICIES] - for json_policy in json_policies: - cls._load_policy(json_policy) - - if cls.JSON_FIELD_INFO_TYPES in json_obj: - for json_info in json_obj[cls.JSON_FIELD_INFO_TYPES]: - info_type = ThermalJsonObject.get_type(json_info) - info_obj = info_type() - cls._thermal_info_dict[json_info[ThermalJsonObject.JSON_FIELD_TYPE]] = info_obj - - if cls.JSON_FIELD_THERMAL_ALGORITHM in json_obj: - json_thermal_algorithm_config = json_obj[cls.JSON_FIELD_THERMAL_ALGORITHM] - if cls.JSON_FIELD_RUN_AT_BOOT_UP in json_thermal_algorithm_config: - cls._run_thermal_algorithm_at_boot_up = \ - True if json_thermal_algorithm_config[cls.JSON_FIELD_RUN_AT_BOOT_UP].lower() == 'true' else False - - if cls.JSON_FIELD_FAN_SPEED_WHEN_SUSPEND in json_thermal_algorithm_config: - # if the string is not a valid int, let it raise - cls._fan_speed_when_suspend = \ - int(json_thermal_algorithm_config[cls.JSON_FIELD_FAN_SPEED_WHEN_SUSPEND]) - - if cls.JSON_FIELD_INTERVAL in json_obj: - cls._interval = int(json_obj[cls.JSON_FIELD_INTERVAL]) - - - @classmethod - def _load_policy(cls, json_policy): - """ - Load a policy object from a JSON object. - :param json_policy: A JSON object representing a thermal policy. - :return: - """ - if cls.JSON_FIELD_POLICY_NAME in json_policy: - name = json_policy[cls.JSON_FIELD_POLICY_NAME] - if name in cls._policy_dict: - raise Exception('Policy {} already exists'.format(name)) - - policy = ThermalPolicy() - policy.load_from_json(json_policy) - policy.validate_duplicate_policy(cls._policy_dict.values()) - cls._policy_dict[name] = policy - else: - raise Exception('{} not found in policy'.format(cls.JSON_FIELD_POLICY_NAME)) - - @classmethod - def run_policy(cls, chassis): - """ - Collect thermal information, run each policy, if one policy matches, execute the policy's action. - :param chassis: The chassis object. - :return: - """ - if not cls._policy_dict: - return - - cls._collect_thermal_information(chassis) - - for policy in cls._policy_dict.values(): - if not cls._running: - return - if policy.is_match(cls._thermal_info_dict): - policy.do_action(cls._thermal_info_dict) - - @classmethod - def _collect_thermal_information(cls, chassis): - """ - Collect thermal information. This function will be called before run_policy. - :param chassis: The chassis object. - :return: - """ - for thermal_info in cls._thermal_info_dict.values(): - if not cls._running: - return - thermal_info.collect(chassis) - - @classmethod - def init_thermal_algorithm(cls, chassis): - """ - Initialize thermal algorithm according to policy file. - :param chassis: The chassis object. - :return: - """ - if cls._run_thermal_algorithm_at_boot_up is not None: - if cls._run_thermal_algorithm_at_boot_up: - cls.start_thermal_control_algorithm() - else: - cls.stop_thermal_control_algorithm() - if cls._fan_speed_when_suspend is not None: - for fan in chassis.get_all_fans(): - fan.set_speed(cls._fan_speed_when_suspend) - - for psu in chassis.get_all_psus(): - for fan in psu.get_all_fans(): - fan.set_speed(cls._fan_speed_when_suspend) - - @classmethod - def get_interval(cls): - """ - Get the wait interval for executing thermal policies - """ - return cls._interval diff --git a/sonic_platform_base/sonic_thermal_control/thermal_policy.py b/sonic_platform_base/sonic_thermal_control/thermal_policy.py deleted file mode 100644 index eeb1962ab..000000000 --- a/sonic_platform_base/sonic_thermal_control/thermal_policy.py +++ /dev/null @@ -1,89 +0,0 @@ -from .thermal_json_object import ThermalJsonObject -from collections import OrderedDict - - -class ThermalPolicy(object): - """ - Class representing a thermal policy. A thermal policy object is initialized by JSON policy file. - """ - # JSON field definition. - JSON_FIELD_NAME = 'name' - JSON_FIELD_CONDITIONS = 'conditions' - JSON_FIELD_ACTIONS = 'actions' - - def __init__(self): - # Name of the policy - self.name = None - - # Conditions load from JSON policy file - self.conditions = OrderedDict() - - # Actions load from JSON policy file - self.actions = OrderedDict() - - def load_from_json(self, json_obj): - """ - Load thermal policy from JSON policy file. - :param json_obj: A json object representing a thermal policy. - :return: - """ - if self.JSON_FIELD_NAME in json_obj: - self.name = json_obj[self.JSON_FIELD_NAME] - - if self.JSON_FIELD_CONDITIONS in json_obj: - for json_condition in json_obj[self.JSON_FIELD_CONDITIONS]: - cond_type = ThermalJsonObject.get_type(json_condition) - if cond_type in self.conditions: - raise Exception('Duplicate thermal condition type detected in policy [{}]!'.format(self.name)) - cond_obj = cond_type() - cond_obj.load_from_json(json_condition) - self.conditions[cond_type] = cond_obj - - if self.JSON_FIELD_ACTIONS in json_obj: - for json_action in json_obj[self.JSON_FIELD_ACTIONS]: - action_type = ThermalJsonObject.get_type(json_action) - if action_type in self.actions: - raise Exception('Duplicate thermal action type detected in policy [{}]!'.format(self.name)) - action_obj = action_type() - action_obj.load_from_json(json_action) - self.actions[action_type] = action_obj - - if not len(self.conditions) or not len(self.actions): - raise Exception('A policy requires at least 1 action and 1 condition') - else: - raise Exception('name field not found in policy') - - def is_match(self, thermal_info_dict): - """ - Indicate if this policy is match. - :param thermal_info_dict: A dictionary stores all thermal information. - :return: True if all conditions matches else False. - """ - for condition in self.conditions.values(): - if not condition.is_match(thermal_info_dict): - return False - - return True - - def do_action(self, thermal_info_dict): - """ - Execute all actions if is_match returns True. - :param thermal_info_dict: A dictionary stores all thermal information. - :return: - """ - for action in self.actions.values(): - action.execute(thermal_info_dict) - - def validate_duplicate_policy(self, policies): - """ - Detect this policy with existing policies, if a policy with same conditions exists, raise Exception. - :param policies: existing policies. - :return: - """ - for policy in policies: - if len(policy.conditions) != len(self.conditions): - continue - - for cond_type, value in policy.conditions.items(): - if cond_type in self.conditions and policy.conditions[cond_type] == self.conditions[cond_type]: - raise Exception('Policy [{}] and policy [{}] have duplicate conditions'.format(policy.name, self.name)) diff --git a/sonic_platform_base/sonic_xcvr/__init__.py b/sonic_platform_base/sonic_xcvr/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/api/__init__.py b/sonic_platform_base/sonic_xcvr/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/api/public/__init__.py b/sonic_platform_base/sonic_xcvr/api/public/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/api/public/c_cmis.py b/sonic_platform_base/sonic_xcvr/api/public/c_cmis.py deleted file mode 100644 index 6929d2614..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/c_cmis.py +++ /dev/null @@ -1,935 +0,0 @@ -""" - c-cmis.py - - Implementation of XcvrApi that corresponds to C-CMIS -""" -from sonic_py_common import logger -from ...fields import consts -from .cmis import CmisApi -import time -BYTELENGTH = 8 -VDM_FREEZE = 128 -VDM_UNFREEZE = 0 -SYSLOG_IDENTIFIER = "CCmisApi" - -helper_logger = logger.Logger(SYSLOG_IDENTIFIER) - -class CCmisApi(CmisApi): - def __init__(self, xcvr_eeprom): - super(CCmisApi, self).__init__(xcvr_eeprom) - - def get_freq_grid(self): - ''' - This function returns the configured frequency grid. Unit in GHz - ''' - freq_grid = self.xcvr_eeprom.read(consts.GRID_SPACING) - if freq_grid == 7: - return 75 - elif freq_grid == 6: - return 33 - elif freq_grid == 5: - return 100 - elif freq_grid == 4: - return 50 - elif freq_grid == 3: - return 25 - elif freq_grid == 2: - return 12.5 - elif freq_grid == 1: - return 6.25 - elif freq_grid == 0: - return 3.125 - else: - return None - - def get_laser_config_freq(self): - ''' - This function returns the configured laser frequency. Unit in GHz - ''' - freq_grid = self.get_freq_grid() - channel = self.xcvr_eeprom.read(consts.LASER_CONFIG_CHANNEL) - if freq_grid == 75: - config_freq = 193100 + channel * freq_grid/3 - else: - config_freq = 193100 + channel * freq_grid - return config_freq - - def get_current_laser_freq(self): - ''' - This function returns the monitored laser frequency. Unit in GHz - ''' - return self.xcvr_eeprom.read(consts.LASER_CURRENT_FREQ) - - def get_tuning_in_progress(self): - ''' - This function returns tuning in progress status on media lane - False means tuning not in progress - True means tuning in progress - ''' - return bool(self.xcvr_eeprom.read(consts.TUNING_IN_PROGRESS)) - - def get_wavelength_unlocked(self): - ''' - This function returns wavelength unlocked status on media lane - False means wavelength locked - True means wavelength unlocked - ''' - return bool(self.xcvr_eeprom.read(consts.WAVELENGTH_UNLOCKED)) - - def get_laser_tuning_summary(self): - ''' - This function returns laser tuning status summary on media lane - ''' - result = self.xcvr_eeprom.read(consts.LASER_TUNING_DETAIL) - laser_tuning_summary = [] - if (result >> 5) & 0x1: - laser_tuning_summary.append("TargetOutputPowerOOR") - if (result >> 4) & 0x1: - laser_tuning_summary.append("FineTuningOutOfRange") - if (result >> 3) & 0x1: - laser_tuning_summary.append("TuningNotAccepted") - if (result >> 2) & 0x1: - laser_tuning_summary.append("InvalidChannel") - if (result >> 1) & 0x1: - laser_tuning_summary.append("WavelengthUnlocked") - if (result >> 0) & 0x1: - laser_tuning_summary.append("TuningComplete") - return laser_tuning_summary - - def get_supported_freq_config(self): - ''' - This function returns the supported freq grid, low and high supported channel in 75/100GHz grid, - and low and high frequency supported in GHz. - allowed channel number bound in 75/100 GHz grid - allowed frequency bound in 75/100 GHz grid - ''' - grid_supported = self.xcvr_eeprom.read(consts.SUPPORT_GRID) - low_ch_num = self.xcvr_eeprom.read(consts.LOW_CHANNEL) - hi_ch_num = self.xcvr_eeprom.read(consts.HIGH_CHANNEL) - low_freq_supported = 193100 + low_ch_num * 25 - high_freq_supported = 193100 + hi_ch_num * 25 - return grid_supported, low_ch_num, hi_ch_num, low_freq_supported, high_freq_supported - - def set_laser_freq(self, freq, grid): - ''' - This function sets the laser frequency. Unit in GHz - ZR application will not support fine tuning of the laser - SONiC will only support 75 GHz and 100GHz frequency grids - Return True if the provision succeeds, False if it fails - ''' - grid_supported, low_ch_num, hi_ch_num, _, _ = self.get_supported_freq_config() - grid_supported_75GHz = (grid_supported >> 7) & 0x1 - grid_supported_100GHz = (grid_supported >> 5) & 0x1 - if grid == 75: - assert grid_supported_75GHz - freq_grid = 0x70 - channel_number = int(round((freq - 193100)/25)) - assert channel_number % 3 == 0 - elif grid == 100: - assert grid_supported_100GHz - freq_grid = 0x50 - channel_number = int(round((freq - 193100)/100)) - else: - return False - self.xcvr_eeprom.write(consts.GRID_SPACING, freq_grid) - if channel_number > hi_ch_num or channel_number < low_ch_num: - raise ValueError('Provisioned frequency out of range. Max Freq: 196100; Min Freq: 191300 GHz.') - status = self.xcvr_eeprom.write(consts.LASER_CONFIG_CHANNEL, channel_number) - return status - - def set_tx_power(self, tx_power): - ''' - This function sets the TX output power. Unit in dBm - Return True if the provision succeeds, False if it fails - ''' - min_prog_tx_output_power, max_prog_tx_output_power = self.get_supported_power_config() - if tx_power > max_prog_tx_output_power or tx_power < min_prog_tx_output_power: - raise ValueError('Provisioned TX power out of range. Max: %.1f; Min: %.1f dBm.' - %(max_prog_tx_output_power, min_prog_tx_output_power)) - status = self.xcvr_eeprom.write(consts.TX_CONFIG_POWER, tx_power) - time.sleep(1) - return status - - def get_pm_all(self): - ''' - This function returns the PMs reported in Page 34h and 35h in OIF C-CMIS document - CD: unit in ps/nm - DGD: unit in ps - SOPMD: unit in ps^2 - PDL: unit in dB - OSNR: unit in dB - ESNR: unit in dB - CFO: unit in MHz - TXpower:unit in dBm - RXpower:unit in dBm - RX sig power: unit in dBm - SOPROC: unit in krad/s - MER: unit in dB - ''' - # When raised by the host, causes the module to freeze and hold all - # reported statistics reporting registers (minimum, maximum and - # average values)in Pages 24h-27h. - # When ceased by the host, releases the freeze request, allowing the - # reported minimum, maximum and average values to update again. - self.xcvr_eeprom.write(consts.VDM_CONTROL, VDM_FREEZE) - time.sleep(1) - self.xcvr_eeprom.write(consts.VDM_CONTROL, VDM_UNFREEZE) - PM_dict = dict() - - rx_bits_pm = self.xcvr_eeprom.read(consts.RX_BITS_PM) - rx_bits_subint_pm = self.xcvr_eeprom.read(consts.RX_BITS_SUB_INTERVAL_PM) - rx_corr_bits_pm = self.xcvr_eeprom.read(consts.RX_CORR_BITS_PM) - rx_min_corr_bits_subint_pm = self.xcvr_eeprom.read(consts.RX_MIN_CORR_BITS_SUB_INTERVAL_PM) - rx_max_corr_bits_subint_pm = self.xcvr_eeprom.read(consts.RX_MAX_CORR_BITS_SUB_INTERVAL_PM) - - if (rx_bits_subint_pm != 0) and (rx_bits_pm != 0): - PM_dict['preFEC_BER_avg'] = rx_corr_bits_pm*1.0/rx_bits_pm - PM_dict['preFEC_BER_min'] = rx_min_corr_bits_subint_pm*1.0/rx_bits_subint_pm - PM_dict['preFEC_BER_max'] = rx_max_corr_bits_subint_pm*1.0/rx_bits_subint_pm - # when module is low power, still need these values to show 1.0 - else: - PM_dict['preFEC_BER_avg'] = 1.0 - PM_dict['preFEC_BER_min'] = 1.0 - PM_dict['preFEC_BER_max'] = 1.0 - rx_frames_pm = self.xcvr_eeprom.read(consts.RX_FRAMES_PM) - rx_frames_subint_pm = self.xcvr_eeprom.read(consts.RX_FRAMES_SUB_INTERVAL_PM) - rx_frames_uncorr_err_pm = self.xcvr_eeprom.read(consts.RX_FRAMES_UNCORR_ERR_PM) - rx_min_frames_uncorr_err_subint_pm = self.xcvr_eeprom.read(consts.RX_MIN_FRAMES_UNCORR_ERR_SUB_INTERVAL_PM) - rx_max_frames_uncorr_err_subint_pm = self.xcvr_eeprom.read(consts.RX_MAX_FRAMES_UNCORR_ERR_SUB_INTERVAL_PM) - - if (rx_frames_subint_pm != 0) and (rx_frames_pm != 0): - PM_dict['preFEC_uncorr_frame_ratio_avg'] = rx_frames_uncorr_err_pm*1.0/rx_frames_subint_pm - PM_dict['preFEC_uncorr_frame_ratio_min'] = rx_min_frames_uncorr_err_subint_pm*1.0/rx_frames_subint_pm - PM_dict['preFEC_uncorr_frame_ratio_max'] = rx_max_frames_uncorr_err_subint_pm*1.0/rx_frames_subint_pm - # when module is low power, still need these values - else: - PM_dict['preFEC_uncorr_frame_ratio_avg'] = 0 - PM_dict['preFEC_uncorr_frame_ratio_min'] = 0 - PM_dict['preFEC_uncorr_frame_ratio_max'] = 0 - PM_dict['rx_cd_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_CD_PM) - PM_dict['rx_cd_min'] = self.xcvr_eeprom.read(consts.RX_MIN_CD_PM) - PM_dict['rx_cd_max'] = self.xcvr_eeprom.read(consts.RX_MAX_CD_PM) - - PM_dict['rx_dgd_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_DGD_PM) - PM_dict['rx_dgd_min'] = self.xcvr_eeprom.read(consts.RX_MIN_DGD_PM) - PM_dict['rx_dgd_max'] = self.xcvr_eeprom.read(consts.RX_MAX_DGD_PM) - - PM_dict['rx_sopmd_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_SOPMD_PM) - PM_dict['rx_sopmd_min'] = self.xcvr_eeprom.read(consts.RX_MIN_SOPMD_PM) - PM_dict['rx_sopmd_max'] = self.xcvr_eeprom.read(consts.RX_MAX_SOPMD_PM) - - PM_dict['rx_pdl_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_PDL_PM) - PM_dict['rx_pdl_min'] = self.xcvr_eeprom.read(consts.RX_MIN_PDL_PM) - PM_dict['rx_pdl_max'] = self.xcvr_eeprom.read(consts.RX_MAX_PDL_PM) - - PM_dict['rx_osnr_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_OSNR_PM) - PM_dict['rx_osnr_min'] = self.xcvr_eeprom.read(consts.RX_MIN_OSNR_PM) - PM_dict['rx_osnr_max'] = self.xcvr_eeprom.read(consts.RX_MAX_OSNR_PM) - - PM_dict['rx_esnr_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_ESNR_PM) - PM_dict['rx_esnr_min'] = self.xcvr_eeprom.read(consts.RX_MIN_ESNR_PM) - PM_dict['rx_esnr_max'] = self.xcvr_eeprom.read(consts.RX_MAX_ESNR_PM) - - PM_dict['rx_cfo_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_CFO_PM) - PM_dict['rx_cfo_min'] = self.xcvr_eeprom.read(consts.RX_MIN_CFO_PM) - PM_dict['rx_cfo_max'] = self.xcvr_eeprom.read(consts.RX_MAX_CFO_PM) - - PM_dict['rx_evm_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_EVM_PM) - PM_dict['rx_evm_min'] = self.xcvr_eeprom.read(consts.RX_MIN_EVM_PM) - PM_dict['rx_evm_max'] = self.xcvr_eeprom.read(consts.RX_MAX_EVM_PM) - - PM_dict['tx_power_avg'] = self.xcvr_eeprom.read(consts.TX_AVG_POWER_PM) - PM_dict['tx_power_min'] = self.xcvr_eeprom.read(consts.TX_MIN_POWER_PM) - PM_dict['tx_power_max'] = self.xcvr_eeprom.read(consts.TX_MAX_POWER_PM) - - PM_dict['rx_power_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_POWER_PM) - PM_dict['rx_power_min'] = self.xcvr_eeprom.read(consts.RX_MIN_POWER_PM) - PM_dict['rx_power_max'] = self.xcvr_eeprom.read(consts.RX_MAX_POWER_PM) - - PM_dict['rx_sigpwr_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_SIG_POWER_PM) - PM_dict['rx_sigpwr_min'] = self.xcvr_eeprom.read(consts.RX_MIN_SIG_POWER_PM) - PM_dict['rx_sigpwr_max'] = self.xcvr_eeprom.read(consts.RX_MAX_SIG_POWER_PM) - - PM_dict['rx_soproc_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_SOPROC_PM) - PM_dict['rx_soproc_min'] = self.xcvr_eeprom.read(consts.RX_MIN_SOPROC_PM) - PM_dict['rx_soproc_max'] = self.xcvr_eeprom.read(consts.RX_MAX_SOPROC_PM) - - PM_dict['rx_mer_avg'] = self.xcvr_eeprom.read(consts.RX_AVG_MER_PM) - PM_dict['rx_mer_min'] = self.xcvr_eeprom.read(consts.RX_MIN_MER_PM) - PM_dict['rx_mer_max'] = self.xcvr_eeprom.read(consts.RX_MAX_MER_PM) - return PM_dict - - - def get_transceiver_info(self): - """ - Retrieves transceiver info of this SFP - - Returns: - A dict which contains following keys/values : - ================================================================================ - key = TRANSCEIVER_INFO|ifname ; information for module on port - ; field = value - module_media_type = 1*255VCHAR ; module media interface ID - host_electrical_interface = 1*255VCHAR ; host electrical interface ID - media_interface_code = 1*255VCHAR ; media interface code - host_lane_count = INTEGER ; host lane count - media_lane_count = INTEGER ; media lane count - host_lane_assignment_option = INTEGER ; permissible first host lane number for application - media_lane_assignment_option = INTEGER ; permissible first media lane number for application - active_apsel_hostlane1 = INTEGER ; active application selected code assigned to host lane 1 - active_apsel_hostlane2 = INTEGER ; active application selected code assigned to host lane 2 - active_apsel_hostlane3 = INTEGER ; active application selected code assigned to host lane 3 - active_apsel_hostlane4 = INTEGER ; active application selected code assigned to host lane 4 - active_apsel_hostlane5 = INTEGER ; active application selected code assigned to host lane 5 - active_apsel_hostlane6 = INTEGER ; active application selected code assigned to host lane 6 - active_apsel_hostlane7 = INTEGER ; active application selected code assigned to host lane 7 - active_apsel_hostlane8 = INTEGER ; active application selected code assigned to host lane 8 - media_interface_technology = 1*255VCHAR ; media interface technology - hardwarerev = 1*255VCHAR ; module hardware revision - serialnum = 1*255VCHAR ; module serial number - manufacturename = 1*255VCHAR ; module venndor name - modelname = 1*255VCHAR ; module model name - vendor_rev = 1*255VCHAR ; module vendor revision - vendor_oui = 1*255VCHAR ; vendor organizationally unique identifier - vendor_date = 1*255VCHAR ; module manufacture date - connector_type = 1*255VCHAR ; connector type - specification_compliance = 1*255VCHAR ; electronic or optical interfaces that supported - active_firmware = 1*255VCHAR ; active firmware - inactive_firmware = 1*255VCHAR ; inactive firmware - supported_max_tx_power = FLOAT ; support maximum tx power - supported_min_tx_power = FLOAT ; support minimum tx power - supported_max_laser_freq = FLOAT ; support maximum laser frequency - supported_min_laser_freq = FLOAT ; support minimum laser frequency - ================================================================================ - """ - trans_info = super(CCmisApi,self).get_transceiver_info() - min_power, max_power = self.get_supported_power_config() - trans_info['supported_max_tx_power'] = max_power - trans_info['supported_min_tx_power'] = min_power - _, _, _, low_freq_supported, high_freq_supported = self.get_supported_freq_config() - trans_info['supported_max_laser_freq'] = high_freq_supported - trans_info['supported_min_laser_freq'] = low_freq_supported - return trans_info - - def get_transceiver_bulk_status(self): - """ - Retrieves bulk status info for this xcvr - - Returns: - A dict containing the following keys/values : - ======================================================================== - key = TRANSCEIVER_DOM_SENSOR|ifname ; information module DOM sensors on port - ; field = value - temperature = FLOAT ; temperature value in Celsius - voltage = FLOAT ; voltage value - txpower = FLOAT ; tx power in mW - rxpower = FLOAT ; rx power in mW - txbias = FLOAT ; tx bias in mA - laser_temperature = FLOAT ; laser temperature value in Celsius - prefec_ber = FLOAT ; prefec ber - postfec_ber = FLOAT ; postfec ber - cd_shortlink = FLOAT ; chromatic dispersion, high granularity, short link in ps/nm - cd_longlink = FLOAT ; chromatic dispersion, low granularity, long link in ps/nm - dgd = FLOAT ; differential group delay in ps - sopmd = FLOAT ; second order polarization mode dispersion in ps^2 - pdl = FLOAT ; polarization dependent loss in db - osnr = FLOAT ; optical signal to noise ratio in db - esnr = FLOAT ; electrical signal to noise ratio in db - cfo = FLOAT ; carrier frequency offset in MHz - soproc = FLOAT ; state of polarization rate of change in krad/s - laser_config_freq = FLOAT ; laser configured frequency in MHz - laser_curr_freq = FLOAT ; laser current frequency in MHz - tx_config_power = FLOAT ; configured tx output power in dbm - tx_curr_power = FLOAT ; tx current output power in dbm - rx_tot_power = FLOAT ; rx total power in dbm - rx_sig_power = FLOAT ; rx signal power in dbm - bias_xi = FLOAT ; modulator bias xi - bias_xq = FLOAT ; modulator bias xq - bias_xp = FLOAT ; modulator bias xp - bias_yi = FLOAT ; modulator bias yi - bias_yq = FLOAT ; modulator bias yq - bias_yp = FLOAT ; modulator bias yp - ======================================================================== - """ - trans_dom = super(CCmisApi,self).get_transceiver_bulk_status() - trans_dom['bias_xi'] = self.vdm_dict['Modulator Bias X/I [%]'][1][0] - trans_dom['bias_xq'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][0] - trans_dom['bias_xp'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][0] - trans_dom['bias_yi'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][0] - trans_dom['bias_yq'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][0] - trans_dom['bias_yp'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][0] - trans_dom['cd_shortlink'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][0] - try: - trans_dom['cd_longlink'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][0] - except KeyError: - pass - trans_dom['dgd'] = self.vdm_dict['DGD [ps]'][1][0] - try: - trans_dom['sopmd'] = self.vdm_dict['SOPMD [ps^2]'][1][0] - except KeyError: - pass - trans_dom['soproc'] = self.vdm_dict['SOP ROC [krad/s]'][1][0] - trans_dom['pdl'] = self.vdm_dict['PDL [dB]'][1][0] - trans_dom['osnr'] = self.vdm_dict['OSNR [dB]'][1][0] - trans_dom['esnr'] = self.vdm_dict['eSNR [dB]'][1][0] - trans_dom['cfo'] = self.vdm_dict['CFO [MHz]'][1][0] - trans_dom['tx_curr_power'] = self.vdm_dict['Tx Power [dBm]'][1][0] - trans_dom['rx_tot_power'] = self.vdm_dict['Rx Total Power [dBm]'][1][0] - try: - trans_dom['rx_sig_power'] = self.vdm_dict['Rx Signal Power [dBm]'][1][0] - except KeyError: - pass - trans_dom['laser_config_freq'] = self.get_laser_config_freq() - trans_dom['laser_curr_freq'] = self.get_current_laser_freq() - trans_dom['tx_config_power'] = self.get_tx_config_power() - return trans_dom - - def get_transceiver_threshold_info(self): - """ - Retrieves threshold info for this xcvr - - Returns: - A dict containing the following keys/values : - ======================================================================== - key = TRANSCEIVER_STATUS|ifname ; DOM threshold information for module on port - ; field = value - temphighalarm = FLOAT ; temperature high alarm threshold in Celsius - temphighwarning = FLOAT ; temperature high warning threshold in Celsius - templowalarm = FLOAT ; temperature low alarm threshold in Celsius - templowwarning = FLOAT ; temperature low warning threshold in Celsius - vcchighalarm = FLOAT ; vcc high alarm threshold in V - vcchighwarning = FLOAT ; vcc high warning threshold in V - vcclowalarm = FLOAT ; vcc low alarm threshold in V - vcclowwarning = FLOAT ; vcc low warning threshold in V - txpowerhighalarm = FLOAT ; tx power high alarm threshold in mW - txpowerlowalarm = FLOAT ; tx power low alarm threshold in mW - txpowerhighwarning = FLOAT ; tx power high warning threshold in mW - txpowerlowwarning = FLOAT ; tx power low alarm threshold in mW - rxpowerhighalarm = FLOAT ; rx power high alarm threshold in mW - rxpowerlowalarm = FLOAT ; rx power low alarm threshold in mW - rxpowerhighwarning = FLOAT ; rx power high warning threshold in mW - rxpowerlowwarning = FLOAT ; rx power low warning threshold in mW - txbiashighalarm = FLOAT ; tx bias high alarm threshold in mA - txbiaslowalarm = FLOAT ; tx bias low alarm threshold in mA - txbiashighwarning = FLOAT ; tx bias high warning threshold in mA - txbiaslowwarning = FLOAT ; tx bias low warning threshold in mA - lasertemphighalarm = FLOAT ; laser temperature high alarm threshold in Celsius - lasertemplowalarm = FLOAT ; laser temperature low alarm threshold in Celsius - lasertemphighwarning = FLOAT ; laser temperature high warning threshold in Celsius - lasertemplowwarning = FLOAT ; laser temperature low warning threshold in Celsius - prefecberhighalarm = FLOAT ; prefec ber high alarm threshold - prefecberlowalarm = FLOAT ; prefec ber low alarm threshold - prefecberhighwarning = FLOAT ; prefec ber high warning threshold - prefecberlowwarning = FLOAT ; prefec ber low warning threshold - postfecberhighalarm = FLOAT ; postfec ber high alarm threshold - postfecberlowalarm = FLOAT ; postfec ber low alarm threshold - postfecberhighwarning = FLOAT ; postfec ber high warning threshold - postfecberlowwarning = FLOAT ; postfec ber low warning threshold - biasxihighalarm = FLOAT ; bias xi high alarm threshold in percent - biasxilowalarm = FLOAT ; bias xi low alarm threshold in percent - biasxihighwarning = FLOAT ; bias xi high warning threshold in percent - biasxilowwarning = FLOAT ; bias xi low warning threshold in percent - biasxqhighalarm = FLOAT ; bias xq high alarm threshold in percent - biasxqlowalarm = FLOAT ; bias xq low alarm threshold in percent - biasxqhighwarning = FLOAT ; bias xq high warning threshold in percent - biasxqlowwarning = FLOAT ; bias xq low warning threshold in percent - biasxphighalarm = FLOAT ; bias xp high alarm threshold in percent - biasxplowalarm = FLOAT ; bias xp low alarm threshold in percent - biasxphighwarning = FLOAT ; bias xp high warning threshold in percent - biasxplowwarning = FLOAT ; bias xp low warning threshold in percent - biasyihighalarm = FLOAT ; bias yi high alarm threshold in percent - biasyilowalarm = FLOAT ; bias yi low alarm threshold in percent - biasyihighwarning = FLOAT ; bias yi high warning threshold in percent - biasyilowwarning = FLOAT ; bias yi low warning threshold in percent - biasyqhighalarm = FLOAT ; bias yq high alarm threshold in percent - biasyqlowalarm = FLOAT ; bias yq low alarm threshold in percent - biasyqhighwarning = FLOAT ; bias yq high warning threshold in percent - biasyqlowwarning = FLOAT ; bias yq low warning threshold in percent - biasyphighalarm = FLOAT ; bias yp high alarm threshold in percent - biasyplowalarm = FLOAT ; bias yp low alarm threshold in percent - biasyphighwarning = FLOAT ; bias yp high warning threshold in percent - biasyplowwarning = FLOAT ; bias yp low warning threshold in percent - cdshorthighalarm = FLOAT ; cd short high alarm threshold in ps/nm - cdshortlowalarm = FLOAT ; cd short low alarm threshold in ps/nm - cdshorthighwarning = FLOAT ; cd short high warning threshold in ps/nm - cdshortlowwarning = FLOAT ; cd short low warning threshold in ps/nm - cdlonghighalarm = FLOAT ; cd long high alarm threshold in ps/nm - cdlonglowalarm = FLOAT ; cd long low alarm threshold in ps/nm - cdlonghighwarning = FLOAT ; cd long high warning threshold in ps/nm - cdlonglowwarning = FLOAT ; cd long low warning threshold in ps/nm - dgdhighalarm = FLOAT ; dgd high alarm threshold in ps - dgdlowalarm = FLOAT ; dgd low alarm threshold in ps - dgdhighwarning = FLOAT ; dgd high warning threshold in ps - dgdlowwarning = FLOAT ; dgd low warning threshold in ps - sopmdhighalarm = FLOAT ; sopmd high alarm threshold in ps^2 - sopmdlowalarm = FLOAT ; sopmd low alarm threshold in ps^2 - sopmdhighwarning = FLOAT ; sopmd high warning threshold in ps^2 - sopmdlowwarning = FLOAT ; sopmd low warning threshold in ps^2 - pdlhighalarm = FLOAT ; pdl high alarm threshold in db - pdllowalarm = FLOAT ; pdl low alarm threshold in db - pdlhighwarning = FLOAT ; pdl high warning threshold in db - pdllowwarning = FLOAT ; pdl low warning threshold in db - osnrhighalarm = FLOAT ; osnr high alarm threshold in db - osnrlowalarm = FLOAT ; osnr low alarm threshold in db - osnrhighwarning = FLOAT ; osnr high warning threshold in db - osnrlowwarning = FLOAT ; osnr low warning threshold in db - esnrhighalarm = FLOAT ; esnr high alarm threshold in db - esnrlowalarm = FLOAT ; esnr low alarm threshold in db - esnrhighwarning = FLOAT ; esnr high warning threshold in db - esnrlowwarning = FLOAT ; esnr low warning threshold in db - cfohighalarm = FLOAT ; cfo high alarm threshold in MHz - cfolowalarm = FLOAT ; cfo low alarm threshold in MHz - cfohighwarning = FLOAT ; cfo high warning threshold in MHz - cfolowwarning = FLOAT ; cfo low warning threshold in MHz - txcurrpowerhighalarm = FLOAT ; txcurrpower high alarm threshold in dbm - txcurrpowerlowalarm = FLOAT ; txcurrpower low alarm threshold in dbm - txcurrpowerhighwarning = FLOAT ; txcurrpower high warning threshold in dbm - txcurrpowerlowwarning = FLOAT ; txcurrpower low warning threshold in dbm - rxtotpowerhighalarm = FLOAT ; rxtotpower high alarm threshold in dbm - rxtotpowerlowalarm = FLOAT ; rxtotpower low alarm threshold in dbm - rxtotpowerhighwarning = FLOAT ; rxtotpower high warning threshold in dbm - rxtotpowerlowwarning = FLOAT ; rxtotpower low warning threshold in dbm - rxsigpowerhighalarm = FLOAT ; rxsigpower high alarm threshold in dbm - rxsigpowerlowalarm = FLOAT ; rxsigpower low alarm threshold in dbm - rxsigpowerhighwarning = FLOAT ; rxsigpower high warning threshold in dbm - rxsigpowerlowwarning = FLOAT ; rxsigpower low warning threshold in dbm - ======================================================================== - """ - trans_dom_th = super(CCmisApi,self).get_transceiver_threshold_info() - trans_dom_th['biasxihighalarm'] = self.vdm_dict['Modulator Bias X/I [%]'][1][1] - trans_dom_th['biasxilowalarm'] = self.vdm_dict['Modulator Bias X/I [%]'][1][2] - trans_dom_th['biasxihighwarning'] = self.vdm_dict['Modulator Bias X/I [%]'][1][3] - trans_dom_th['biasxilowwarning'] = self.vdm_dict['Modulator Bias X/I [%]'][1][4] - trans_dom_th['biasxqhighalarm'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][1] - trans_dom_th['biasxqlowalarm'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][2] - trans_dom_th['biasxqhighwarning'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][3] - trans_dom_th['biasxqlowwarning'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][4] - trans_dom_th['biasxphighalarm'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][1] - trans_dom_th['biasxplowalarm'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][2] - trans_dom_th['biasxphighwarning'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][3] - trans_dom_th['biasxplowwarning'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][4] - trans_dom_th['biasyihighalarm'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][1] - trans_dom_th['biasyilowalarm'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][2] - trans_dom_th['biasyihighwarning'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][3] - trans_dom_th['biasyilowwarning'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][4] - trans_dom_th['biasyqhighalarm'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][1] - trans_dom_th['biasyqlowalarm'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][2] - trans_dom_th['biasyqhighwarning'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][3] - trans_dom_th['biasyqlowwarning'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][4] - trans_dom_th['biasyphighalarm'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][1] - trans_dom_th['biasyplowalarm'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][2] - trans_dom_th['biasyphighwarning'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][3] - trans_dom_th['biasyplowwarning'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][4] - trans_dom_th['cdshorthighalarm'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][1] - trans_dom_th['cdshortlowalarm'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][2] - trans_dom_th['cdshorthighwarning'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][3] - trans_dom_th['cdshortlowwarning'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][4] - try: - trans_dom_th['cdlonghighalarm'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][1] - trans_dom_th['cdlonglowalarm'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][2] - trans_dom_th['cdlonghighwarning'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][3] - trans_dom_th['cdlonglowwarning'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][4] - except KeyError: - pass - trans_dom_th['dgdhighalarm'] = self.vdm_dict['DGD [ps]'][1][1] - trans_dom_th['dgdlowalarm'] = self.vdm_dict['DGD [ps]'][1][2] - trans_dom_th['dgdhighwarning'] = self.vdm_dict['DGD [ps]'][1][3] - trans_dom_th['dgdlowwarning'] = self.vdm_dict['DGD [ps]'][1][4] - try: - trans_dom_th['sopmdhighalarm'] = self.vdm_dict['SOPMD [ps^2]'][1][1] - trans_dom_th['sopmdlowalarm'] = self.vdm_dict['SOPMD [ps^2]'][1][2] - trans_dom_th['sopmdhighwarning'] = self.vdm_dict['SOPMD [ps^2]'][1][3] - trans_dom_th['sopmdlowwarning'] = self.vdm_dict['SOPMD [ps^2]'][1][4] - except KeyError: - pass - trans_dom_th['pdlhighalarm'] = self.vdm_dict['PDL [dB]'][1][1] - trans_dom_th['pdllowalarm'] = self.vdm_dict['PDL [dB]'][1][2] - trans_dom_th['pdlhighwarning'] = self.vdm_dict['PDL [dB]'][1][3] - trans_dom_th['pdllowwarning'] = self.vdm_dict['PDL [dB]'][1][4] - trans_dom_th['osnrhighalarm'] = self.vdm_dict['OSNR [dB]'][1][1] - trans_dom_th['osnrlowalarm'] = self.vdm_dict['OSNR [dB]'][1][2] - trans_dom_th['osnrhighwarning'] = self.vdm_dict['OSNR [dB]'][1][3] - trans_dom_th['osnrlowwarning'] = self.vdm_dict['OSNR [dB]'][1][4] - trans_dom_th['esnrhighalarm'] = self.vdm_dict['eSNR [dB]'][1][1] - trans_dom_th['esnrlowalarm'] = self.vdm_dict['eSNR [dB]'][1][2] - trans_dom_th['esnrhighwarning'] = self.vdm_dict['eSNR [dB]'][1][3] - trans_dom_th['esnrlowwarning'] = self.vdm_dict['eSNR [dB]'][1][4] - trans_dom_th['cfohighalarm'] = self.vdm_dict['CFO [MHz]'][1][1] - trans_dom_th['cfolowalarm'] = self.vdm_dict['CFO [MHz]'][1][2] - trans_dom_th['cfohighwarning'] = self.vdm_dict['CFO [MHz]'][1][3] - trans_dom_th['cfolowwarning'] = self.vdm_dict['CFO [MHz]'][1][4] - trans_dom_th['txcurrpowerhighalarm'] = self.vdm_dict['Tx Power [dBm]'][1][1] - trans_dom_th['txcurrpowerlowalarm'] = self.vdm_dict['Tx Power [dBm]'][1][2] - trans_dom_th['txcurrpowerhighwarning'] = self.vdm_dict['Tx Power [dBm]'][1][3] - trans_dom_th['txcurrpowerlowwarning'] = self.vdm_dict['Tx Power [dBm]'][1][4] - trans_dom_th['rxtotpowerhighalarm'] = self.vdm_dict['Rx Total Power [dBm]'][1][1] - trans_dom_th['rxtotpowerlowalarm'] = self.vdm_dict['Rx Total Power [dBm]'][1][2] - trans_dom_th['rxtotpowerhighwarning'] = self.vdm_dict['Rx Total Power [dBm]'][1][3] - trans_dom_th['rxtotpowerlowwarning'] = self.vdm_dict['Rx Total Power [dBm]'][1][4] - try: - trans_dom_th['rxsigpowerhighalarm'] = self.vdm_dict['Rx Signal Power [dBm]'][1][1] - trans_dom_th['rxsigpowerlowalarm'] = self.vdm_dict['Rx Signal Power [dBm]'][1][2] - trans_dom_th['rxsigpowerhighwarning'] = self.vdm_dict['Rx Signal Power [dBm]'][1][3] - trans_dom_th['rxsigpowerlowwarning'] = self.vdm_dict['Rx Signal Power [dBm]'][1][4] - except KeyError: - pass - return trans_dom_th - - def get_transceiver_status(self): - """ - Retrieves transceiver status of this SFP - - Returns: - A dict which contains following keys/values : - ================================================================================ - key = TRANSCEIVER_STATUS|ifname ; Error information for module on port - ; field = value - module_state = 1*255VCHAR ; current module state (ModuleLowPwr, ModulePwrUp, ModuleReady, ModulePwrDn, Fault) - module_fault_cause = 1*255VCHAR ; reason of entering the module fault state - datapath_firmware_fault = BOOLEAN ; datapath (DSP) firmware fault - module_firmware_fault = BOOLEAN ; module firmware fault - module_state_changed = BOOLEAN ; module state changed - datapath_hostlane1 = 1*255VCHAR ; data path state indicator on host lane 1 - datapath_hostlane2 = 1*255VCHAR ; data path state indicator on host lane 2 - datapath_hostlane3 = 1*255VCHAR ; data path state indicator on host lane 3 - datapath_hostlane4 = 1*255VCHAR ; data path state indicator on host lane 4 - datapath_hostlane5 = 1*255VCHAR ; data path state indicator on host lane 5 - datapath_hostlane6 = 1*255VCHAR ; data path state indicator on host lane 6 - datapath_hostlane7 = 1*255VCHAR ; data path state indicator on host lane 7 - datapath_hostlane8 = 1*255VCHAR ; data path state indicator on host lane 8 - txoutput_status = BOOLEAN ; tx output status on media lane - rxoutput_status_hostlane1 = BOOLEAN ; rx output status on host lane 1 - rxoutput_status_hostlane2 = BOOLEAN ; rx output status on host lane 2 - rxoutput_status_hostlane3 = BOOLEAN ; rx output status on host lane 3 - rxoutput_status_hostlane4 = BOOLEAN ; rx output status on host lane 4 - rxoutput_status_hostlane5 = BOOLEAN ; rx output status on host lane 5 - rxoutput_status_hostlane6 = BOOLEAN ; rx output status on host lane 6 - rxoutput_status_hostlane7 = BOOLEAN ; rx output status on host lane 7 - rxoutput_status_hostlane8 = BOOLEAN ; rx output status on host lane 8 - txfault = BOOLEAN ; tx fault flag on media lane - txlos_hostlane1 = BOOLEAN ; tx loss of signal flag on host lane 1 - txlos_hostlane2 = BOOLEAN ; tx loss of signal flag on host lane 2 - txlos_hostlane3 = BOOLEAN ; tx loss of signal flag on host lane 3 - txlos_hostlane4 = BOOLEAN ; tx loss of signal flag on host lane 4 - txlos_hostlane5 = BOOLEAN ; tx loss of signal flag on host lane 5 - txlos_hostlane6 = BOOLEAN ; tx loss of signal flag on host lane 6 - txlos_hostlane7 = BOOLEAN ; tx loss of signal flag on host lane 7 - txlos_hostlane8 = BOOLEAN ; tx loss of signal flag on host lane 8 - txcdrlol_hostlane1 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 1 - txcdrlol_hostlane2 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 2 - txcdrlol_hostlane3 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 3 - txcdrlol_hostlane4 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 4 - txcdrlol_hostlane5 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 5 - txcdrlol_hostlane6 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 6 - txcdrlol_hostlane7 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 7 - txcdrlol_hostlane8 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 8 - rxlos = BOOLEAN ; rx loss of signal flag on media lane - rxcdrlol = BOOLEAN ; rx clock and data recovery loss of lock on media lane - config_state_hostlane1 = 1*255VCHAR ; configuration status for the data path of host line 1 - config_state_hostlane2 = 1*255VCHAR ; configuration status for the data path of host line 2 - config_state_hostlane3 = 1*255VCHAR ; configuration status for the data path of host line 3 - config_state_hostlane4 = 1*255VCHAR ; configuration status for the data path of host line 4 - config_state_hostlane5 = 1*255VCHAR ; configuration status for the data path of host line 5 - config_state_hostlane6 = 1*255VCHAR ; configuration status for the data path of host line 6 - config_state_hostlane7 = 1*255VCHAR ; configuration status for the data path of host line 7 - config_state_hostlane8 = 1*255VCHAR ; configuration status for the data path of host line 8 - dpinit_pending_hostlane1 = BOOLEAN ; data path configuration updated on host lane 1 - dpinit_pending_hostlane2 = BOOLEAN ; data path configuration updated on host lane 2 - dpinit_pending_hostlane3 = BOOLEAN ; data path configuration updated on host lane 3 - dpinit_pending_hostlane4 = BOOLEAN ; data path configuration updated on host lane 4 - dpinit_pending_hostlane5 = BOOLEAN ; data path configuration updated on host lane 5 - dpinit_pending_hostlane6 = BOOLEAN ; data path configuration updated on host lane 6 - dpinit_pending_hostlane7 = BOOLEAN ; data path configuration updated on host lane 7 - dpinit_pending_hostlane8 = BOOLEAN ; data path configuration updated on host lane 8 - tuning_in_progress = BOOLEAN ; tuning in progress status - wavelength_unlock_status = BOOLEAN ; laser unlocked status - target_output_power_oor = BOOLEAN ; target output power out of range flag - fine_tuning_oor = BOOLEAN ; fine tuning out of range flag - tuning_not_accepted = BOOLEAN ; tuning not accepted flag - invalid_channel_num = BOOLEAN ; invalid channel number flag - tuning_complete = BOOLEAN ; tuning complete flag - temphighalarm_flag = BOOLEAN ; temperature high alarm flag - temphighwarning_flag = BOOLEAN ; temperature high warning flag - templowalarm_flag = BOOLEAN ; temperature low alarm flag - templowwarning_flag = BOOLEAN ; temperature low warning flag - vcchighalarm_flag = BOOLEAN ; vcc high alarm flag - vcchighwarning_flag = BOOLEAN ; vcc high warning flag - vcclowalarm_flag = BOOLEAN ; vcc low alarm flag - vcclowwarning_flag = BOOLEAN ; vcc low warning flag - txpowerhighalarm_flag = BOOLEAN ; tx power high alarm flag - txpowerlowalarm_flag = BOOLEAN ; tx power low alarm flag - txpowerhighwarning_flag = BOOLEAN ; tx power high warning flag - txpowerlowwarning_flag = BOOLEAN ; tx power low alarm flag - rxpowerhighalarm_flag = BOOLEAN ; rx power high alarm flag - rxpowerlowalarm_flag = BOOLEAN ; rx power low alarm flag - rxpowerhighwarning_flag = BOOLEAN ; rx power high warning flag - rxpowerlowwarning_flag = BOOLEAN ; rx power low warning flag - txbiashighalarm_flag = BOOLEAN ; tx bias high alarm flag - txbiaslowalarm_flag = BOOLEAN ; tx bias low alarm flag - txbiashighwarning_flag = BOOLEAN ; tx bias high warning flag - txbiaslowwarning_flag = BOOLEAN ; tx bias low warning flag - lasertemphighalarm_flag = BOOLEAN ; laser temperature high alarm flag - lasertemplowalarm_flag = BOOLEAN ; laser temperature low alarm flag - lasertemphighwarning_flag = BOOLEAN ; laser temperature high warning flag - lasertemplowwarning_flag = BOOLEAN ; laser temperature low warning flag - prefecberhighalarm_flag = BOOLEAN ; prefec ber high alarm flag - prefecberlowalarm_flag = BOOLEAN ; prefec ber low alarm flag - prefecberhighwarning_flag = BOOLEAN ; prefec ber high warning flag - prefecberlowwarning_flag = BOOLEAN ; prefec ber low warning flag - postfecberhighalarm_flag = BOOLEAN ; postfec ber high alarm flag - postfecberlowalarm_flag = BOOLEAN ; postfec ber low alarm flag - postfecberhighwarning_flag = BOOLEAN ; postfec ber high warning flag - postfecberlowwarning_flag = BOOLEAN ; postfec ber low warning flag - biasxihighalarm_flag = BOOLEAN ; bias xi high alarm flag - biasxilowalarm_flag = BOOLEAN ; bias xi low alarm flag - biasxihighwarning_flag = BOOLEAN ; bias xi high warning flag - biasxilowwarning_flag = BOOLEAN ; bias xi low warning flag - biasxqhighalarm_flag = BOOLEAN ; bias xq high alarm flag - biasxqlowalarm_flag = BOOLEAN ; bias xq low alarm flag - biasxqhighwarning_flag = BOOLEAN ; bias xq high warning flag - biasxqlowwarning_flag = BOOLEAN ; bias xq low warning flag - biasxphighalarm_flag = BOOLEAN ; bias xp high alarm flag - biasxplowalarm_flag = BOOLEAN ; bias xp low alarm flag - biasxphighwarning_flag = BOOLEAN ; bias xp high warning flag - biasxplowwarning_flag = BOOLEAN ; bias xp low warning flag - biasyihighalarm_flag = BOOLEAN ; bias yi high alarm flag - biasyilowalarm_flag = BOOLEAN ; bias yi low alarm flag - biasyihighwarning_flag = BOOLEAN ; bias yi high warning flag - biasyilowwarning_flag = BOOLEAN ; bias yi low warning flag - biasyqhighalarm_flag = BOOLEAN ; bias yq high alarm flag - biasyqlowalarm_flag = BOOLEAN ; bias yq low alarm flag - biasyqhighwarning_flag = BOOLEAN ; bias yq high warning flag - biasyqlowwarning_flag = BOOLEAN ; bias yq low warning flag - biasyphighalarm_flag = BOOLEAN ; bias yp high alarm flag - biasyplowalarm_flag = BOOLEAN ; bias yp low alarm flag - biasyphighwarning_flag = BOOLEAN ; bias yp high warning flag - biasyplowwarning_flag = BOOLEAN ; bias yp low warning flag - cdshorthighalarm_flag = BOOLEAN ; cd short high alarm flag - cdshortlowalarm_flag = BOOLEAN ; cd short low alarm flag - cdshorthighwarning_flag = BOOLEAN ; cd short high warning flag - cdshortlowwarning_flag = BOOLEAN ; cd short low warning flag - cdlonghighalarm_flag = BOOLEAN ; cd long high alarm flag - cdlonglowalarm_flag = BOOLEAN ; cd long low alarm flag - cdlonghighwarning_flag = BOOLEAN ; cd long high warning flag - cdlonglowwarning_flag = BOOLEAN ; cd long low warning flag - dgdhighalarm_flag = BOOLEAN ; dgd high alarm flag - dgdlowalarm_flag = BOOLEAN ; dgd low alarm flag - dgdhighwarning_flag = BOOLEAN ; dgd high warning flag - dgdlowwarning_flag = BOOLEAN ; dgd low warning flag - sopmdhighalarm_flag = BOOLEAN ; sopmd high alarm flag - sopmdlowalarm_flag = BOOLEAN ; sopmd low alarm flag - sopmdhighwarning_flag = BOOLEAN ; sopmd high warning flag - sopmdlowwarning_flag = BOOLEAN ; sopmd low warning flag - pdlhighalarm_flag = BOOLEAN ; pdl high alarm flag - pdllowalarm_flag = BOOLEAN ; pdl low alarm flag - pdlhighwarning_flag = BOOLEAN ; pdl high warning flag - pdllowwarning_flag = BOOLEAN ; pdl low warning flag - osnrhighalarm_flag = BOOLEAN ; osnr high alarm flag - osnrlowalarm_flag = BOOLEAN ; osnr low alarm flag - osnrhighwarning_flag = BOOLEAN ; osnr high warning flag - osnrlowwarning_flag = BOOLEAN ; osnr low warning flag - esnrhighalarm_flag = BOOLEAN ; esnr high alarm flag - esnrlowalarm_flag = BOOLEAN ; esnr low alarm flag - esnrhighwarning_flag = BOOLEAN ; esnr high warning flag - esnrlowwarning_flag = BOOLEAN ; esnr low warning flag - cfohighalarm_flag = BOOLEAN ; cfo high alarm flag - cfolowalarm_flag = BOOLEAN ; cfo low alarm flag - cfohighwarning_flag = BOOLEAN ; cfo high warning flag - cfolowwarning_flag = BOOLEAN ; cfo low warning flag - txcurrpowerhighalarm_flag = BOOLEAN ; txcurrpower high alarm flag - txcurrpowerlowalarm_flag = BOOLEAN ; txcurrpower low alarm flag - txcurrpowerhighwarning_flag = BOOLEAN ; txcurrpower high warning flag - txcurrpowerlowwarning_flag = BOOLEAN ; txcurrpower low warning flag - rxtotpowerhighalarm_flag = BOOLEAN ; rxtotpower high alarm flag - rxtotpowerlowalarm_flag = BOOLEAN ; rxtotpower low alarm flag - rxtotpowerhighwarning_flag = BOOLEAN ; rxtotpower high warning flag - rxtotpowerlowwarning_flag = BOOLEAN ; rxtotpower low warning flag - rxsigpowerhighalarm_flag = BOOLEAN ; rxsigpower high alarm flag - rxsigpowerlowalarm_flag = BOOLEAN ; rxsigpower low alarm flag - rxsigpowerhighwarning_flag = BOOLEAN ; rxsigpower high warning flag - rxsigpowerlowwarning_flag = BOOLEAN ; rxsigpower low warning flag - ================================================================================ - """ - trans_status = super(CCmisApi,self).get_transceiver_status() - trans_status['tuning_in_progress'] = self.get_tuning_in_progress() - trans_status['wavelength_unlock_status'] = self.get_wavelength_unlocked() - laser_tuning_summary = self.get_laser_tuning_summary() - trans_status['target_output_power_oor'] = 'TargetOutputPowerOOR' in laser_tuning_summary - trans_status['fine_tuning_oor'] = 'FineTuningOutOfRange' in laser_tuning_summary - trans_status['tuning_not_accepted'] = 'TuningNotAccepted' in laser_tuning_summary - trans_status['invalid_channel_num'] = 'InvalidChannel' in laser_tuning_summary - trans_status['tuning_complete'] = 'TuningComplete' in laser_tuning_summary - trans_status['biasxihighalarm_flag'] = self.vdm_dict['Modulator Bias X/I [%]'][1][5] - trans_status['biasxilowalarm_flag'] = self.vdm_dict['Modulator Bias X/I [%]'][1][6] - trans_status['biasxihighwarning_flag'] = self.vdm_dict['Modulator Bias X/I [%]'][1][7] - trans_status['biasxilowwarning_flag'] = self.vdm_dict['Modulator Bias X/I [%]'][1][8] - trans_status['biasxqhighalarm_flag'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][5] - trans_status['biasxqlowalarm_flag'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][6] - trans_status['biasxqhighwarning_flag'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][7] - trans_status['biasxqlowwarning_flag'] = self.vdm_dict['Modulator Bias X/Q [%]'][1][8] - trans_status['biasxphighalarm_flag'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][5] - trans_status['biasxplowalarm_flag'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][6] - trans_status['biasxphighwarning_flag'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][7] - trans_status['biasxplowwarning_flag'] = self.vdm_dict['Modulator Bias X_Phase [%]'][1][8] - trans_status['biasyihighalarm_flag'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][5] - trans_status['biasyilowalarm_flag'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][6] - trans_status['biasyihighwarning_flag'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][7] - trans_status['biasyilowwarning_flag'] = self.vdm_dict['Modulator Bias Y/I [%]'][1][8] - trans_status['biasyqhighalarm_flag'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][5] - trans_status['biasyqlowalarm_flag'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][6] - trans_status['biasyqhighwarning_flag'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][7] - trans_status['biasyqlowwarning_flag'] = self.vdm_dict['Modulator Bias Y/Q [%]'][1][8] - trans_status['biasyphighalarm_flag'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][5] - trans_status['biasyplowalarm_flag'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][6] - trans_status['biasyphighwarning_flag'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][7] - trans_status['biasyplowwarning_flag'] = self.vdm_dict['Modulator Bias Y_Phase [%]'][1][8] - trans_status['cdshorthighalarm_flag'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][5] - trans_status['cdshortlowalarm_flag'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][6] - trans_status['cdshorthighwarning_flag'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][7] - trans_status['cdshortlowwarning_flag'] = self.vdm_dict['CD high granularity, short link [ps/nm]'][1][8] - try: - trans_status['cdlonghighalarm_flag'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][5] - trans_status['cdlonglowalarm_flag'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][6] - trans_status['cdlonghighwarning_flag'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][7] - trans_status['cdlonglowwarning_flag'] = self.vdm_dict['CD low granularity, long link [ps/nm]'][1][8] - except KeyError: - pass - trans_status['dgdhighalarm_flag'] = self.vdm_dict['DGD [ps]'][1][5] - trans_status['dgdlowalarm_flag'] = self.vdm_dict['DGD [ps]'][1][6] - trans_status['dgdhighwarning_flag'] = self.vdm_dict['DGD [ps]'][1][7] - trans_status['dgdlowwarning_flag'] = self.vdm_dict['DGD [ps]'][1][8] - try: - trans_status['sopmdhighalarm_flag'] = self.vdm_dict['SOPMD [ps^2]'][1][5] - trans_status['sopmdlowalarm_flag'] = self.vdm_dict['SOPMD [ps^2]'][1][6] - trans_status['sopmdhighwarning_flag'] = self.vdm_dict['SOPMD [ps^2]'][1][7] - trans_status['sopmdlowwarning_flag'] = self.vdm_dict['SOPMD [ps^2]'][1][8] - except KeyError: - pass - trans_status['pdlhighalarm_flag'] = self.vdm_dict['PDL [dB]'][1][5] - trans_status['pdllowalarm_flag'] = self.vdm_dict['PDL [dB]'][1][6] - trans_status['pdlhighwarning_flag'] = self.vdm_dict['PDL [dB]'][1][7] - trans_status['pdllowwarning_flag'] = self.vdm_dict['PDL [dB]'][1][8] - trans_status['osnrhighalarm_flag'] = self.vdm_dict['OSNR [dB]'][1][5] - trans_status['osnrlowalarm_flag'] = self.vdm_dict['OSNR [dB]'][1][6] - trans_status['osnrhighwarning_flag'] = self.vdm_dict['OSNR [dB]'][1][7] - trans_status['osnrlowwarning_flag'] = self.vdm_dict['OSNR [dB]'][1][8] - trans_status['esnrhighalarm_flag'] = self.vdm_dict['eSNR [dB]'][1][5] - trans_status['esnrlowalarm_flag'] = self.vdm_dict['eSNR [dB]'][1][6] - trans_status['esnrhighwarning_flag'] = self.vdm_dict['eSNR [dB]'][1][7] - trans_status['esnrlowwarning_flag'] = self.vdm_dict['eSNR [dB]'][1][8] - trans_status['cfohighalarm_flag'] = self.vdm_dict['CFO [MHz]'][1][5] - trans_status['cfolowalarm_flag'] = self.vdm_dict['CFO [MHz]'][1][6] - trans_status['cfohighwarning_flag'] = self.vdm_dict['CFO [MHz]'][1][7] - trans_status['cfolowwarning_flag'] = self.vdm_dict['CFO [MHz]'][1][8] - trans_status['txcurrpowerhighalarm_flag'] = self.vdm_dict['Tx Power [dBm]'][1][5] - trans_status['txcurrpowerlowalarm_flag'] = self.vdm_dict['Tx Power [dBm]'][1][6] - trans_status['txcurrpowerhighwarning_flag'] = self.vdm_dict['Tx Power [dBm]'][1][7] - trans_status['txcurrpowerlowwarning_flag'] = self.vdm_dict['Tx Power [dBm]'][1][8] - trans_status['rxtotpowerhighalarm_flag'] = self.vdm_dict['Rx Total Power [dBm]'][1][5] - trans_status['rxtotpowerlowalarm_flag'] = self.vdm_dict['Rx Total Power [dBm]'][1][6] - trans_status['rxtotpowerhighwarning_flag'] = self.vdm_dict['Rx Total Power [dBm]'][1][7] - trans_status['rxtotpowerlowwarning_flag'] = self.vdm_dict['Rx Total Power [dBm]'][1][8] - try: - trans_status['rxsigpowerhighalarm_flag'] = self.vdm_dict['Rx Signal Power [dBm]'][1][5] - trans_status['rxsigpowerlowalarm_flag'] = self.vdm_dict['Rx Signal Power [dBm]'][1][6] - trans_status['rxsigpowerhighwarning_flag'] = self.vdm_dict['Rx Signal Power [dBm]'][1][7] - trans_status['rxsigpowerlowwarning_flag'] = self.vdm_dict['Rx Signal Power [dBm]'][1][8] - except KeyError: - helper_logger.log_debug('Rx Signal Power [dBm] not present in VDM') - return trans_status - - def get_transceiver_pm(self): - """ - Retrieves PM for this xcvr - - Returns: - A dict containing the following keys/values : - ======================================================================== - key = TRANSCEIVER_PM|ifname ; information of PM on port - ; field = value - prefec_ber_avg = FLOAT ; prefec ber avg - prefec_ber_min = FLOAT ; prefec ber min - prefec_ber_max = FLOAT ; prefec ber max - uncorr_frames_avg = FLOAT ; uncorrected frames ratio avg - uncorr_frames_min = FLOAT ; uncorrected frames ratio min - uncorr_frames_max = FLOAT ; uncorrected frames ratio max - cd_avg = FLOAT ; chromatic dispersion avg - cd_min = FLOAT ; chromatic dispersion min - cd_max = FLOAT ; chromatic dispersion max - dgd_avg = FLOAT ; differential group delay avg - dgd_min = FLOAT ; differential group delay min - dgd_max = FLOAT ; differential group delay max - sopmd_avg = FLOAT ; second order polarization mode dispersion avg - sopmd_min = FLOAT ; second order polarization mode dispersion min - sopmd_max = FLOAT ; second order polarization mode dispersion max - pdl_avg = FLOAT ; polarization dependent loss avg - pdl_min = FLOAT ; polarization dependent loss min - pdl_max = FLOAT ; polarization dependent loss max - osnr_avg = FLOAT ; optical signal to noise ratio avg - osnr_min = FLOAT ; optical signal to noise ratio min - osnr_max = FLOAT ; optical signal to noise ratio max - esnr_avg = FLOAT ; electrical signal to noise ratio avg - esnr_min = FLOAT ; electrical signal to noise ratio min - esnr_max = FLOAT ; electrical signal to noise ratio max - cfo_avg = FLOAT ; carrier frequency offset avg - cfo_min = FLOAT ; carrier frequency offset min - cfo_max = FLOAT ; carrier frequency offset max - soproc_avg = FLOAT ; state of polarization rate of change avg - soproc_min = FLOAT ; state of polarization rate of change min - soproc_max = FLOAT ; state of polarization rate of change max - tx_power_avg = FLOAT ; tx output power avg - tx_power_min = FLOAT ; tx output power min - tx_power_max = FLOAT ; tx output power max - rx_tot_power_avg = FLOAT ; rx total power avg - rx_tot_power_min = FLOAT ; rx total power min - rx_tot_power_max = FLOAT ; rx total power max - rx_sig_power_avg = FLOAT ; rx signal power avg - rx_sig_power_min = FLOAT ; rx signal power min - rx_sig_power_max = FLOAT ; rx signal power max - ======================================================================== - """ - trans_pm = dict() - PM_dict = self.get_pm_all() - trans_pm['prefec_ber_avg'] = PM_dict['preFEC_BER_avg'] - trans_pm['prefec_ber_min'] = PM_dict['preFEC_BER_min'] - trans_pm['prefec_ber_max'] = PM_dict['preFEC_BER_max'] - trans_pm['uncorr_frames_avg'] = PM_dict['preFEC_uncorr_frame_ratio_avg'] - trans_pm['uncorr_frames_min'] = PM_dict['preFEC_uncorr_frame_ratio_min'] - trans_pm['uncorr_frames_max'] = PM_dict['preFEC_uncorr_frame_ratio_max'] - trans_pm['cd_avg'] = PM_dict['rx_cd_avg'] - trans_pm['cd_min'] = PM_dict['rx_cd_min'] - trans_pm['cd_max'] = PM_dict['rx_cd_max'] - trans_pm['dgd_avg'] = PM_dict['rx_dgd_avg'] - trans_pm['dgd_min'] = PM_dict['rx_dgd_min'] - trans_pm['dgd_max'] = PM_dict['rx_dgd_max'] - trans_pm['sopmd_avg'] = PM_dict['rx_sopmd_avg'] - trans_pm['sopmd_min'] = PM_dict['rx_sopmd_min'] - trans_pm['sopmd_max'] = PM_dict['rx_sopmd_max'] - trans_pm['pdl_avg'] = PM_dict['rx_pdl_avg'] - trans_pm['pdl_min'] = PM_dict['rx_pdl_min'] - trans_pm['pdl_max'] = PM_dict['rx_pdl_max'] - trans_pm['osnr_avg'] = PM_dict['rx_osnr_avg'] - trans_pm['osnr_min'] = PM_dict['rx_osnr_min'] - trans_pm['osnr_max'] = PM_dict['rx_osnr_max'] - trans_pm['esnr_avg'] = PM_dict['rx_esnr_avg'] - trans_pm['esnr_min'] = PM_dict['rx_esnr_min'] - trans_pm['esnr_max'] = PM_dict['rx_esnr_max'] - trans_pm['cfo_avg'] = PM_dict['rx_cfo_avg'] - trans_pm['cfo_min'] = PM_dict['rx_cfo_min'] - trans_pm['cfo_max'] = PM_dict['rx_cfo_max'] - trans_pm['evm_avg'] = PM_dict['rx_evm_avg'] - trans_pm['evm_min'] = PM_dict['rx_evm_min'] - trans_pm['evm_max'] = PM_dict['rx_evm_max'] - trans_pm['soproc_avg'] = PM_dict['rx_soproc_avg'] - trans_pm['soproc_min'] = PM_dict['rx_soproc_min'] - trans_pm['soproc_max'] = PM_dict['rx_soproc_max'] - trans_pm['tx_power_avg'] = PM_dict['tx_power_avg'] - trans_pm['tx_power_min'] = PM_dict['tx_power_min'] - trans_pm['tx_power_max'] = PM_dict['tx_power_max'] - trans_pm['rx_tot_power_avg'] = PM_dict['rx_power_avg'] - trans_pm['rx_tot_power_min'] = PM_dict['rx_power_min'] - trans_pm['rx_tot_power_max'] = PM_dict['rx_power_max'] - trans_pm['rx_sig_power_avg'] = PM_dict['rx_sigpwr_avg'] - trans_pm['rx_sig_power_min'] = PM_dict['rx_sigpwr_min'] - trans_pm['rx_sig_power_max'] = PM_dict['rx_sigpwr_max'] - return trans_pm diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmis.py b/sonic_platform_base/sonic_xcvr/api/public/cmis.py deleted file mode 100644 index 118544056..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/cmis.py +++ /dev/null @@ -1,2010 +0,0 @@ - -""" - cmis.py - - Implementation of XcvrApi that corresponds to the CMIS specification. -""" - -from ...fields import consts -from ..xcvr_api import XcvrApi - -import logging -from ...codes.public.cmis import CmisCodes -from ...codes.public.sff8024 import Sff8024 -from ...fields import consts -from ..xcvr_api import XcvrApi -from .cmisCDB import CmisCdbApi -from .cmisVDM import CmisVdmApi -import time - -logger = logging.getLogger(__name__) -logger.addHandler(logging.NullHandler()) - -class CmisApi(XcvrApi): - NUM_CHANNELS = 8 - LowPwrRequestSW = 4 - LowPwrAllowRequestHW = 6 - - def __init__(self, xcvr_eeprom): - super(CmisApi, self).__init__(xcvr_eeprom) - self.vdm = CmisVdmApi(xcvr_eeprom) if not self.is_flat_memory() else None - self.cdb = CmisCdbApi(xcvr_eeprom) if not self.is_flat_memory() else None - - def get_model(self): - ''' - This function returns the part number of the module - ''' - return self.xcvr_eeprom.read(consts.VENDOR_PART_NO_FIELD) - - def get_vendor_rev(self): - ''' - This function returns the revision level for part number provided by vendor - ''' - return self.xcvr_eeprom.read(consts.VENDOR_REV_FIELD) - - def get_serial(self): - ''' - This function returns the serial number of the module - ''' - return self.xcvr_eeprom.read(consts.VENDOR_SERIAL_NO_FIELD) - - def get_module_type(self): - ''' - This function returns the SFF8024Identifier (module type / form-factor). Table 4-1 in SFF-8024 Rev4.6 - ''' - return self.xcvr_eeprom.read(consts.ID_FIELD) - - def get_module_type_abbreviation(self): - ''' - This function returns the SFF8024Identifier (module type / form-factor). Table 4-1 in SFF-8024 Rev4.6 - ''' - return self.xcvr_eeprom.read(consts.ID_ABBRV_FIELD) - - def get_connector_type(self): - ''' - This function returns module connector. Table 4-3 in SFF-8024 Rev4.6 - ''' - return self.xcvr_eeprom.read(consts.CONNECTOR_FIELD) - - def get_module_hardware_revision(self): - ''' - This function returns the module hardware revision - ''' - if self.is_flat_memory(): - return '0.0' - hw_major_rev = self.xcvr_eeprom.read(consts.HW_MAJOR_REV) - hw_minor_rev = self.xcvr_eeprom.read(consts.HW_MAJOR_REV) - hw_rev = [str(num) for num in [hw_major_rev, hw_minor_rev]] - return '.'.join(hw_rev) - - def get_cmis_rev(self): - ''' - This function returns the CMIS version the module complies to - ''' - cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) - cmis_minor = self.xcvr_eeprom.read(consts.CMIS_MINOR_REVISION) - cmis_rev = [str(num) for num in [cmis_major, cmis_minor]] - return '.'.join(cmis_rev) - - # Transceiver status - def get_module_state(self): - ''' - This function returns the module state - ''' - return self.xcvr_eeprom.read(consts.MODULE_STATE) - - def get_module_fault_cause(self): - ''' - This function returns the module fault cause - ''' - return self.xcvr_eeprom.read(consts.MODULE_FAULT_CAUSE) - - def get_module_active_firmware(self): - ''' - This function returns the active firmware version - ''' - active_fw_major = self.xcvr_eeprom.read(consts.ACTIVE_FW_MAJOR_REV) - active_fw_minor = self.xcvr_eeprom.read(consts.ACTIVE_FW_MINOR_REV) - active_fw = [str(num) for num in [active_fw_major, active_fw_minor]] - return '.'.join(active_fw) - - def get_module_inactive_firmware(self): - ''' - This function returns the inactive firmware version - ''' - if self.is_flat_memory(): - return 'N/A' - inactive_fw_major = self.xcvr_eeprom.read(consts.INACTIVE_FW_MAJOR_REV) - inactive_fw_minor = self.xcvr_eeprom.read(consts.INACTIVE_FW_MINOR_REV) - inactive_fw = [str(num) for num in [inactive_fw_major, inactive_fw_minor]] - return '.'.join(inactive_fw) - - def get_transceiver_info(self): - admin_info = self.xcvr_eeprom.read(consts.ADMIN_INFO_FIELD) - if admin_info is None: - return None - - ext_id = admin_info[consts.EXT_ID_FIELD] - power_class = ext_id[consts.POWER_CLASS_FIELD] - max_power = ext_id[consts.MAX_POWER_FIELD] - - xcvr_info = { - "type": admin_info[consts.ID_FIELD], - "type_abbrv_name": admin_info[consts.ID_ABBRV_FIELD], - "hardware_rev": self.get_module_hardware_revision(), - "serial": admin_info[consts.VENDOR_SERIAL_NO_FIELD], - "manufacturer": admin_info[consts.VENDOR_NAME_FIELD], - "model": admin_info[consts.VENDOR_PART_NO_FIELD], - "connector": admin_info[consts.CONNECTOR_FIELD], - "encoding": "N/A", # Not supported - "ext_identifier": "%s (%sW Max)" % (power_class, max_power), - "ext_rateselect_compliance": "N/A", # Not supported - "cable_type": "Length Cable Assembly(m)", - "cable_length": float(admin_info[consts.LENGTH_ASSEMBLY_FIELD]), - "nominal_bit_rate": 0, # Not supported - "specification_compliance": admin_info[consts.MEDIA_TYPE_FIELD], - "vendor_date": admin_info[consts.VENDOR_DATE_FIELD], - "vendor_oui": admin_info[consts.VENDOR_OUI_FIELD] - } - appl_advt = self.get_application_advertisement() - xcvr_info['application_advertisement'] = str(appl_advt) if len(appl_advt) > 0 else 'N/A' - xcvr_info['host_electrical_interface'] = self.get_host_electrical_interface() - xcvr_info['media_interface_code'] = self.get_module_media_interface() - xcvr_info['host_lane_count'] = self.get_host_lane_count() - xcvr_info['media_lane_count'] = self.get_media_lane_count() - xcvr_info['host_lane_assignment_option'] = self.get_host_lane_assignment_option() - xcvr_info['media_lane_assignment_option'] = self.get_media_lane_assignment_option() - apsel_dict = self.get_active_apsel_hostlane() - for lane in range(1, self.NUM_CHANNELS+1): - xcvr_info["%s%d" % ("active_apsel_hostlane", lane)] = \ - apsel_dict["%s%d" % (consts.ACTIVE_APSEL_HOSTLANE, lane)] - xcvr_info['media_interface_technology'] = self.get_media_interface_technology() - xcvr_info['vendor_rev'] = self.get_vendor_rev() - xcvr_info['cmis_rev'] = self.get_cmis_rev() - xcvr_info['active_firmware'] = self.get_module_active_firmware() - xcvr_info['inactive_firmware'] = self.get_module_inactive_firmware() - xcvr_info['specification_compliance'] = self.get_module_media_type() - - # In normal case will get a valid value for each of the fields. If get a 'None' value - # means there was a failure while reading the EEPROM, either because the EEPROM was - # not ready yet or experincing some other issues. It shouldn't return a dict with a - # wrong field value, instead should return a 'None' to indicate to XCVRD that retry is - # needed. - if None in xcvr_info.values(): - return None - else: - return xcvr_info - - def get_transceiver_bulk_status(self): - rx_los = self.get_rx_los() - tx_fault = self.get_tx_fault() - tx_disable = self.get_tx_disable() - tx_disabled_channel = self.get_tx_disable_channel() - temp = self.get_module_temperature() - voltage = self.get_voltage() - tx_bias = self.get_tx_bias() - rx_power = self.get_rx_power() - tx_power = self.get_tx_power() - read_failed = rx_los is None or \ - tx_fault is None or \ - tx_disable is None or \ - tx_disabled_channel is None or \ - temp is None or \ - voltage is None or \ - tx_bias is None or \ - rx_power is None or \ - tx_power is None - if read_failed: - return None - - bulk_status = { - "rx_los": all(rx_los) if self.get_rx_los_support() else 'N/A', - "tx_fault": all(tx_fault) if self.get_tx_fault_support() else 'N/A', - "tx_disabled_channel": tx_disabled_channel, - "temperature": temp, - "voltage": voltage - } - - for i in range(1, self.NUM_CHANNELS + 1): - bulk_status["tx%ddisable" % i] = tx_disable[i-1] if self.get_tx_disable_support() else 'N/A' - bulk_status["tx%dbias" % i] = tx_bias[i - 1] - bulk_status["rx%dpower" % i] = float("{:.3f}".format(self.mw_to_dbm(rx_power[i - 1]))) if self.get_rx_power_support() else 'N/A' - bulk_status["tx%dpower" % i] = float("{:.3f}".format(self.mw_to_dbm(tx_power[i - 1]))) if self.get_tx_power_support() else 'N/A' - - laser_temp_dict = self.get_laser_temperature() - self.vdm_dict = self.get_vdm() - try: - bulk_status['laser_temperature'] = laser_temp_dict['monitor value'] - bulk_status['prefec_ber'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][0] - bulk_status['postfec_ber_min'] = self.vdm_dict['Errored Frames Minimum Media Input'][1][0] - bulk_status['postfec_ber_max'] = self.vdm_dict['Errored Frames Maximum Media Input'][1][0] - bulk_status['postfec_ber_avg'] = self.vdm_dict['Errored Frames Average Media Input'][1][0] - bulk_status['postfec_curr_val'] = self.vdm_dict['Errored Frames Current Value Media Input'][1][0] - except (KeyError, TypeError): - pass - return bulk_status - - def get_transceiver_threshold_info(self): - threshold_info_keys = ['temphighalarm', 'temphighwarning', - 'templowalarm', 'templowwarning', - 'vcchighalarm', 'vcchighwarning', - 'vcclowalarm', 'vcclowwarning', - 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', - 'txpowerhighalarm', 'txpowerhighwarning', - 'txpowerlowalarm', 'txpowerlowwarning', - 'txbiashighalarm', 'txbiashighwarning', - 'txbiaslowalarm', 'txbiaslowwarning' - ] - threshold_info_dict = dict.fromkeys(threshold_info_keys, 'N/A') - - thresh_support = self.get_transceiver_thresholds_support() - if thresh_support is None: - return None - if not thresh_support: - return threshold_info_dict - thresh = self.xcvr_eeprom.read(consts.THRESHOLDS_FIELD) - if thresh is None: - return None - tx_bias_scale_raw = self.xcvr_eeprom.read(consts.TX_BIAS_SCALE) - tx_bias_scale = 2**tx_bias_scale_raw if tx_bias_scale_raw < 3 else 1 - threshold_info_dict = { - "temphighalarm": float("{:.3f}".format(thresh[consts.TEMP_HIGH_ALARM_FIELD])), - "templowalarm": float("{:.3f}".format(thresh[consts.TEMP_LOW_ALARM_FIELD])), - "temphighwarning": float("{:.3f}".format(thresh[consts.TEMP_HIGH_WARNING_FIELD])), - "templowwarning": float("{:.3f}".format(thresh[consts.TEMP_LOW_WARNING_FIELD])), - "vcchighalarm": float("{:.3f}".format(thresh[consts.VOLTAGE_HIGH_ALARM_FIELD])), - "vcclowalarm": float("{:.3f}".format(thresh[consts.VOLTAGE_LOW_ALARM_FIELD])), - "vcchighwarning": float("{:.3f}".format(thresh[consts.VOLTAGE_HIGH_WARNING_FIELD])), - "vcclowwarning": float("{:.3f}".format(thresh[consts.VOLTAGE_LOW_WARNING_FIELD])), - "rxpowerhighalarm": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.RX_POWER_HIGH_ALARM_FIELD]))), - "rxpowerlowalarm": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.RX_POWER_LOW_ALARM_FIELD]))), - "rxpowerhighwarning": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.RX_POWER_HIGH_WARNING_FIELD]))), - "rxpowerlowwarning": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.RX_POWER_LOW_WARNING_FIELD]))), - "txpowerhighalarm": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.TX_POWER_HIGH_ALARM_FIELD]))), - "txpowerlowalarm": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.TX_POWER_LOW_ALARM_FIELD]))), - "txpowerhighwarning": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.TX_POWER_HIGH_WARNING_FIELD]))), - "txpowerlowwarning": float("{:.3f}".format(self.mw_to_dbm(thresh[consts.TX_POWER_LOW_WARNING_FIELD]))), - "txbiashighalarm": float("{:.3f}".format(thresh[consts.TX_BIAS_HIGH_ALARM_FIELD]*tx_bias_scale)), - "txbiaslowalarm": float("{:.3f}".format(thresh[consts.TX_BIAS_LOW_ALARM_FIELD]*tx_bias_scale)), - "txbiashighwarning": float("{:.3f}".format(thresh[consts.TX_BIAS_HIGH_WARNING_FIELD]*tx_bias_scale)), - "txbiaslowwarning": float("{:.3f}".format(thresh[consts.TX_BIAS_LOW_WARNING_FIELD]*tx_bias_scale)) - } - laser_temp_dict = self.get_laser_temperature() - threshold_info_dict['lasertemphighalarm'] = laser_temp_dict['high alarm'] - threshold_info_dict['lasertemplowalarm'] = laser_temp_dict['low alarm'] - threshold_info_dict['lasertemphighwarning'] = laser_temp_dict['high warn'] - threshold_info_dict['lasertemplowwarning'] = laser_temp_dict['low warn'] - self.vdm_dict = self.get_vdm() - try: - threshold_info_dict['prefecberhighalarm'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][1] - threshold_info_dict['prefecberlowalarm'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][2] - threshold_info_dict['prefecberhighwarning'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][3] - threshold_info_dict['prefecberlowwarning'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][4] - threshold_info_dict['postfecberhighalarm'] = self.vdm_dict['Errored Frames Average Media Input'][1][1] - threshold_info_dict['postfecberlowalarm'] = self.vdm_dict['Errored Frames Average Media Input'][1][2] - threshold_info_dict['postfecberhighwarning'] = self.vdm_dict['Errored Frames Average Media Input'][1][3] - threshold_info_dict['postfecberlowwarning'] = self.vdm_dict['Errored Frames Average Media Input'][1][4] - except (KeyError, TypeError): - pass - return threshold_info_dict - - def get_module_temperature(self): - ''' - This function returns the module case temperature and its thresholds. Unit in deg C - ''' - if not self.get_temperature_support(): - return 'N/A' - temp = self.xcvr_eeprom.read(consts.TEMPERATURE_FIELD) - if temp is None: - return None - return float("{:.3f}".format(temp)) - - def get_voltage(self): - ''' - This function returns the monitored value of the 3.3-V supply voltage and its thresholds. - Unit in V - ''' - if not self.get_voltage_support(): - return 'N/A' - voltage = self.xcvr_eeprom.read(consts.VOLTAGE_FIELD) - if voltage is None: - return None - return float("{:.3f}".format(voltage)) - - def is_flat_memory(self): - return self.xcvr_eeprom.read(consts.FLAT_MEM_FIELD) - - def get_temperature_support(self): - return not self.is_flat_memory() - - def get_voltage_support(self): - return not self.is_flat_memory() - - def get_rx_los_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.RX_LOS_SUPPORT) - - def get_tx_cdr_lol_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_CDR_LOL_SUPPORT_FIELD) - - def get_tx_cdr_lol(self): - ''' - This function returns TX CDR LOL flag on TX host lane - ''' - tx_cdr_lol_support = self.get_tx_cdr_lol_support() - if tx_cdr_lol_support is None: - return None - if not tx_cdr_lol_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_cdr_lol = self.xcvr_eeprom.read(consts.TX_CDR_LOL) - if tx_cdr_lol is None: - return None - keys = sorted(tx_cdr_lol.keys()) - tx_cdr_lol_final = [] - for key in keys: - tx_cdr_lol_final.append(bool(tx_cdr_lol[key])) - return tx_cdr_lol_final - - def get_rx_los(self): - ''' - This function returns RX LOS flag on RX media lane - ''' - rx_los_support = self.get_rx_los_support() - if rx_los_support is None: - return None - if not rx_los_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - rx_los = self.xcvr_eeprom.read(consts.RX_LOS_FIELD) - if rx_los is None: - return None - keys = sorted(rx_los.keys()) - rx_los_final = [] - for key in keys: - rx_los_final.append(bool(rx_los[key])) - return rx_los_final - - def get_rx_cdr_lol_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.RX_CDR_LOL_SUPPORT_FIELD) - - def get_rx_cdr_lol(self): - ''' - This function returns RX CDR LOL flag on RX media lane - ''' - rx_cdr_lol_support = self.get_rx_cdr_lol_support() - if rx_cdr_lol_support is None: - return None - if not rx_cdr_lol_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - rx_cdr_lol = self.xcvr_eeprom.read(consts.RX_CDR_LOL) - if rx_cdr_lol is None: - return None - keys = sorted(rx_cdr_lol.keys()) - rx_cdr_lol_final = [] - for key in keys: - rx_cdr_lol_final.append(bool(rx_cdr_lol[key])) - return rx_cdr_lol_final - - def get_tx_power_flag(self): - ''' - This function returns TX power out of range flag on TX media lane - ''' - tx_power_high_alarm_dict = self.xcvr_eeprom.read(consts.TX_POWER_HIGH_ALARM_FLAG) - tx_power_low_alarm_dict = self.xcvr_eeprom.read(consts.TX_POWER_LOW_ALARM_FLAG) - tx_power_high_warn_dict = self.xcvr_eeprom.read(consts.TX_POWER_HIGH_WARN_FLAG) - tx_power_low_warn_dict = self.xcvr_eeprom.read(consts.TX_POWER_LOW_WARN_FLAG) - if tx_power_high_alarm_dict is None or tx_power_low_alarm_dict is None or tx_power_high_warn_dict is None or tx_power_low_warn_dict is None: - return None - for key, value in tx_power_high_alarm_dict.items(): - tx_power_high_alarm_dict[key] = bool(value) - for key, value in tx_power_low_alarm_dict.items(): - tx_power_low_alarm_dict[key] = bool(value) - for key, value in tx_power_high_warn_dict.items(): - tx_power_high_warn_dict[key] = bool(value) - for key, value in tx_power_low_warn_dict.items(): - tx_power_low_warn_dict[key] = bool(value) - tx_power_flag_dict = {'tx_power_high_alarm': tx_power_high_alarm_dict, - 'tx_power_low_alarm': tx_power_low_alarm_dict, - 'tx_power_high_warn': tx_power_high_warn_dict, - 'tx_power_low_warn': tx_power_low_warn_dict,} - return tx_power_flag_dict - - def get_tx_bias_flag(self): - ''' - This function returns TX bias out of range flag on TX media lane - ''' - tx_bias_high_alarm_dict = self.xcvr_eeprom.read(consts.TX_BIAS_HIGH_ALARM_FLAG) - tx_bias_low_alarm_dict = self.xcvr_eeprom.read(consts.TX_BIAS_LOW_ALARM_FLAG) - tx_bias_high_warn_dict = self.xcvr_eeprom.read(consts.TX_BIAS_HIGH_WARN_FLAG) - tx_bias_low_warn_dict = self.xcvr_eeprom.read(consts.TX_BIAS_LOW_WARN_FLAG) - if tx_bias_high_alarm_dict is None or tx_bias_low_alarm_dict is None or tx_bias_high_warn_dict is None or tx_bias_low_warn_dict is None: - return None - for key, value in tx_bias_high_alarm_dict.items(): - tx_bias_high_alarm_dict[key] = bool(value) - for key, value in tx_bias_low_alarm_dict.items(): - tx_bias_low_alarm_dict[key] = bool(value) - for key, value in tx_bias_high_warn_dict.items(): - tx_bias_high_warn_dict[key] = bool(value) - for key, value in tx_bias_low_warn_dict.items(): - tx_bias_low_warn_dict[key] = bool(value) - tx_bias_flag_dict = {'tx_bias_high_alarm': tx_bias_high_alarm_dict, - 'tx_bias_low_alarm': tx_bias_low_alarm_dict, - 'tx_bias_high_warn': tx_bias_high_warn_dict, - 'tx_bias_low_warn': tx_bias_low_warn_dict,} - return tx_bias_flag_dict - - def get_rx_power_flag(self): - ''' - This function returns RX power out of range flag on RX media lane - ''' - rx_power_high_alarm_dict = self.xcvr_eeprom.read(consts.RX_POWER_HIGH_ALARM_FLAG) - rx_power_low_alarm_dict = self.xcvr_eeprom.read(consts.RX_POWER_LOW_ALARM_FLAG) - rx_power_high_warn_dict = self.xcvr_eeprom.read(consts.RX_POWER_HIGH_WARN_FLAG) - rx_power_low_warn_dict = self.xcvr_eeprom.read(consts.RX_POWER_LOW_WARN_FLAG) - if rx_power_high_alarm_dict is None or rx_power_low_alarm_dict is None or rx_power_high_warn_dict is None or rx_power_low_warn_dict is None: - return None - for key, value in rx_power_high_alarm_dict.items(): - rx_power_high_alarm_dict[key] = bool(value) - for key, value in rx_power_low_alarm_dict.items(): - rx_power_low_alarm_dict[key] = bool(value) - for key, value in rx_power_high_warn_dict.items(): - rx_power_high_warn_dict[key] = bool(value) - for key, value in rx_power_low_warn_dict.items(): - rx_power_low_warn_dict[key] = bool(value) - rx_power_flag_dict = {'rx_power_high_alarm': rx_power_high_alarm_dict, - 'rx_power_low_alarm': rx_power_low_alarm_dict, - 'rx_power_high_warn': rx_power_high_warn_dict, - 'rx_power_low_warn': rx_power_low_warn_dict,} - return rx_power_flag_dict - - def get_tx_output_status(self): - ''' - This function returns whether TX output signals are valid on TX media lane - ''' - tx_output_status_dict = self.xcvr_eeprom.read(consts.TX_OUTPUT_STATUS) - if tx_output_status_dict is None: - return None - for key, value in tx_output_status_dict.items(): - tx_output_status_dict[key] = bool(value) - return tx_output_status_dict - - def get_rx_output_status(self): - ''' - This function returns whether RX output signals are valid on RX host lane - ''' - rx_output_status_dict = self.xcvr_eeprom.read(consts.RX_OUTPUT_STATUS) - if rx_output_status_dict is None: - return None - for key, value in rx_output_status_dict.items(): - rx_output_status_dict[key] = bool(value) - return rx_output_status_dict - - def get_tx_bias_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_BIAS_SUPPORT_FIELD) - - def get_tx_bias(self): - ''' - This function returns TX bias current on each media lane - ''' - tx_bias_support = self.get_tx_bias_support() - if tx_bias_support is None: - return None - if not tx_bias_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - scale_raw = self.xcvr_eeprom.read(consts.TX_BIAS_SCALE) - scale = 2**scale_raw if scale_raw < 3 else 1 - tx_bias = self.xcvr_eeprom.read(consts.TX_BIAS_FIELD) - for key, value in tx_bias.items(): - tx_bias[key] *= scale - return [tx_bias['LaserBiasTx%dField' % i] for i in range(1, self.NUM_CHANNELS + 1)] - - def get_tx_power(self): - ''' - This function returns TX output power in mW on each media lane - ''' - tx_power_support = self.get_tx_power_support() - if tx_power_support is None: - return None - - tx_power = ["N/A" for _ in range(self.NUM_CHANNELS)] - - if tx_power_support: - tx_power = self.xcvr_eeprom.read(consts.TX_POWER_FIELD) - if tx_power is not None: - tx_power = [tx_power['OpticalPowerTx%dField' %i] for i in range(1, self.NUM_CHANNELS+1)] - - return tx_power - - def get_tx_power_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_POWER_SUPPORT_FIELD) - - def get_rx_power(self): - ''' - This function returns RX input power in mW on each media lane - ''' - rx_power_support = self.get_rx_power_support() - if rx_power_support is None: - return None - - rx_power = ["N/A" for _ in range(self.NUM_CHANNELS)] - - if rx_power_support: - rx_power = self.xcvr_eeprom.read(consts.RX_POWER_FIELD) - if rx_power is not None: - rx_power = [rx_power['OpticalPowerRx%dField' %i] for i in range(1, self.NUM_CHANNELS+1)] - - return rx_power - - def get_rx_power_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.RX_POWER_SUPPORT_FIELD) - - def get_tx_fault_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_FAULT_SUPPORT_FIELD) - - def get_tx_fault(self): - ''' - This function returns TX fault flag on TX media lane - ''' - tx_fault_support = self.get_tx_fault_support() - if tx_fault_support is None: - return None - if not tx_fault_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_fault = self.xcvr_eeprom.read(consts.TX_FAULT_FIELD) - if tx_fault is None: - return None - keys = sorted(tx_fault.keys()) - tx_fault_final = [] - for key in keys: - tx_fault_final.append(bool(tx_fault[key])) - return tx_fault_final - - def get_tx_los_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_LOS_SUPPORT_FIELD) - - def get_tx_los(self): - ''' - This function returns TX LOS flag on TX host lane - ''' - tx_los_support = self.get_tx_los_support() - if tx_los_support is None: - return None - if not tx_los_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_los = self.xcvr_eeprom.read(consts.TX_LOS_FIELD) - if tx_los is None: - return None - keys = sorted(tx_los.keys()) - tx_los_final = [] - for key in keys: - tx_los_final.append(bool(tx_los[key])) - return tx_los_final - - def get_tx_disable_support(self): - return not self.is_flat_memory() and self.xcvr_eeprom.read(consts.TX_DISABLE_SUPPORT_FIELD) - - def get_tx_disable(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_disable = self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - if tx_disable is None: - return None - return [bool(tx_disable & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def tx_disable(self, tx_disable): - val = 0xFF if tx_disable else 0x0 - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, val) - - def get_tx_disable_channel(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return 'N/A' - return self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - - def tx_disable_channel(self, channel, disable): - channel_state = self.get_tx_disable_channel() - if channel_state is None or channel_state == 'N/A': - return False - - for i in range(self.NUM_CHANNELS): - mask = (1 << i) - if not (channel & mask): - continue - if disable: - channel_state |= mask - else: - channel_state &= ~mask - - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, channel_state) - - def get_power_override(self): - return None - - def set_power_override(self, power_override, power_set): - return True - - def get_transceiver_thresholds_support(self): - return not self.is_flat_memory() - - def get_lpmode_support(self): - power_class = self.xcvr_eeprom.read(consts.POWER_CLASS_FIELD) - if power_class is None: - return False - return "Power Class 1" not in power_class - - def get_power_override_support(self): - return False - - def get_module_media_type(self): - ''' - This function returns module media type: MMF, SMF, Passive Copper Cable, Active Cable Assembly or Base-T. - ''' - return self.xcvr_eeprom.read(consts.MEDIA_TYPE_FIELD) - - def get_host_electrical_interface(self): - ''' - This function returns module host electrical interface. Table 4-5 in SFF-8024 Rev4.6 - ''' - if self.is_flat_memory(): - return 'N/A' - return self.xcvr_eeprom.read(consts.HOST_ELECTRICAL_INTERFACE) - - def get_module_media_interface(self): - ''' - This function returns module media electrical interface. Table 4-6 ~ 4-10 in SFF-8024 Rev4.6 - ''' - media_type = self.get_module_media_type() - if media_type == 'nm_850_media_interface': - return self.xcvr_eeprom.read(consts.MODULE_MEDIA_INTERFACE_850NM) - elif media_type == 'sm_media_interface': - return self.xcvr_eeprom.read(consts.MODULE_MEDIA_INTERFACE_SM) - elif media_type == 'passive_copper_media_interface': - return self.xcvr_eeprom.read(consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER) - elif media_type == 'active_cable_media_interface': - return self.xcvr_eeprom.read(consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE) - elif media_type == 'base_t_media_interface': - return self.xcvr_eeprom.read(consts.MODULE_MEDIA_INTERFACE_BASE_T) - else: - return 'Unknown media interface' - - def is_coherent_module(self): - ''' - Returns True if the module follow C-CMIS spec, False otherwise - ''' - mintf = self.get_module_media_interface() - return False if 'ZR' not in mintf else True - - def get_datapath_init_duration(self): - ''' - This function returns the duration of datapath init - ''' - if self.is_flat_memory(): - return 0 - duration = self.xcvr_eeprom.read(consts.DP_PATH_INIT_DURATION) - return float(duration) if duration is not None else 0 - - def get_datapath_deinit_duration(self): - ''' - This function returns the duration of datapath deinit - ''' - if self.is_flat_memory(): - return 0 - duration = self.xcvr_eeprom.read(consts.DP_PATH_DEINIT_DURATION) - return float(duration) if duration is not None else 0 - - def get_host_lane_count(self): - ''' - This function returns number of host lanes for default application - ''' - return self.xcvr_eeprom.read(consts.HOST_LANE_COUNT) - - def get_media_lane_count(self): - ''' - This function returns number of media lanes for default application - ''' - if self.is_flat_memory(): - return 0 - return self.xcvr_eeprom.read(consts.MEDIA_LANE_COUNT) - - def get_media_interface_technology(self): - ''' - This function returns the media lane technology - ''' - return self.xcvr_eeprom.read(consts.MEDIA_INTERFACE_TECH) - - def get_host_lane_assignment_option(self): - ''' - This function returns the host lane that the application begins on - ''' - return self.xcvr_eeprom.read(consts.HOST_LANE_ASSIGNMENT_OPTION) - - def get_media_lane_assignment_option(self): - ''' - This function returns the media lane that the application is allowed to begin on - ''' - if self.is_flat_memory(): - return 'N/A' - return self.xcvr_eeprom.read(consts.MEDIA_LANE_ASSIGNMENT_OPTION) - - def get_active_apsel_hostlane(self): - ''' - This function returns the application select code that each host lane has - ''' - if (self.is_flat_memory()): - return {'{}{}'.format(consts.ACTIVE_APSEL_HOSTLANE, i) : 'N/A' for i in range(1, self.NUM_CHANNELS+1)} - return self.xcvr_eeprom.read(consts.ACTIVE_APSEL_CODE) - - def get_tx_config_power(self): - ''' - This function returns the configured TX output power. Unit in dBm - ''' - return self.xcvr_eeprom.read(consts.TX_CONFIG_POWER) - - def get_media_output_loopback(self): - ''' - This function returns the media output loopback status - ''' - result = self.xcvr_eeprom.read(consts.MEDIA_OUTPUT_LOOPBACK) - if result is None: - return None - return result == 1 - - def get_media_input_loopback(self): - ''' - This function returns the media input loopback status - ''' - result = self.xcvr_eeprom.read(consts.MEDIA_INPUT_LOOPBACK) - if result is None: - return None - return result == 1 - - def get_host_output_loopback(self): - ''' - This function returns the host output loopback status - ''' - result = self.xcvr_eeprom.read(consts.HOST_OUTPUT_LOOPBACK) - if result is None: - return None - loopback_status = [] - for bitpos in range(self.NUM_CHANNELS): - loopback_status.append(bool((result >> bitpos) & 0x1)) - return loopback_status - - def get_host_input_loopback(self): - ''' - This function returns the host input loopback status - ''' - result = self.xcvr_eeprom.read(consts.HOST_INPUT_LOOPBACK) - if result is None: - return None - loopback_status = [] - for bitpos in range(self.NUM_CHANNELS): - loopback_status.append(bool((result >> bitpos) & 0x1)) - return loopback_status - - def get_aux_mon_type(self): - ''' - This function returns the aux monitor types - ''' - result = self.xcvr_eeprom.read(consts.AUX_MON_TYPE) if not self.is_flat_memory() else None - if result is None: - return None - aux1_mon_type = result & 0x1 - aux2_mon_type = (result >> 1) & 0x1 - aux3_mon_type = (result >> 2) & 0x1 - return aux1_mon_type, aux2_mon_type, aux3_mon_type - - def get_laser_temperature(self): - ''' - This function returns the laser temperature monitor value - ''' - laser_temp_dict = { - 'monitor value' : 'N/A', - 'high alarm' : 'N/A', - 'low alarm' : 'N/A', - 'high warn' : 'N/A', - 'low warn' : 'N/A' - } - - if self.is_flat_memory(): - return laser_temp_dict - - try: - aux1_mon_type, aux2_mon_type, aux3_mon_type = self.get_aux_mon_type() - except TypeError: - return None - LASER_TEMP_SCALE = 256.0 - if aux2_mon_type == 0: - laser_temp = self.xcvr_eeprom.read(consts.AUX2_MON)/LASER_TEMP_SCALE - laser_temp_high_alarm = self.xcvr_eeprom.read(consts.AUX2_HIGH_ALARM)/LASER_TEMP_SCALE - laser_temp_low_alarm = self.xcvr_eeprom.read(consts.AUX2_LOW_ALARM)/LASER_TEMP_SCALE - laser_temp_high_warn = self.xcvr_eeprom.read(consts.AUX2_HIGH_WARN)/LASER_TEMP_SCALE - laser_temp_low_warn = self.xcvr_eeprom.read(consts.AUX2_LOW_WARN)/LASER_TEMP_SCALE - elif aux2_mon_type == 1 and aux3_mon_type == 0: - laser_temp = self.xcvr_eeprom.read(consts.AUX3_MON)/LASER_TEMP_SCALE - laser_temp_high_alarm = self.xcvr_eeprom.read(consts.AUX3_HIGH_ALARM)/LASER_TEMP_SCALE - laser_temp_low_alarm = self.xcvr_eeprom.read(consts.AUX3_LOW_ALARM)/LASER_TEMP_SCALE - laser_temp_high_warn = self.xcvr_eeprom.read(consts.AUX3_HIGH_WARN)/LASER_TEMP_SCALE - laser_temp_low_warn = self.xcvr_eeprom.read(consts.AUX3_LOW_WARN)/LASER_TEMP_SCALE - else: - return laser_temp_dict - laser_temp_dict = {'monitor value': laser_temp, - 'high alarm': laser_temp_high_alarm, - 'low alarm': laser_temp_low_alarm, - 'high warn': laser_temp_high_warn, - 'low warn': laser_temp_low_warn} - return laser_temp_dict - - def get_laser_TEC_current(self): - ''' - This function returns the laser TEC current monitor value - ''' - try: - aux1_mon_type, aux2_mon_type, aux3_mon_type = self.get_aux_mon_type() - except TypeError: - return None - LASER_TEC_CURRENT_SCALE = 32767.0 - if aux1_mon_type == 1: - laser_tec_current = self.xcvr_eeprom.read(consts.AUX1_MON)/LASER_TEC_CURRENT_SCALE - laser_tec_current_high_alarm = self.xcvr_eeprom.read(consts.AUX1_HIGH_ALARM)/LASER_TEC_CURRENT_SCALE - laser_tec_current_low_alarm = self.xcvr_eeprom.read(consts.AUX1_LOW_ALARM)/LASER_TEC_CURRENT_SCALE - laser_tec_current_high_warn = self.xcvr_eeprom.read(consts.AUX1_HIGH_WARN)/LASER_TEC_CURRENT_SCALE - laser_tec_current_low_warn = self.xcvr_eeprom.read(consts.AUX1_LOW_WARN)/LASER_TEC_CURRENT_SCALE - elif aux1_mon_type == 0 and aux2_mon_type == 1: - laser_tec_current = self.xcvr_eeprom.read(consts.AUX2_MON)/LASER_TEC_CURRENT_SCALE - laser_tec_current_high_alarm = self.xcvr_eeprom.read(consts.AUX2_HIGH_ALARM)/LASER_TEC_CURRENT_SCALE - laser_tec_current_low_alarm = self.xcvr_eeprom.read(consts.AUX2_LOW_ALARM)/LASER_TEC_CURRENT_SCALE - laser_tec_current_high_warn = self.xcvr_eeprom.read(consts.AUX2_HIGH_WARN)/LASER_TEC_CURRENT_SCALE - laser_tec_current_low_warn = self.xcvr_eeprom.read(consts.AUX2_LOW_WARN)/LASER_TEC_CURRENT_SCALE - else: - return None - laser_tec_current_dict = {'monitor value': laser_tec_current, - 'high alarm': laser_tec_current_high_alarm, - 'low alarm': laser_tec_current_low_alarm, - 'high warn': laser_tec_current_high_warn, - 'low warn': laser_tec_current_low_warn} - return laser_tec_current_dict - - def get_config_datapath_hostlane_status(self): - ''' - This function returns configuration command execution - / result status for the datapath of each host lane - ''' - return self.xcvr_eeprom.read(consts.CONFIG_LANE_STATUS) - - def get_datapath_state(self): - ''' - This function returns the eight datapath states - ''' - return self.xcvr_eeprom.read(consts.DATA_PATH_STATE) - - def get_dpinit_pending(self): - ''' - This function returns datapath init pending status. - 0 means datapath init not pending. - 1 means datapath init pending. DPInit not yet executed after successful ApplyDPInit. - Hence the active control set content may deviate from the actual hardware config - ''' - dpinit_pending_dict = self.xcvr_eeprom.read(consts.DPINIT_PENDING) - if dpinit_pending_dict is None: - return None - for key, value in dpinit_pending_dict.items(): - dpinit_pending_dict[key] = bool(value) - return dpinit_pending_dict - - def get_supported_power_config(self): - ''' - This function returns the supported TX power range - ''' - min_prog_tx_output_power = self.xcvr_eeprom.read(consts.MIN_PROG_OUTPUT_POWER) - max_prog_tx_output_power = self.xcvr_eeprom.read(consts.MAX_PROG_OUTPUT_POWER) - return min_prog_tx_output_power, max_prog_tx_output_power - - def reset_module(self, reset = False): - ''' - This function resets the module - Return True if the provision succeeds, False if it fails - Return True if no action. - ''' - if reset: - reset_control = reset << 3 - return self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, reset_control) - else: - return True - - def reset(self): - """ - Reset SFP and return all user module settings to their default state. - - Returns: - A boolean, True if successful, False if not - """ - if self.reset_module(True): - # minimum waiting time for the TWI to be functional again - time.sleep(2) - # buffer time - for retries in range(5): - state = self.get_module_state() - if state in ['ModuleReady', 'ModuleLowPwr']: - return True - time.sleep(1) - return False - - def get_lpmode(self): - ''' - Retrieves Low power module status - Returns True if module in low power else returns False. - ''' - if self.is_flat_memory() or not self.get_lpmode_support(): - return False - - lpmode = self.xcvr_eeprom.read(consts.TRANS_MODULE_STATUS_FIELD) - if lpmode is not None: - if lpmode.get('ModuleState') == 'ModuleLowPwr': - return True - return False - - def set_lpmode(self, lpmode): - ''' - This function sets the module to low power state. - lpmode being False means "set to high power" - lpmode being True means "set to low power" - Return True if the provision succeeds, False if it fails - ''' - - if self.is_flat_memory() or not self.get_lpmode_support(): - return False - - lpmode_val = self.xcvr_eeprom.read(consts.MODULE_LEVEL_CONTROL) - if lpmode_val is not None: - if lpmode is True: - # Force module transition to LowPwr under SW control - lpmode_val = lpmode_val | (1 << CmisApi.LowPwrRequestSW) - self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, lpmode_val) - time.sleep(0.1) - return self.get_lpmode() - else: - # Force transition from LowPwr to HighPower state under SW control. - # This will transition LowPwrS signal to False. (see Table 6-12 CMIS v5.0) - lpmode_val = lpmode_val & ~(1 << CmisApi.LowPwrRequestSW) - lpmode_val = lpmode_val & ~(1 << CmisApi.LowPwrAllowRequestHW) - self.xcvr_eeprom.write(consts.MODULE_LEVEL_CONTROL, lpmode_val) - time.sleep(1) - mstate = self.get_module_state() - return True if mstate == 'ModuleReady' else False - return False - - def get_loopback_capability(self): - ''' - This function returns the module loopback capability as advertised - ''' - if self.is_flat_memory(): - return None - allowed_loopback_result = self.xcvr_eeprom.read(consts.LOOPBACK_CAPABILITY) - if allowed_loopback_result is None: - return None - loopback_capability = dict() - loopback_capability['simultaneous_host_media_loopback_supported'] = bool((allowed_loopback_result >> 6) & 0x1) - loopback_capability['per_lane_media_loopback_supported'] = bool((allowed_loopback_result >> 5) & 0x1) - loopback_capability['per_lane_host_loopback_supported'] = bool((allowed_loopback_result >> 4) & 0x1) - loopback_capability['host_side_input_loopback_supported'] = bool((allowed_loopback_result >> 3) & 0x1) - loopback_capability['host_side_output_loopback_supported'] = bool((allowed_loopback_result >> 2) & 0x1) - loopback_capability['media_side_input_loopback_supported'] = bool((allowed_loopback_result >> 1) & 0x1) - loopback_capability['media_side_output_loopback_supported'] = bool((allowed_loopback_result >> 0) & 0x1) - return loopback_capability - - def set_loopback_mode(self, loopback_mode): - ''' - This function sets the module loopback mode. - Loopback mode has to be one of the five: - 1. "none" (default) - 2. "host-side-input" - 3. "host-side-output" - 4. "media-side-input" - 5. "media-side-output" - The function will look at 13h:128 to check advertized loopback capabilities. - Return True if the provision succeeds, False if it fails - ''' - loopback_capability = self.get_loopback_capability() - if loopback_capability is None: - return False - if loopback_mode == 'none': - status_host_input = self.xcvr_eeprom.write(consts.HOST_INPUT_LOOPBACK, 0) - status_host_output = self.xcvr_eeprom.write(consts.HOST_OUTPUT_LOOPBACK, 0) - status_media_input = self.xcvr_eeprom.write(consts.MEDIA_INPUT_LOOPBACK, 0) - status_media_output = self.xcvr_eeprom.write(consts.MEDIA_OUTPUT_LOOPBACK, 0) - return all([status_host_input, status_host_output, status_media_input, status_media_output]) - elif loopback_mode == 'host-side-input': - if loopback_capability['host_side_input_loopback_supported']: - return self.xcvr_eeprom.write(consts.HOST_INPUT_LOOPBACK, 0xff) - else: - return False - elif loopback_mode == 'host-side-output': - if loopback_capability['host_side_output_loopback_supported']: - return self.xcvr_eeprom.write(consts.HOST_OUTPUT_LOOPBACK, 0xff) - else: - return False - elif loopback_mode == 'media-side-input': - if loopback_capability['media_side_input_loopback_supported']: - return self.xcvr_eeprom.write(consts.MEDIA_INPUT_LOOPBACK, 0xff) - else: - return False - elif loopback_mode == 'media-side-output': - if loopback_capability['media_side_output_loopback_supported']: - return self.xcvr_eeprom.write(consts.MEDIA_OUTPUT_LOOPBACK, 0xff) - else: - return False - else: - return False - - def get_vdm(self): - ''' - This function returns all the VDM items, including real time monitor value, threholds and flags - ''' - vdm = self.vdm.get_vdm_allpage() if self.vdm is not None else {} - return vdm - - def get_module_firmware_fault_state_changed(self): - ''' - This function returns datapath firmware fault state, module firmware fault state - and whether module state changed - ''' - result = self.xcvr_eeprom.read(consts.MODULE_FIRMWARE_FAULT_INFO) - if result is None: - return None - datapath_firmware_fault = bool((result >> 2) & 0x1) - module_firmware_fault = bool((result >> 1) & 0x1) - module_state_changed = bool(result & 0x1) - return datapath_firmware_fault, module_firmware_fault, module_state_changed - - def get_module_level_flag(self): - ''' - This function returns teh module level flags, including - - 3.3 V voltage supply flags - - Case temperature flags - - Aux 1 flags - - Aux 2 flags - - Aux 3 flags - - Custom field flags - ''' - module_flag_byte1 = self.xcvr_eeprom.read(consts.MODULE_FLAG_BYTE1) - module_flag_byte2 = self.xcvr_eeprom.read(consts.MODULE_FLAG_BYTE2) - module_flag_byte3 = self.xcvr_eeprom.read(consts.MODULE_FLAG_BYTE3) - if module_flag_byte1 is None or module_flag_byte2 is None or module_flag_byte3 is None: - return None - voltage_high_alarm_flag = bool((module_flag_byte1 >> 4) & 0x1) - voltage_low_alarm_flag = bool((module_flag_byte1 >> 5) & 0x1) - voltage_high_warn_flag = bool((module_flag_byte1 >> 6) & 0x1) - voltage_low_warn_flag = bool((module_flag_byte1 >> 7) & 0x1) - voltage_flags = {'voltage_high_alarm_flag': voltage_high_alarm_flag, - 'voltage_low_alarm_flag': voltage_low_alarm_flag, - 'voltage_high_warn_flag': voltage_high_warn_flag, - 'voltage_low_warn_flag': voltage_low_warn_flag} - - case_temp_high_alarm_flag = bool((module_flag_byte1 >> 0) & 0x1) - case_temp_low_alarm_flag = bool((module_flag_byte1 >> 1) & 0x1) - case_temp_high_warn_flag = bool((module_flag_byte1 >> 2) & 0x1) - case_temp_low_warn_flag = bool((module_flag_byte1 >> 3) & 0x1) - case_temp_flags = {'case_temp_high_alarm_flag': case_temp_high_alarm_flag, - 'case_temp_low_alarm_flag': case_temp_low_alarm_flag, - 'case_temp_high_warn_flag': case_temp_high_warn_flag, - 'case_temp_low_warn_flag': case_temp_low_warn_flag} - - aux2_high_alarm_flag = bool((module_flag_byte2 >> 4) & 0x1) - aux2_low_alarm_flag = bool((module_flag_byte2 >> 5) & 0x1) - aux2_high_warn_flag = bool((module_flag_byte2 >> 6) & 0x1) - aux2_low_warn_flag = bool((module_flag_byte2 >> 7) & 0x1) - aux2_flags = {'aux2_high_alarm_flag': aux2_high_alarm_flag, - 'aux2_low_alarm_flag': aux2_low_alarm_flag, - 'aux2_high_warn_flag': aux2_high_warn_flag, - 'aux2_low_warn_flag': aux2_low_warn_flag} - - aux1_high_alarm_flag = bool((module_flag_byte2 >> 0) & 0x1) - aux1_low_alarm_flag = bool((module_flag_byte2 >> 1) & 0x1) - aux1_high_warn_flag = bool((module_flag_byte2 >> 2) & 0x1) - aux1_low_warn_flag = bool((module_flag_byte2 >> 3) & 0x1) - aux1_flags = {'aux1_high_alarm_flag': aux1_high_alarm_flag, - 'aux1_low_alarm_flag': aux1_low_alarm_flag, - 'aux1_high_warn_flag': aux1_high_warn_flag, - 'aux1_low_warn_flag': aux1_low_warn_flag} - - custom_mon_high_alarm_flag = bool((module_flag_byte3 >> 4) & 0x1) - custom_mon_low_alarm_flag = bool((module_flag_byte3 >> 5) & 0x1) - custom_mon_high_warn_flag = bool((module_flag_byte3 >> 6) & 0x1) - custom_mon_low_warn_flag = bool((module_flag_byte3 >> 7) & 0x1) - custom_mon_flags = {'custom_mon_high_alarm_flag': custom_mon_high_alarm_flag, - 'custom_mon_low_alarm_flag': custom_mon_low_alarm_flag, - 'custom_mon_high_warn_flag': custom_mon_high_warn_flag, - 'custom_mon_low_warn_flag': custom_mon_low_warn_flag} - - aux3_high_alarm_flag = bool((module_flag_byte3 >> 0) & 0x1) - aux3_low_alarm_flag = bool((module_flag_byte3 >> 1) & 0x1) - aux3_high_warn_flag = bool((module_flag_byte3 >> 2) & 0x1) - aux3_low_warn_flag = bool((module_flag_byte3 >> 3) & 0x1) - aux3_flags = {'aux3_high_alarm_flag': aux3_high_alarm_flag, - 'aux3_low_alarm_flag': aux3_low_alarm_flag, - 'aux3_high_warn_flag': aux3_high_warn_flag, - 'aux3_low_warn_flag': aux3_low_warn_flag} - - module_flag = {'voltage_flags': voltage_flags, - 'case_temp_flags': case_temp_flags, - 'aux1_flags': aux1_flags, - 'aux2_flags': aux2_flags, - 'aux3_flags': aux3_flags, - 'custom_mon_flags': custom_mon_flags} - return module_flag - - def get_module_fw_mgmt_feature(self, verbose = False): - """ - This function obtains CDB features supported by the module from CDB command 0041h, - such as start header size, maximum block size, whether extended payload messaging - (page 0xA0 - 0xAF) or only local payload is supported. These features are important because - the following upgrade with depend on these parameters. - """ - txt = '' - if self.cdb is None: - return {'status': False, 'info': "CDB Not supported", 'result': None} - - # get fw upgrade features (CMD 0041h) - starttime = time.time() - autopaging = self.xcvr_eeprom.read(consts.AUTO_PAGING_SUPPORT) - autopaging_flag = bool(autopaging) - writelength_raw = self.xcvr_eeprom.read(consts.CDB_SEQ_WRITE_LENGTH_EXT) - if writelength_raw is None: - return None - writelength = (writelength_raw + 1) * 8 - txt += 'Auto page support: %s\n' %autopaging_flag - txt += 'Max write length: %d\n' %writelength - rpllen, rpl_chkcode, rpl = self.cdb.get_fw_management_features() - if self.cdb.cdb_chkcode(rpl) == rpl_chkcode: - startLPLsize = rpl[2] - txt += 'Start payload size %d\n' % startLPLsize - maxblocksize = (rpl[4] + 1) * 8 - txt += 'Max block size %d\n' % maxblocksize - lplEplSupport = {0x00 : 'No write to LPL/EPL supported', - 0x01 : 'Write to LPL supported', - 0x10 : 'Write to EPL supported', - 0x11 : 'Write to LPL/EPL supported'} - txt += '{}\n'.format(lplEplSupport[rpl[5]]) - if rpl[5] == 1: - lplonly_flag = True - else: - lplonly_flag = False - txt += 'Abort CMD102h supported %s\n' %bool(rpl[1] & 0x01) - if verbose: - txt += 'Copy CMD108h supported %s\n' %bool((rpl[1] >> 1) & 0x01) - txt += 'Skipping erased blocks supported %s\n' %bool((rpl[1] >> 2) & 0x01) - txt += 'Full image readback supported %s\n' %bool((rpl[1] >> 7) & 0x01) - txt += 'Default erase byte {:#x}\n'.format(rpl[3]) - txt += 'Read to LPL/EPL {:#x}\n'.format(rpl[6]) - - else: - txt += 'Reply payload check code error\n' - return {'status': False, 'info': txt, 'result': None} - elapsedtime = time.time()-starttime - logger.info('Get module FW upgrade features time: %.2f s\n' %elapsedtime) - logger.info(txt) - return {'status': True, 'info': txt, 'feature': (startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength)} - - def get_module_fw_info(self): - """ - This function returns firmware Image A and B version, running version, committed version - and whether both firmware images are valid. - Operational Status: 1 = running, 0 = not running - Administrative Status: 1=committed, 0=uncommitted - Validity Status: 1 = invalid, 0 = valid - """ - txt = '' - - if self.cdb is None: - return {'status': False, 'info': "CDB Not supported", 'result': None} - - # get fw info (CMD 0100h) - rpllen, rpl_chkcode, rpl = self.cdb.get_fw_info() - # Interface NACK or timeout - if (rpllen is None) or (rpl_chkcode is None): - return {'status': False, 'info': "Interface fail", 'result': 0} # Return result 0 for distinguishing CDB is maybe in busy or failure. - - # password issue - if self.cdb.cdb_chkcode(rpl) != rpl_chkcode: - string = 'Get module FW info: Need to enter password\n' - logger.info(string) - # Reset password for module using CMIS 4.0 - self.cdb.module_enter_password(0) - rpllen, rpl_chkcode, rpl = self.cdb.get_fw_info() - - if self.cdb.cdb_chkcode(rpl) == rpl_chkcode: - # Regiter 9Fh:136 - fwStatus = rpl[0] - ImageARunning = (fwStatus & 0x01) # bit 0 - image A is running - ImageACommitted = ((fwStatus >> 1) & 0x01) # bit 1 - image A is committed - ImageAValid = ((fwStatus >> 2) & 0x01) # bit 2 - image A is valid - ImageBRunning = ((fwStatus >> 4) & 0x01) # bit 4 - image B is running - ImageBCommitted = ((fwStatus >> 5) & 0x01) # bit 5 - image B is committed - ImageBValid = ((fwStatus >> 6) & 0x01) # bit 6 - image B is valid - - if ImageAValid == 0: - # Registers 9Fh:138,139; 140,141 - ImageA = '%d.%d.%d' %(rpl[2], rpl[3], ((rpl[4]<< 8) | rpl[5])) - else: - ImageA = "N/A" - txt += 'Image A Version: %s\n' %ImageA - - if ImageBValid == 0: - # Registers 9Fh:174,175; 176.177 - ImageB = '%d.%d.%d' %(rpl[38], rpl[39], ((rpl[40]<< 8) | rpl[41])) - else: - ImageB = "N/A" - txt += 'Image B Version: %s\n' %ImageB - - if rpllen > 77: - factory_image = '%d.%d.%d' % (rpl[74], rpl[75], ((rpl[76] << 8) | rpl[77])) - txt += 'Factory Image Version: %s\n' %factory_image - - if ImageARunning == 1: - RunningImage = 'A' - elif ImageBRunning == 1: - RunningImage = 'B' - else: - RunningImage = 'N/A' - if ImageACommitted == 1: - CommittedImage = 'A' - elif ImageBCommitted == 1: - CommittedImage = 'B' - else: - CommittedImage = 'N/A' - txt += 'Running Image: %s\n' % (RunningImage) - txt += 'Committed Image: %s\n' % (CommittedImage) - txt += 'Active Firmware: {}\n'.format(self.get_module_active_firmware()) - txt += 'Inactive Firmware: {}\n'.format(self.get_module_inactive_firmware()) - else: - txt += 'Reply payload check code error\n' - return {'status': False, 'info': txt, 'result': None} - return {'status': True, 'info': txt, 'result': (ImageA, ImageARunning, ImageACommitted, ImageAValid, ImageB, ImageBRunning, ImageBCommitted, ImageBValid)} - - def cdb_run_firmware(self, mode = 0x01): - # run module FW (CMD 0109h) - return self.cdb.run_fw_image(mode) - - def cdb_commit_firmware(self): - return self.cdb.commit_fw_image() - - def module_fw_run(self, mode = 0x01): - """ - This command is used to start and run a selected image. - This command transfers control from the currently - running firmware to a selected firmware that is started. It - can be used to switch between firmware versions, or to - perform a restart of the currently running firmware. - mode: - 00h = Traffic affecting Reset to Inactive Image. - 01h = Attempt Hitless Reset to Inactive Image - 02h = Traffic affecting Reset to Running Image. - 03h = Attempt Hitless Reset to Running Image - - This function returns True if firmware run successfully completes. - Otherwise it will return False. - """ - # run module FW (CMD 0109h) - txt = '' - if self.cdb is None: - return False, "CDB NOT supported on this module" - starttime = time.time() - fw_run_status = self.cdb.run_fw_image(mode) - if fw_run_status == 1: - txt += 'Module FW run: Success\n' - # password issue - elif fw_run_status == 70: - string = 'Module FW run: Need to enter password\n' - logger.info(string) - self.cdb.module_enter_password() - fw_run_status = self.cdb.run_fw_image(mode) - txt += 'FW_run_status %d\n' %fw_run_status - else: - # self.cdb.abort_fw_download() - txt += 'Module FW run: Fail\n' - txt += 'FW_run_status %d\n' %fw_run_status - return False, txt - elapsedtime = time.time()-starttime - logger.info('Module FW run time: %.2f s\n' %elapsedtime) - logger.info(txt) - return True, txt - - def module_fw_commit(self): - """ - The host uses this command to commit the running image - so that the module will boot from it on future boots. - - This function returns True if firmware commit successfully completes. - Otherwise it will return False. - """ - txt = '' - if self.cdb is None: - return False, "CDB NOT supported on this module" - # commit module FW (CMD 010Ah) - starttime = time.time() - fw_commit_status= self.cdb.commit_fw_image() - if fw_commit_status == 1: - txt += 'Module FW commit: Success\n' - # password issue - elif fw_commit_status == 70: - string = 'Module FW commit: Need to enter password\n' - logger.info(string) - self.cdb.module_enter_password() - fw_commit_status = self.cdb.commit_fw_image() - txt += 'FW_commit_status %d\n' %fw_commit_status - else: - # self.cdb.abort_fw_download() - txt += 'Module FW commit: Fail\n' - txt += 'FW_commit_status %d\n' %fw_commit_status - return False, txt - elapsedtime = time.time()-starttime - logger.info('Module FW commit time: %.2f s\n' %elapsedtime) - logger.info(txt) - return True, txt - - def cdb_firmware_download_complete(self): - # complete FW download (CMD 0107h) - return self.cdb.validate_fw_image() - - def cdb_start_firmware_download(self, startLPLsize, startdata, imagesize): - return self.cdb.start_fw_download(startLPLsize, bytearray(startdata), imagesize) - - def cdb_lpl_block_write(self, address, data): - return self.cdb.block_write_lpl(address, data) - - def cdb_epl_block_write(self, address, data, autopaging_flag, writelength): - return self.cdb.block_write_epl(address, data, autopaging_flag, writelength) - - def cdb_enter_host_password(self, password): - return self.cdb.module_enter_password(password) - - def module_fw_download(self, startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength, imagepath): - """ - This function performs the download of a firmware image to module eeprom - It starts CDB download by writing the header of start header size - from the designated firmware file to the local payload page 0x9F, with CDB command 0101h. - - Then it repeatedly reads from the given firmware file and write to the payload - space advertised from the first step. We use CDB command 0103h to write to the local payload; - we use CDB command 0104h to write to the extended paylaod. This step repeats until it reaches - end of the firmware file, or the CDB status failed. - - The last step is to complete the firmware upgrade with CDB command 0107h. - - Note that if the download process fails anywhere in the middle, we need to run CDB command 0102h - to abort the upgrade before we restart another upgrade process. - - This function returns True if download successfully completes. Otherwise it will return False where it fails. - """ - txt = '' - if self.cdb is None: - return False, "CDB NOT supported on this module" - - # start fw download (CMD 0101h) - starttime = time.time() - try: - f = open(imagepath, 'rb') - except FileNotFoundError: - txt += 'Image path %s is incorrect.\n' % imagepath - logger.info(txt) - return False, txt - - f.seek(0, 2) - imagesize = f.tell() - f.seek(0, 0) - startdata = f.read(startLPLsize) - logger.info('\nStart FW downloading') - logger.info("startLPLsize is %d" %startLPLsize) - fw_start_status = self.cdb.start_fw_download(startLPLsize, bytearray(startdata), imagesize) - if fw_start_status == 1: - string = 'Start module FW download: Success\n' - logger.info(string) - # password error - elif fw_start_status == 70: - string = 'Start module FW download: Need to enter password\n' - logger.info(string) - self.cdb.module_enter_password() - self.cdb.start_fw_download(startLPLsize, bytearray(startdata), imagesize) - else: - string = 'Start module FW download: Fail\n' - txt += string - self.cdb.abort_fw_download() - txt += 'FW_start_status %d\n' %fw_start_status - logger.info(txt) - return False, txt - elapsedtime = time.time()-starttime - logger.info('Start module FW download time: %.2f s' %elapsedtime) - - # start periodically writing (CMD 0103h or 0104h) - # assert maxblocksize == 2048 or lplonly_flag - if lplonly_flag: - BLOCK_SIZE = 116 - else: - BLOCK_SIZE = maxblocksize - address = 0 - remaining = imagesize - startLPLsize - logger.info("\nTotal size: {} start bytes: {} remaining: {}".format(imagesize, startLPLsize, remaining)) - while remaining > 0: - if remaining < BLOCK_SIZE: - count = remaining - else: - count = BLOCK_SIZE - data = f.read(count) - if lplonly_flag: - fw_download_status = self.cdb.block_write_lpl(address, data) - else: - fw_download_status = self.cdb.block_write_epl(address, data, autopaging_flag, writelength) - if fw_download_status != 1: - self.cdb.abort_fw_download() - txt += 'CDB download failed. CDB Status: %d\n' %fw_download_status - txt += 'FW_download_status %d\n' %fw_download_status - logger.info(txt) - return False, txt - elapsedtime = time.time()-starttime - address += count - remaining -= count - progress = (imagesize - remaining) * 100.0 / imagesize - logger.info('Address: {:#08x}; Count: {}; Remain: {:#08x}; Progress: {:.2f}%; Time: {:.2f}s'.format(address, count, remaining, progress, elapsedtime)) - - elapsedtime = time.time()-starttime - logger.info('Total module FW download time: %.2f s' %elapsedtime) - - time.sleep(2) - # complete FW download (CMD 0107h) - fw_complete_status = self.cdb.validate_fw_image() - if fw_complete_status == 1: - string = 'Module FW download complete: Success' - logger.info(string) - txt += string - else: - txt += 'Module FW download complete: Fail\n' - txt += 'FW_complete_status %d\n' %fw_complete_status - logger.info(txt) - return False, txt - elapsedtime = time.time()-elapsedtime-starttime - string = 'Complete module FW download time: %.2f s\n' %elapsedtime - logger.info(string) - txt += string - return True, txt - - def module_fw_upgrade(self, imagepath): - """ - This function performs firmware upgrade. - 1. show FW version in the beginning - 2. check module advertised FW download capability - 3. configure download - 4. show download progress - 5. configure run downloaded firmware - 6. configure commit downloaded firmware - 7. show FW version in the end - - imagepath specifies where firmware image file is located. - target_firmware is a string that specifies the firmware version to upgrade to - - This function returns True if download successfully completes. - Otherwise it will return False. - """ - result = self.get_module_fw_info() - try: - _, _, _, _, _, _, _, _ = result['result'] - except (ValueError, TypeError): - return result['status'], result['info'] - result = self.get_module_fw_mgmt_feature() - try: - startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength = result['result'] - except (ValueError, TypeError): - return result['status'], result['info'] - download_status, txt = self.module_fw_download(startLPLsize, maxblocksize, lplonly_flag, autopaging_flag, writelength, imagepath) - if not download_status: - return False, txt - switch_status, switch_txt = self.module_fw_switch() - status = download_status and switch_status - txt += switch_txt - return status, txt - - def module_fw_switch(self): - """ - This function switch the active/inactive module firmware in the current module memory - This function returns True if firmware switch successfully completes. - Otherwise it will return False. - If not both images are valid, it will stop firmware switch and return False - """ - txt = '' - result = self.get_module_fw_info() - try: - (ImageA_init, ImageARunning_init, ImageACommitted_init, ImageAValid_init, - ImageB_init, ImageBRunning_init, ImageBCommitted_init, ImageBValid_init) = result['result'] - except (ValueError, TypeError): - return result['status'], result['info'] - if ImageAValid_init == 0 and ImageBValid_init == 0: - self.module_fw_run(mode = 0x01) - time.sleep(60) - self.module_fw_commit() - (ImageA, ImageARunning, ImageACommitted, ImageAValid, - ImageB, ImageBRunning, ImageBCommitted, ImageBValid) = self.get_module_fw_info()['result'] - # detect if image switch happened - txt += 'Before switch Image A: %s; Run: %d Commit: %d, Valid: %d\n' %( - ImageA_init, ImageARunning_init, ImageACommitted_init, ImageAValid_init - ) - txt += 'Before switch Image B: %s; Run: %d Commit: %d, Valid: %d\n' %( - ImageB_init, ImageBRunning_init, ImageBCommitted_init, ImageBValid_init - ) - txt += 'After switch Image A: %s; Run: %d Commit: %d, Valid: %d\n' %(ImageA, ImageARunning, ImageACommitted, ImageAValid) - txt += 'After switch Image B: %s; Run: %d Commit: %d, Valid: %d\n' %(ImageB, ImageBRunning, ImageBCommitted, ImageBValid) - if (ImageARunning_init == 1 and ImageARunning == 1) or (ImageBRunning_init == 1 and ImageBRunning == 1): - txt += 'Switch did not happen.\n' - logger.info(txt) - return False, txt - else: - logger.info(txt) - return True, txt - else: - txt += 'Not both images are valid.' - logger.info(txt) - return False, txt - - def get_transceiver_status(self): - """ - Retrieves transceiver status of this SFP - - Returns: - A dict which contains following keys/values : - ================================================================================ - key = TRANSCEIVER_STATUS|ifname ; Error information for module on port - ; field = value - module_state = 1*255VCHAR ; current module state (ModuleLowPwr, ModulePwrUp, ModuleReady, ModulePwrDn, Fault) - module_fault_cause = 1*255VCHAR ; reason of entering the module fault state - datapath_firmware_fault = BOOLEAN ; datapath (DSP) firmware fault - module_firmware_fault = BOOLEAN ; module firmware fault - module_state_changed = BOOLEAN ; module state changed - datapath_hostlane1 = 1*255VCHAR ; data path state indicator on host lane 1 - datapath_hostlane2 = 1*255VCHAR ; data path state indicator on host lane 2 - datapath_hostlane3 = 1*255VCHAR ; data path state indicator on host lane 3 - datapath_hostlane4 = 1*255VCHAR ; data path state indicator on host lane 4 - datapath_hostlane5 = 1*255VCHAR ; data path state indicator on host lane 5 - datapath_hostlane6 = 1*255VCHAR ; data path state indicator on host lane 6 - datapath_hostlane7 = 1*255VCHAR ; data path state indicator on host lane 7 - datapath_hostlane8 = 1*255VCHAR ; data path state indicator on host lane 8 - txoutput_status = BOOLEAN ; tx output status on media lane - rxoutput_status_hostlane1 = BOOLEAN ; rx output status on host lane 1 - rxoutput_status_hostlane2 = BOOLEAN ; rx output status on host lane 2 - rxoutput_status_hostlane3 = BOOLEAN ; rx output status on host lane 3 - rxoutput_status_hostlane4 = BOOLEAN ; rx output status on host lane 4 - rxoutput_status_hostlane5 = BOOLEAN ; rx output status on host lane 5 - rxoutput_status_hostlane6 = BOOLEAN ; rx output status on host lane 6 - rxoutput_status_hostlane7 = BOOLEAN ; rx output status on host lane 7 - rxoutput_status_hostlane8 = BOOLEAN ; rx output status on host lane 8 - txfault = BOOLEAN ; tx fault flag on media lane - txlos_hostlane1 = BOOLEAN ; tx loss of signal flag on host lane 1 - txlos_hostlane2 = BOOLEAN ; tx loss of signal flag on host lane 2 - txlos_hostlane3 = BOOLEAN ; tx loss of signal flag on host lane 3 - txlos_hostlane4 = BOOLEAN ; tx loss of signal flag on host lane 4 - txlos_hostlane5 = BOOLEAN ; tx loss of signal flag on host lane 5 - txlos_hostlane6 = BOOLEAN ; tx loss of signal flag on host lane 6 - txlos_hostlane7 = BOOLEAN ; tx loss of signal flag on host lane 7 - txlos_hostlane8 = BOOLEAN ; tx loss of signal flag on host lane 8 - txcdrlol_hostlane1 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 1 - txcdrlol_hostlane2 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 2 - txcdrlol_hostlane3 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 3 - txcdrlol_hostlane4 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 4 - txcdrlol_hostlane5 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 5 - txcdrlol_hostlane6 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 6 - txcdrlol_hostlane7 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 7 - txcdrlol_hostlane8 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 8 - rxlos = BOOLEAN ; rx loss of signal flag on media lane - rxcdrlol = BOOLEAN ; rx clock and data recovery loss of lock on media lane - config_state_hostlane1 = 1*255VCHAR ; configuration status for the data path of host line 1 - config_state_hostlane2 = 1*255VCHAR ; configuration status for the data path of host line 2 - config_state_hostlane3 = 1*255VCHAR ; configuration status for the data path of host line 3 - config_state_hostlane4 = 1*255VCHAR ; configuration status for the data path of host line 4 - config_state_hostlane5 = 1*255VCHAR ; configuration status for the data path of host line 5 - config_state_hostlane6 = 1*255VCHAR ; configuration status for the data path of host line 6 - config_state_hostlane7 = 1*255VCHAR ; configuration status for the data path of host line 7 - config_state_hostlane8 = 1*255VCHAR ; configuration status for the data path of host line 8 - dpinit_pending_hostlane1 = BOOLEAN ; data path configuration updated on host lane 1 - dpinit_pending_hostlane2 = BOOLEAN ; data path configuration updated on host lane 2 - dpinit_pending_hostlane3 = BOOLEAN ; data path configuration updated on host lane 3 - dpinit_pending_hostlane4 = BOOLEAN ; data path configuration updated on host lane 4 - dpinit_pending_hostlane5 = BOOLEAN ; data path configuration updated on host lane 5 - dpinit_pending_hostlane6 = BOOLEAN ; data path configuration updated on host lane 6 - dpinit_pending_hostlane7 = BOOLEAN ; data path configuration updated on host lane 7 - dpinit_pending_hostlane8 = BOOLEAN ; data path configuration updated on host lane 8 - temphighalarm_flag = BOOLEAN ; temperature high alarm flag - temphighwarning_flag = BOOLEAN ; temperature high warning flag - templowalarm_flag = BOOLEAN ; temperature low alarm flag - templowwarning_flag = BOOLEAN ; temperature low warning flag - vcchighalarm_flag = BOOLEAN ; vcc high alarm flag - vcchighwarning_flag = BOOLEAN ; vcc high warning flag - vcclowalarm_flag = BOOLEAN ; vcc low alarm flag - vcclowwarning_flag = BOOLEAN ; vcc low warning flag - txpowerhighalarm_flag = BOOLEAN ; tx power high alarm flag - txpowerlowalarm_flag = BOOLEAN ; tx power low alarm flag - txpowerhighwarning_flag = BOOLEAN ; tx power high warning flag - txpowerlowwarning_flag = BOOLEAN ; tx power low alarm flag - rxpowerhighalarm_flag = BOOLEAN ; rx power high alarm flag - rxpowerlowalarm_flag = BOOLEAN ; rx power low alarm flag - rxpowerhighwarning_flag = BOOLEAN ; rx power high warning flag - rxpowerlowwarning_flag = BOOLEAN ; rx power low warning flag - txbiashighalarm_flag = BOOLEAN ; tx bias high alarm flag - txbiaslowalarm_flag = BOOLEAN ; tx bias low alarm flag - txbiashighwarning_flag = BOOLEAN ; tx bias high warning flag - txbiaslowwarning_flag = BOOLEAN ; tx bias low warning flag - lasertemphighalarm_flag = BOOLEAN ; laser temperature high alarm flag - lasertemplowalarm_flag = BOOLEAN ; laser temperature low alarm flag - lasertemphighwarning_flag = BOOLEAN ; laser temperature high warning flag - lasertemplowwarning_flag = BOOLEAN ; laser temperature low warning flag - prefecberhighalarm_flag = BOOLEAN ; prefec ber high alarm flag - prefecberlowalarm_flag = BOOLEAN ; prefec ber low alarm flag - prefecberhighwarning_flag = BOOLEAN ; prefec ber high warning flag - prefecberlowwarning_flag = BOOLEAN ; prefec ber low warning flag - postfecberhighalarm_flag = BOOLEAN ; postfec ber high alarm flag - postfecberlowalarm_flag = BOOLEAN ; postfec ber low alarm flag - postfecberhighwarning_flag = BOOLEAN ; postfec ber high warning flag - postfecberlowwarning_flag = BOOLEAN ; postfec ber low warning flag - ================================================================================ - """ - trans_status = dict() - trans_status['module_state'] = self.get_module_state() - trans_status['module_fault_cause'] = self.get_module_fault_cause() - try: - dp_fw_fault, module_fw_fault, module_state_changed = self.get_module_firmware_fault_state_changed() - trans_status['datapath_firmware_fault'] = dp_fw_fault - trans_status['module_firmware_fault'] = module_fw_fault - trans_status['module_state_changed'] = module_state_changed - except TypeError: - pass - module_flag = self.get_module_level_flag() - trans_status['temphighalarm_flag'] = module_flag['case_temp_flags']['case_temp_high_alarm_flag'] - trans_status['templowalarm_flag'] = module_flag['case_temp_flags']['case_temp_low_alarm_flag'] - trans_status['temphighwarning_flag'] = module_flag['case_temp_flags']['case_temp_high_warn_flag'] - trans_status['templowwarning_flag'] = module_flag['case_temp_flags']['case_temp_low_warn_flag'] - trans_status['vcchighalarm_flag'] = module_flag['voltage_flags']['voltage_high_alarm_flag'] - trans_status['vcclowalarm_flag'] = module_flag['voltage_flags']['voltage_low_alarm_flag'] - trans_status['vcchighwarning_flag'] = module_flag['voltage_flags']['voltage_high_warn_flag'] - trans_status['vcclowwarning_flag'] = module_flag['voltage_flags']['voltage_low_warn_flag'] - try: - aux1_mon_type, aux2_mon_type, aux3_mon_type = self.get_aux_mon_type() - if aux2_mon_type == 0: - trans_status['lasertemphighalarm_flag'] = module_flag['aux2_flags']['aux2_high_alarm_flag'] - trans_status['lasertemplowalarm_flag'] = module_flag['aux2_flags']['aux2_low_alarm_flag'] - trans_status['lasertemphighwarning_flag'] = module_flag['aux2_flags']['aux2_high_warn_flag'] - trans_status['lasertemplowwarning_flag'] = module_flag['aux2_flags']['aux2_low_warn_flag'] - elif aux2_mon_type == 1 and aux3_mon_type == 0: - trans_status['lasertemphighalarm_flag'] = module_flag['aux3_flags']['aux3_high_alarm_flag'] - trans_status['lasertemplowalarm_flag'] = module_flag['aux3_flags']['aux3_low_alarm_flag'] - trans_status['lasertemphighwarning_flag'] = module_flag['aux3_flags']['aux3_high_warn_flag'] - trans_status['lasertemplowwarning_flag'] = module_flag['aux3_flags']['aux3_low_warn_flag'] - except TypeError: - pass - if not self.is_flat_memory(): - dp_state_dict = self.get_datapath_state() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['DP%dState' % lane] = dp_state_dict['DP%dState' % lane] - tx_output_status_dict = self.get_tx_output_status() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['txoutput_status%d' % lane] = tx_output_status_dict['TxOutputStatus%d' % lane] - rx_output_status_dict = self.get_rx_output_status() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['rxoutput_status_hostlane%d' % lane] = rx_output_status_dict['RxOutputStatus%d' % lane] - tx_fault = self.get_tx_fault() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['txfault%d' % lane] = tx_fault[lane - 1] - tx_los = self.get_tx_los() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['txlos_hostlane%d' % lane] = tx_los[lane - 1] - tx_lol = self.get_tx_cdr_lol() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['txcdrlol_hostlane%d' % lane] = tx_lol[lane - 1] - rx_los = self.get_rx_los() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['rxlos%d' % lane] = rx_los[lane - 1] - rx_lol = self.get_rx_cdr_lol() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['rxcdrlol%d' % lane] = rx_lol[lane - 1] - config_status_dict = self.get_config_datapath_hostlane_status() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['config_state_hostlane%d' % lane] = config_status_dict['ConfigStatusLane%d' % lane] - dpinit_pending_dict = self.get_dpinit_pending() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['dpinit_pending_hostlane%d' % lane] = dpinit_pending_dict['DPInitPending%d' % lane] - tx_power_flag_dict = self.get_tx_power_flag() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['txpowerhighalarm_flag%d' % lane] = tx_power_flag_dict['tx_power_high_alarm']['TxPowerHighAlarmFlag%d' % lane] - trans_status['txpowerlowalarm_flag%d' % lane] = tx_power_flag_dict['tx_power_low_alarm']['TxPowerLowAlarmFlag%d' % lane] - trans_status['txpowerhighwarning_flag%d' % lane] = tx_power_flag_dict['tx_power_high_warn']['TxPowerHighWarnFlag%d' % lane] - trans_status['txpowerlowwarning_flag%d' % lane] = tx_power_flag_dict['tx_power_low_warn']['TxPowerLowWarnFlag%d' % lane] - rx_power_flag_dict = self.get_rx_power_flag() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['rxpowerhighalarm_flag%d' % lane] = rx_power_flag_dict['rx_power_high_alarm']['RxPowerHighAlarmFlag%d' % lane] - trans_status['rxpowerlowalarm_flag%d' % lane] = rx_power_flag_dict['rx_power_low_alarm']['RxPowerLowAlarmFlag%d' % lane] - trans_status['rxpowerhighwarning_flag%d' % lane] = rx_power_flag_dict['rx_power_high_warn']['RxPowerHighWarnFlag%d' % lane] - trans_status['rxpowerlowwarning_flag%d' % lane] = rx_power_flag_dict['rx_power_low_warn']['RxPowerLowWarnFlag%d' % lane] - tx_bias_flag_dict = self.get_tx_bias_flag() - for lane in range(1, self.NUM_CHANNELS+1): - trans_status['txbiashighalarm_flag%d' % lane] = tx_bias_flag_dict['tx_bias_high_alarm']['TxBiasHighAlarmFlag%d' % lane] - trans_status['txbiaslowalarm_flag%d' % lane] = tx_bias_flag_dict['tx_bias_low_alarm']['TxBiasLowAlarmFlag%d' % lane] - trans_status['txbiashighwarning_flag%d' % lane] = tx_bias_flag_dict['tx_bias_high_warn']['TxBiasHighWarnFlag%d' % lane] - trans_status['txbiaslowwarning_flag%d' % lane] = tx_bias_flag_dict['tx_bias_low_warn']['TxBiasLowWarnFlag%d' % lane] - self.vdm_dict = self.get_vdm() - try: - trans_status['prefecberhighalarm_flag'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][5] - trans_status['prefecberlowalarm_flag'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][6] - trans_status['prefecberhighwarning_flag'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][7] - trans_status['prefecberlowwarning_flag'] = self.vdm_dict['Pre-FEC BER Average Media Input'][1][8] - trans_status['postfecberhighalarm_flag'] = self.vdm_dict['Errored Frames Average Media Input'][1][5] - trans_status['postfecberlowalarm_flag'] = self.vdm_dict['Errored Frames Average Media Input'][1][6] - trans_status['postfecberhighwarning_flag'] = self.vdm_dict['Errored Frames Average Media Input'][1][7] - trans_status['postfecberlowwarning_flag'] = self.vdm_dict['Errored Frames Average Media Input'][1][8] - except (KeyError, TypeError): - pass - return trans_status - - def get_transceiver_loopback(self): - """ - Retrieves loopback mode for this xcvr - - Returns: - A dict containing the following keys/values : - ======================================================================== - key = TRANSCEIVER_PM|ifname ; information of loopback on port - ; field = value - media_output_loopback = BOOLEAN ; media side output loopback enable - media_input_loopback = BOOLEAN ; media side input loopback enable - host_output_loopback_lane1 = BOOLEAN ; host side output loopback enable lane1 - host_output_loopback_lane2 = BOOLEAN ; host side output loopback enable lane2 - host_output_loopback_lane3 = BOOLEAN ; host side output loopback enable lane3 - host_output_loopback_lane4 = BOOLEAN ; host side output loopback enable lane4 - host_output_loopback_lane5 = BOOLEAN ; host side output loopback enable lane5 - host_output_loopback_lane6 = BOOLEAN ; host side output loopback enable lane6 - host_output_loopback_lane7 = BOOLEAN ; host side output loopback enable lane7 - host_output_loopback_lane8 = BOOLEAN ; host side output loopback enable lane8 - host_input_loopback_lane1 = BOOLEAN ; host side input loopback enable lane1 - host_input_loopback_lane2 = BOOLEAN ; host side input loopback enable lane2 - host_input_loopback_lane3 = BOOLEAN ; host side input loopback enable lane3 - host_input_loopback_lane4 = BOOLEAN ; host side input loopback enable lane4 - host_input_loopback_lane5 = BOOLEAN ; host side input loopback enable lane5 - host_input_loopback_lane6 = BOOLEAN ; host side input loopback enable lane6 - host_input_loopback_lane7 = BOOLEAN ; host side input loopback enable lane7 - host_input_loopback_lane8 = BOOLEAN ; host side input loopback enable lane8 - ======================================================================== - """ - trans_loopback = dict() - loopback_capability = self.get_loopback_capability() - if loopback_capability is None: - trans_loopback['simultaneous_host_media_loopback_supported'] = 'N/A' - trans_loopback['per_lane_media_loopback_supported'] = 'N/A' - trans_loopback['per_lane_host_loopback_supported'] = 'N/A' - trans_loopback['host_side_input_loopback_supported'] = 'N/A' - trans_loopback['host_side_output_loopback_supported'] = 'N/A' - trans_loopback['media_side_input_loopback_supported'] = 'N/A' - trans_loopback['media_side_output_loopback_supported'] = 'N/A' - trans_loopback['media_output_loopback'] = 'N/A' - trans_loopback['media_input_loopback'] = 'N/A' - for lane in range(1, self.NUM_CHANNELS+1): - trans_loopback['host_output_loopback_lane%d' % lane] = 'N/A' - trans_loopback['host_input_loopback_lane%d' % lane] = 'N/A' - return trans_loopback - else: - trans_loopback['simultaneous_host_media_loopback_supported'] = loopback_capability['simultaneous_host_media_loopback_supported'] - trans_loopback['per_lane_media_loopback_supported'] = loopback_capability['per_lane_media_loopback_supported'] - trans_loopback['per_lane_host_loopback_supported'] = loopback_capability['per_lane_host_loopback_supported'] - trans_loopback['host_side_input_loopback_supported'] = loopback_capability['host_side_input_loopback_supported'] - trans_loopback['host_side_output_loopback_supported'] = loopback_capability['host_side_output_loopback_supported'] - trans_loopback['media_side_input_loopback_supported'] = loopback_capability['media_side_input_loopback_supported'] - trans_loopback['media_side_output_loopback_supported'] = loopback_capability['media_side_output_loopback_supported'] - if loopback_capability['media_side_output_loopback_supported']: - trans_loopback['media_output_loopback'] = self.get_media_output_loopback() - else: - trans_loopback['media_output_loopback'] = 'N/A' - if loopback_capability['media_side_input_loopback_supported']: - trans_loopback['media_input_loopback'] = self.get_media_input_loopback() - else: - trans_loopback['media_input_loopback'] = 'N/A' - if loopback_capability['host_side_output_loopback_supported']: - host_output_loopback_status = self.get_host_output_loopback() - for lane in range(1, self.NUM_CHANNELS+1): - trans_loopback['host_output_loopback_lane%d' % lane] = host_output_loopback_status[lane - 1] - else: - for lane in range(1, self.NUM_CHANNELS+1): - trans_loopback['host_output_loopback_lane%d' % lane] = 'N/A' - if loopback_capability['host_side_input_loopback_supported']: - host_input_loopback_status = self.get_host_input_loopback() - for lane in range(1, self.NUM_CHANNELS+1): - trans_loopback['host_input_loopback_lane%d' % lane] = host_input_loopback_status[lane - 1] - else: - for lane in range(1, self.NUM_CHANNELS+1): - trans_loopback['host_input_loopback_lane%d' % lane] = 'N/A' - return trans_loopback - - def set_datapath_init(self, channel): - """ - Put the CMIS datapath into the initialized state - - Args: - channel: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) - data = self.xcvr_eeprom.read(consts.DATAPATH_DEINIT_FIELD) - for lane in range(self.NUM_CHANNELS): - if ((1 << lane) & channel) == 0: - continue - if cmis_major >= 4: # CMIS v4 onwards - data &= ~(1 << lane) - else: # CMIS v3 - data |= (1 << lane) - self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) - - def set_datapath_deinit(self, channel): - """ - Put the CMIS datapath into the de-initialized state - - Args: - channel: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - - Returns: - Boolean, true if success otherwise false - """ - cmis_major = self.xcvr_eeprom.read(consts.CMIS_MAJOR_REVISION) - data = self.xcvr_eeprom.read(consts.DATAPATH_DEINIT_FIELD) - for lane in range(self.NUM_CHANNELS): - if ((1 << lane) & channel) == 0: - continue - if cmis_major >= 4: # CMIS v4 onwards - data |= (1 << lane) - else: # CMIS v3 - data &= ~(1 << lane) - self.xcvr_eeprom.write(consts.DATAPATH_DEINIT_FIELD, data) - - def get_application_advertisement(self): - """ - Get the application advertisement of the CMIS transceiver - - Returns: - Dictionary, the application advertisement - """ - map = { - Sff8024.MODULE_MEDIA_TYPE[1]: consts.MODULE_MEDIA_INTERFACE_850NM, - Sff8024.MODULE_MEDIA_TYPE[2]: consts.MODULE_MEDIA_INTERFACE_SM, - Sff8024.MODULE_MEDIA_TYPE[3]: consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, - Sff8024.MODULE_MEDIA_TYPE[4]: consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, - Sff8024.MODULE_MEDIA_TYPE[5]: consts.MODULE_MEDIA_INTERFACE_BASE_T - } - - ret = {} - # Read the application advertisment in lower memory - dic = self.xcvr_eeprom.read(consts.APPLS_ADVT_FIELD) - - if not self.is_flat_memory(): - # Read the application advertisement in page01 - try: - dic.update(self.xcvr_eeprom.read(consts.APPLS_ADVT_FIELD_PAGE01)) - except (TypeError, AttributeError) as e: - logger.error('Failed to read APPLS_ADVT_FIELD_PAGE01: ' + str(e)) - return ret - - for app in range(1, 16): - buf = {} - - key = "{}_{}".format(consts.HOST_ELECTRICAL_INTERFACE, app) - val = dic.get(key) - if val in [None, 'Unknown', 'Undefined']: - break - buf['host_electrical_interface_id'] = val - - prefix = map.get(self.xcvr_eeprom.read(consts.MEDIA_TYPE_FIELD)) - if prefix is None: - break - key = "{}_{}".format(prefix, app) - val = dic.get(key) - if val in [None, 'Unknown', 'Undefined']: - break - buf['module_media_interface_id'] = val - - key = "{}_{}".format(consts.MEDIA_LANE_COUNT, app) - val = dic.get(key) - if val is None: - break - buf['media_lane_count'] = val - - key = "{}_{}".format(consts.HOST_LANE_COUNT, app) - val = dic.get(key) - if val is None: - break - buf['host_lane_count'] = val - - key = "{}_{}".format(consts.HOST_LANE_ASSIGNMENT_OPTION, app) - val = dic.get(key) - if val is None: - break - buf['host_lane_assignment_options'] = val - - key = "{}_{}".format(consts.MEDIA_LANE_ASSIGNMENT_OPTION, app) - val = dic.get(key) - if val is not None: - buf['media_lane_assignment_options'] = val - - ret[app] = buf - return ret - - def get_application(self, lane): - """ - Get the CMIS selected application code of a host lane - - Args: - lane: - Integer, the zero-based lane id on the host side - - Returns: - Integer, the transceiver-specific application code - """ - appl = 0 - if lane in range(self.NUM_CHANNELS) and not self.is_flat_memory(): - name = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) - appl = self.xcvr_eeprom.read(name) >> 4 - - return (appl & 0xf) - - def set_application(self, channel, appl_code): - """ - Update the selected application code to the specified lanes on the host side - - Args: - channel: - Integer, a bitmask of the lanes on the host side - e.g. 0x5 for lane 0 and lane 2. - appl_code: - Integer, the desired application code - - Returns: - Boolean, true if success otherwise false - """ - # Update the application selection - lane_first = -1 - for lane in range(self.NUM_CHANNELS): - if ((1 << lane) & channel) == 0: - continue - if lane_first < 0: - lane_first = lane - addr = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) - data = (appl_code << 4) | (lane_first << 1) - self.xcvr_eeprom.write(addr, data) - - # Apply DataPathInit - return self.xcvr_eeprom.write("%s_%d" % (consts.STAGED_CTRL_APPLY_DPINIT_FIELD, 0), channel) - - def get_error_description(self): - dp_state = self.get_datapath_state() - conf_state = self.get_config_datapath_hostlane_status() - for lane in range(self.NUM_CHANNELS): - name = "{}_{}_{}".format(consts.STAGED_CTRL_APSEL_FIELD, 0, lane + 1) - appl = self.xcvr_eeprom.read(name) - if (appl is None) or ((appl >> 4) == 0): - continue - - name = "DP{}State".format(lane + 1) - if dp_state[name] != CmisCodes.DATAPATH_STATE[4]: - return dp_state[name] - - name = "ConfigStatusLane{}".format(lane + 1) - if conf_state[name] != CmisCodes.CONFIG_STATUS[1]: - return conf_state[name] - - state = self.get_module_state() - if state != CmisCodes.MODULE_STATE[3]: - return state - - return None - - # TODO: other XcvrApi methods diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py b/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py deleted file mode 100644 index 019d7913f..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/cmisCDB.py +++ /dev/null @@ -1,481 +0,0 @@ -""" - cmisCDB.py - - Implementation of APIs related to CDB commands -""" -import logging -from ...fields import consts -from ..xcvr_api import XcvrApi -import struct -import time - -logger = logging.getLogger(__name__) -logger.addHandler(logging.NullHandler()) - -LPLPAGE = 0x9f -CDB_RPL_OFFSET = 136 -CDB_WRITE_MSG_START = 130 -PAGE_LENGTH = 128 -INIT_OFFSET = 128 -CMDLEN = 2 -MAX_WAIT = 600 - - -class CmisCdbApi(XcvrApi): - def __init__(self, xcvr_eeprom): - super(CmisCdbApi, self).__init__(xcvr_eeprom) - self.cdb_instance_supported = self.xcvr_eeprom.read(consts.CDB_SUPPORT) - self.failed_status_dict = self.xcvr_eeprom.mem_map.codes.CDB_FAIL_STATUS - #assert self.cdb_instance_supported != 0 - - def cdb1_chkflags(self): - ''' - This function detects if there is datapath or module firmware fault. - If there is no firmware fault, it checks if CDB command completes. - It retruns True if the CDB command is incomplete and returns False if complete - - Bit 7: L-Cdb2CommandComplete Latched Flag to indicate completion of the CDB command - for CDB block 2. Support is advertised in field 01h:163.7-6 - - Bit 6: L-Cdb1CommandComplete Latched Flag to indicate completion of the CDB command - for CDB block 1. Support is advertised in field 01h:163.7-6 - - Bit 5-3: - Reserved - - Bit 2: L-DataPathFirmwareFault Latched Flag to indicate that subordinated firmware in an - auxiliary device for processing transmitted or received - signals (e.g. a DSP) has failed. - - Bit 1: L-ModuleFirmwareFault Latched Flag to indicate that self-supervision of the main - module firmware has detected a failure in the main module - firmware itself. There are several possible causes of the - error such as program memory becoming corrupted and - incomplete firmware loading. - - Bit 0: L-ModuleStateChanged Latched Flag to indicate a Module State Change - ''' - status = self.xcvr_eeprom.read(consts.MODULE_FIRMWARE_FAULT_INFO) - datapath_firmware_fault = bool((status >> 2) & 0x1) - module_firmware_fault = bool((status >> 1) & 0x1) - cdb1_command_complete = bool((status >> 6) & 0x1) - assert not datapath_firmware_fault - assert not module_firmware_fault - if cdb1_command_complete: - return False - else: - return True - - def cdb_chkcode(self, cmd): - ''' - This function calculates and returns the checksum of a CDB command - ''' - checksum = 0 - for byte in cmd: - checksum += byte - return 0xff - (checksum & 0xff) - - def cdb1_chkstatus(self): - ''' - This function checks the CDB status. - The format of returned values is busy flag, failed flag and cause - - CDB command status - Bit 7: CdbIsBusy - Bit 6: CdbHasFailed - Bit 5-0: CdBCommandResult - Coarse Status CdbIsBusy CdbHasFailed - IN PROGRESS 1 X (dont care) - SUCCESS 0 0 - FAILED 0 1 - - IN PROGRESS - 00h=Reserved - 01h=Command is captured but not processed - 02h=Command checking is in progress - 03h=Previous CMD was ABORTED by CMD Abort - 04h-1Fh=Reserved - 20h-2Fh=Reserved - 30h-3Fh=Custom - - SUCCESS - 00h=Reserved - 01h=Command completed successfully - 02h=Reserved - 03h=Previous CMD was ABORTED by CMD Abort - 04h-1Fh=Reserved - 20h-2Fh=Reserved - 30h-3Fh=Custom - - FAILED - 00h=Reserved - 01h=CMDCode unknown - 02h=Parameter range error or parameter not supported - 03h=Previous CMD was not ABORTED by CMD Abort - 04h=Command checking time out - 05h=CdbCheckCode Error - 06h=Password related error (command specific meaning) - 07h=Command not compatible with operating status - 08h-0Fh=Reserved for STS command checking error - 10h-1Fh=Reserved - 20h-2Fh=For individual STS command or task error - 30h-3Fh=Custom - ''' - status = self.xcvr_eeprom.read(consts.CDB1_STATUS) - is_busy = bool(((0x80 if status is None else status) >> 7) & 0x1) - cnt = 0 - while is_busy and cnt < MAX_WAIT: - time.sleep(0.1) - status = self.xcvr_eeprom.read(consts.CDB1_STATUS) - is_busy = bool(((0x80 if status is None else status) >> 7) & 0x1) - cnt += 1 - return status - - def write_cdb(self, cmd): - ''' - This function writes a CDB command to page 0x9f - ''' - self.xcvr_eeprom.write_raw(LPLPAGE*PAGE_LENGTH+CDB_WRITE_MSG_START, len(cmd)-CMDLEN, cmd[CMDLEN:]) - self.xcvr_eeprom.write_raw(LPLPAGE*PAGE_LENGTH+INIT_OFFSET, CMDLEN, cmd[:CMDLEN]) - - def read_cdb(self): - ''' - This function reads the reply of a CDB command from page 0x9f. - It returns the reply message of a CDB command. - rpllen is the length (number of bytes) of rpl - rpl_chkcode is the check code of rpl and can be calculated by cdb_chkcode() - rpl is the reply message. - ''' - rpllen = self.xcvr_eeprom.read(consts.CDB_RPL_LENGTH) - rpl_chkcode = self.xcvr_eeprom.read(consts.CDB_RPL_CHKCODE) - rpl = self.xcvr_eeprom.read_raw(LPLPAGE*PAGE_LENGTH+CDB_RPL_OFFSET, rpllen) - return rpllen, rpl_chkcode, rpl - - # Query status - def query_cdb_status(self): - ''' - This QUERY Status command may be used to retrieve the password acceptance - status and to perform a test of the CDB interface. - It returns the reply message of this CDB command 0000h. - ''' - cmd = bytearray(b'\x00\x00\x00\x00\x02\x00\x00\x00\x00\x10') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Query CDB status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Query CDB status: Fail- ' + status_txt - else: - txt = 'Query CDB status: Success' - logger.info(txt) - return self.read_cdb() - - # Enter password - def module_enter_password(self, psw = 0x00001011): - ''' - The Enter Password command allows the host to enter a host password - The default host password is 00001011h. CDB command 0001h puts the - password in Page 9Fh, Byte 136-139. - It returns the status of CDB command 0001h - ''' - psw = struct.pack('>L', psw) - cmd = bytearray(b'\x00\x01\x00\x00\x04\x00\x00\x00') + psw - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Enter password status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Enter password status: Fail- ' + status_txt - else: - txt = 'Enter password status: Success' - logger.info(txt) - return status - - def get_module_feature(self): - ''' - This command is used to query which CDB commands are supported. - It returns the reply message of this CDB command 0040h. - ''' - cmd = bytearray(b'\x00\x40\x00\x00\x00\x00\x00\x00') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Get module feature status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Get module feature status: Fail- ' + status_txt - else: - txt = 'Get module feature status: Success' - logger.info(txt) - return self.read_cdb() - - # Firmware Update Features Supported - def get_fw_management_features(self): - ''' - This command is used to query supported firmware update features - It returns the reply message of this CDB command 0041h. - ''' - cmd = bytearray(b'\x00\x41\x00\x00\x00\x00\x00\x00') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Get firmware management feature status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Get firmware management feature status: Fail- ' + status_txt - else: - txt = 'Get firmware management feature status: Success' - logger.info(txt) - return self.read_cdb() - - # Get FW info - def get_fw_info(self): - ''' - This command returns the firmware versions and firmware default running - images that reside in the module - It returns the reply message of this CDB command 0100h. - ''' - cmd = bytearray(b'\x01\x00\x00\x00\x00\x00\x00\x00') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Get firmware info status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Get firmware info status: Fail- ' + status_txt - else: - txt = 'Get firmware info status: Success' - logger.info(txt) - return self.read_cdb() - - # Start FW download - def start_fw_download(self, startLPLsize, header, imagesize): - ''' - This command starts the firmware download - It returns the status of CDB command 0101h - ''' - # pwd_status = self.module_enter_password() - # logger.info('Module password enter status is %d' %pwd_status) - logger.info("Image size is {}".format(imagesize)) - cmd = bytearray(b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') - cmd[132-INIT_OFFSET] = startLPLsize + 8 - cmd[136-INIT_OFFSET] = (imagesize >> 24) & 0xff - cmd[137-INIT_OFFSET] = (imagesize >> 16) & 0xff - cmd[138-INIT_OFFSET] = (imagesize >> 8) & 0xff - cmd[139-INIT_OFFSET] = (imagesize >> 0) & 0xff - cmd += header - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - time.sleep(2) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Start firmware download status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Start firmware download status: Fail- ' + status_txt - else: - txt = 'Start firmware download status: Success' - logger.info(txt) - return status - - # Abort FW download - def abort_fw_download(self): - ''' - This command aborts the firmware download - It returns the status of CDB command 0102h - ''' - # pwd_status = self.module_enter_password() - # logger.info('Module password enter status is %d' %pwd_status) - cmd = bytearray(b'\x01\x02\x00\x00\x00\x00\x00\x00') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Abort firmware download status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Abort firmware download status: Fail- ' + status_txt - else: - txt = 'Abort firmware download status: Success' - logger.info(txt) - return status - - # Download FW with LPL - def block_write_lpl(self, addr, data): - ''' - This command writes one block of the firmware image into the LPL - It returns the status of CDB command 0103h - ''' - # lpl_len includes 136-139, four bytes, data is 116-byte long. - lpl_len = len(data) + 4 - cmd = bytearray(b'\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') - cmd[132-INIT_OFFSET] = lpl_len & 0xff - cmd[136-INIT_OFFSET] = (addr >> 24) & 0xff - cmd[137-INIT_OFFSET] = (addr >> 16) & 0xff - cmd[138-INIT_OFFSET] = (addr >> 8) & 0xff - cmd[139-INIT_OFFSET] = (addr >> 0) & 0xff - # pad data to 116 bytes just in case, make sure to fill all 0x9f page - paddedPayload = data.ljust(116, b'\x00') - cmd += paddedPayload - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'LPL firmware download status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'LPL firmware download status: Fail- ' + status_txt - else: - txt = 'LPL firmware download status: Success' - logger.info(txt) - return status - - # Download FW with EPL - def block_write_epl(self, addr, data, autopaging_flag, writelength): - ''' - This command writes one block of the firmware image into the EPL - It returns the status of CDB command 0104h - ''' - epl_len = len(data) - subtime = time.time() - if not autopaging_flag: - pages = epl_len // PAGE_LENGTH - if (epl_len % PAGE_LENGTH) != 0: - pages += 1 - # write to page 0xA0 - 0xAF (max of 16 pages) - for pageoffset in range(pages): - next_page = 0xa0 + pageoffset - if PAGE_LENGTH*(pageoffset + 1) <= epl_len: - datachunk = data[PAGE_LENGTH*pageoffset : PAGE_LENGTH*(pageoffset + 1)] - self.xcvr_eeprom.write_raw(next_page*PAGE_LENGTH+INIT_OFFSET, PAGE_LENGTH, datachunk) - else: - datachunk = data[INIT_OFFSET*pageoffset : ] - self.xcvr_eeprom.write_raw(next_page*PAGE_LENGTH+INIT_OFFSET, len(datachunk), datachunk) - else: - sections = epl_len // writelength - if (epl_len % writelength) != 0: - sections += 1 - # write to page 0xA0 - 0xAF (max of 16 pages), with length of writelength per piece - for offset in range(0, epl_len, writelength): - if offset + writelength <= epl_len: - datachunk = data[offset : offset + writelength] - self.xcvr_eeprom.write_raw(0xA0*PAGE_LENGTH+offset+INIT_OFFSET, writelength, datachunk) - else: - datachunk = data[offset : ] - self.xcvr_eeprom.write_raw(0xA0*PAGE_LENGTH+offset+INIT_OFFSET, len(datachunk), datachunk) - subtimeint = time.time()-subtime - logger.info('%dB write time: %.2fs' %(epl_len, subtimeint)) - cmd = bytearray(b'\x01\x04\x08\x00\x04\x00\x00\x00') - addr_byte = struct.pack('>L',addr) - cmd += addr_byte - cmd[130-INIT_OFFSET] = (epl_len >> 8) & 0xff - cmd[131-INIT_OFFSET] = epl_len & 0xff - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'EPL firmware download status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'EPL firmware download status: Fail- ' + status_txt - else: - txt = 'EPL firmware download status: Success' - logger.info(txt) - return status - - # FW download complete - def validate_fw_image(self): - ''' - When this command is issued, the module shall validate the complete - image and then return success or failure - It returns the status of CDB command 0107h - ''' - cmd = bytearray(b'\x01\x07\x00\x00\x00\x00\x00\x00') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Firmware download complete status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Firmware download complete status: Fail- ' + status_txt - else: - txt = 'Firmware download complete status: Success' - logger.info(txt) - return status - - # Run FW image - # mode: - # 00h = Traffic affecting Reset to Inactive Image. - # 01h = Attempt Hitless Reset to Inactive Image - # 02h = Traffic affecting Reset to Running Image. - # 03h = Attempt Hitless Reset to Running Image - def run_fw_image(self, mode = 0x01): - ''' - The host uses this command to run a selected image from module internal firmware banks - It returns the status of CDB command 0109h - ''' - cmd = bytearray(b'\x01\x09\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00') - cmd[137-INIT_OFFSET] = mode - cmd[138-INIT_OFFSET] = 2 # Delay to Reset 512 ms - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - delay = int.from_bytes(cmd[138-INIT_OFFSET:138+2-INIT_OFFSET], byteorder='big') + 50 # Add few ms on setting time. - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Run firmware status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Run firmware status: Fail- ' + status_txt - else: - txt = 'Run firmware status: Success' - logger.info(txt) - time.sleep(delay/1000) # Wait "delay time" to avoid other cmd sent before "run_fw_image" start. - return status - - # Commit FW image - def commit_fw_image(self): - ''' - A Commit is the process where the running image is set to be the image to be used on exit from module - reset. In other words, a committed image is the image that will run and is expected to be a 'good' firmware - version to run upon any resets (including watch dog). - - This command is used to switch the committed image after the firmware update process, when the new - firmware is running and when the host has determined that the new firmware is working properly. The module - shall only execute a Commit Image command on the image that it is currently running. If a non-running image - is allowed to be committed, it is possible that a bad version may be committed and attempted to run after the - next module reset. - - It returns the status of CDB command 010Ah - ''' - cmd = bytearray(b'\x01\x0A\x00\x00\x00\x00\x00\x00') - cmd[133-INIT_OFFSET] = self.cdb_chkcode(cmd) - self.write_cdb(cmd) - status = self.cdb1_chkstatus() - if (status != 0x1): - if status > 127: - txt = 'Commit firmware status: Busy' - else: - status_txt = self.failed_status_dict.get(status & 0x3f, "Unknown") - txt = 'Commit firmware status: Fail- ' + status_txt - else: - txt = 'Commit firmware status: Success' - logger.info(txt) - return status diff --git a/sonic_platform_base/sonic_xcvr/api/public/cmisVDM.py b/sonic_platform_base/sonic_xcvr/api/public/cmisVDM.py deleted file mode 100644 index a76c7a39e..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/cmisVDM.py +++ /dev/null @@ -1,185 +0,0 @@ -""" - cmisCDB.py - - Implementation of APIs related to VDMs -""" - -from ...fields import consts -from ..xcvr_api import XcvrApi -import struct -import time - -PAGE_SIZE = 128 -PAGE_OFFSET = 128 -THRSH_SPACING = 8 -VDM_SIZE = 2 -VDM_FLAG_PAGE = 0x2c -VDM_FREEZE = 128 -VDM_UNFREEZE = 0 - -class CmisVdmApi(XcvrApi): - def __init__(self, xcvr_eeprom): - super(CmisVdmApi, self).__init__(xcvr_eeprom) - - def get_F16(self, value): - ''' - This function converts raw data to "F16" format defined in cmis. - ''' - scale_exponent = (value >> 11) & 0x1f - mantissa = value & 0x7ff - result = mantissa*10**(scale_exponent-24) - return result - - def get_vdm_page(self, page, VDM_flag_page): - ''' - This function returns VDM items from a specific VDM page. - Output format is a dictionary. Key is observable type; value is a dictionary. - In the inside dictionary, key is lane; value is a list - [ - vdm_value, - vdm_thrsh_high_alarm, - vdm_thrsh_low_alarm, - vdm_thrsh_high_warn, - vdm_thrsh_low_warn, - vdm_high_alarm_flag, - vdm_low_alarm_flag, - vdm_high_warn_flag, - vdm_low_warn_flag - ] - ''' - if page not in [0x20, 0x21, 0x22, 0x23]: - raise ValueError('Page not in VDM Descriptor range!') - vdm_descriptor = self.xcvr_eeprom.read_raw(page * PAGE_SIZE + PAGE_OFFSET, PAGE_SIZE) - if not vdm_descriptor: - return {} - - # Odd Adress VDM observable type ID, real-time monitored value in Page + 4 - vdm_typeID = vdm_descriptor[1::2] - # Even Address - # Bit 7-4: Threshold set ID in Page + 8, in group of 8 bytes, 16 sets/page - # Bit 3-0: n. Monitored lane n+1 - vdm_lane = [(elem & 0xf) for elem in vdm_descriptor[0::2]] - VDM_thresholdID = [(elem>>4) for elem in vdm_descriptor[0::2]] - vdm_valuePage = page + 4 - vdm_thrshPage = page + 8 - vdm_Page_data = {} - VDM_TYPE_DICT = self.xcvr_eeprom.mem_map.codes.VDM_TYPE - for index, typeID in enumerate(vdm_typeID): - if typeID not in VDM_TYPE_DICT: - continue - else: - vdm_info_dict = VDM_TYPE_DICT[typeID] - thrshID = VDM_thresholdID[index] - vdm_type = vdm_info_dict[0] - vdm_format = vdm_info_dict[1] - scale = vdm_info_dict[2] - - vdm_value_offset = vdm_valuePage * PAGE_SIZE + PAGE_OFFSET + VDM_SIZE * index - vdm_high_alarm_offset = vdm_thrshPage * PAGE_SIZE + PAGE_OFFSET + THRSH_SPACING * thrshID - vdm_low_alarm_offset = vdm_high_alarm_offset + 2 - vdm_high_warn_offset = vdm_high_alarm_offset + 4 - vdm_low_warn_offset = vdm_high_alarm_offset + 6 - - vdm_value_raw = self.xcvr_eeprom.read_raw(vdm_value_offset, VDM_SIZE, True) - vdm_thrsh_high_alarm_raw = self.xcvr_eeprom.read_raw(vdm_high_alarm_offset, VDM_SIZE, True) - vdm_thrsh_low_alarm_raw = self.xcvr_eeprom.read_raw(vdm_low_alarm_offset, VDM_SIZE, True) - vdm_thrsh_high_warn_raw = self.xcvr_eeprom.read_raw(vdm_high_warn_offset, VDM_SIZE, True) - vdm_thrsh_low_warn_raw = self.xcvr_eeprom.read_raw(vdm_low_warn_offset, VDM_SIZE, True) - if not vdm_value_raw or not vdm_thrsh_high_alarm_raw or not vdm_thrsh_low_alarm_raw \ - or not vdm_high_warn_offset or not vdm_thrsh_low_warn_raw: - return {} - if vdm_format == 'S16': - vdm_value = struct.unpack('>h',vdm_value_raw)[0] * scale - vdm_thrsh_high_alarm = struct.unpack('>h', vdm_thrsh_high_alarm_raw)[0] * scale - vdm_thrsh_low_alarm = struct.unpack('>h', vdm_thrsh_low_alarm_raw)[0] * scale - vdm_thrsh_high_warn = struct.unpack('>h', vdm_thrsh_high_warn_raw)[0] * scale - vdm_thrsh_low_warn = struct.unpack('>h', vdm_thrsh_low_warn_raw)[0] * scale - elif vdm_format == 'U16': - vdm_value = struct.unpack('>H',vdm_value_raw)[0] * scale - vdm_thrsh_high_alarm = struct.unpack('>H', vdm_thrsh_high_alarm_raw)[0] * scale - vdm_thrsh_low_alarm = struct.unpack('>H', vdm_thrsh_low_alarm_raw)[0] * scale - vdm_thrsh_high_warn = struct.unpack('>H', vdm_thrsh_high_warn_raw)[0] * scale - vdm_thrsh_low_warn = struct.unpack('>H', vdm_thrsh_low_warn_raw)[0] * scale - elif vdm_format == 'F16': - vdm_value_int = struct.unpack('>H',vdm_value_raw)[0] - vdm_value = self.get_F16(vdm_value_int) - vdm_thrsh_high_alarm_int = struct.unpack('>H', vdm_thrsh_high_alarm_raw)[0] - vdm_thrsh_low_alarm_int = struct.unpack('>H', vdm_thrsh_low_alarm_raw)[0] - vdm_thrsh_high_warn_int = struct.unpack('>H', vdm_thrsh_high_warn_raw)[0] - vdm_thrsh_low_warn_int = struct.unpack('>H', vdm_thrsh_low_warn_raw)[0] - vdm_thrsh_high_alarm = self.get_F16(vdm_thrsh_high_alarm_int) - vdm_thrsh_low_alarm = self.get_F16(vdm_thrsh_low_alarm_int) - vdm_thrsh_high_warn = self.get_F16(vdm_thrsh_high_warn_int) - vdm_thrsh_low_warn = self.get_F16(vdm_thrsh_low_warn_int) - else: - continue - - vdm_flag_offset = 32 * (page - 0x20) + index//2 - bit_offset = 4*(index%2) - vdm_high_alarm_flag = bool((VDM_flag_page[vdm_flag_offset] >> (bit_offset)) & 0x1) - vdm_low_alarm_flag = bool((VDM_flag_page[vdm_flag_offset] >> (bit_offset+1)) & 0x1) - vdm_high_warn_flag = bool((VDM_flag_page[vdm_flag_offset] >> (bit_offset+2)) & 0x1) - vdm_low_warn_flag = bool((VDM_flag_page[vdm_flag_offset] >> (bit_offset+3)) & 0x1) - - if vdm_type not in vdm_Page_data: - vdm_Page_data[vdm_type] = { - vdm_lane[index]+1: [ - vdm_value, - vdm_thrsh_high_alarm, - vdm_thrsh_low_alarm, - vdm_thrsh_high_warn, - vdm_thrsh_low_warn, - vdm_high_alarm_flag, - vdm_low_alarm_flag, - vdm_high_warn_flag, - vdm_low_warn_flag] - } - - else: - vdm_Page_data[vdm_info_dict[0]][vdm_lane[index]+1] = [ - vdm_value, - vdm_thrsh_high_alarm, - vdm_thrsh_low_alarm, - vdm_thrsh_high_warn, - vdm_thrsh_low_warn, - vdm_high_alarm_flag, - vdm_low_alarm_flag, - vdm_high_warn_flag, - vdm_low_warn_flag] - return vdm_Page_data - - def get_vdm_allpage(self): - ''' - This function returns VDM items from all advertised VDM pages. - Output format is a dictionary. Key is observable type; value is a dictionary. - In the inside dictionary, key is lane; value is a list - [ - vdm_value, - vdm_thrsh_high_alarm, - vdm_thrsh_low_alarm, - vdm_thrsh_high_warn, - vdm_thrsh_low_warn, - vdm_high_alarm_flag, - vdm_low_alarm_flag, - vdm_high_warn_flag, - vdm_low_warn_flag - ] - ''' - vdm_page_supported_raw = self.xcvr_eeprom.read(consts.VDM_SUPPORTED_PAGE) - if vdm_page_supported_raw is None: - return None - VDM_START_PAGE = 0x20 - vdm = dict() - # When raised by the host, causes the module to freeze and hold all - # reported statistics reporting registers (minimum, maximum and - # average values)in Pages 24h-27h. - # When ceased by the host, releases the freeze request, allowing the - # reported minimum, maximum and average values to update again. - self.xcvr_eeprom.write(consts.VDM_CONTROL, VDM_FREEZE) - time.sleep(1) - self.xcvr_eeprom.write(consts.VDM_CONTROL, VDM_UNFREEZE) - vdm_flag_page = self.xcvr_eeprom.read_raw(VDM_FLAG_PAGE * PAGE_SIZE + PAGE_OFFSET, PAGE_SIZE) - for page in range(VDM_START_PAGE, VDM_START_PAGE + vdm_page_supported_raw + 1): - vdm_current_page = self.get_vdm_page(page, vdm_flag_page) - vdm.update(vdm_current_page) - return vdm diff --git a/sonic_platform_base/sonic_xcvr/api/public/sff8436.py b/sonic_platform_base/sonic_xcvr/api/public/sff8436.py deleted file mode 100644 index 5834ac4f4..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/sff8436.py +++ /dev/null @@ -1,310 +0,0 @@ -""" - sff8436.py - - Implementation of XcvrApi that corresponds to the SFF-8436 specification for - QSFP+ pluggable transceivers. -""" - -from ...fields import consts -from ..xcvr_api import XcvrApi - -class Sff8436Api(XcvrApi): - NUM_CHANNELS = 4 - - def __init__(self, xcvr_eeprom): - super(Sff8436Api, self).__init__(xcvr_eeprom) - self._is_copper = None - - def get_model(self): - return self.xcvr_eeprom.read(consts.VENDOR_PART_NO_FIELD) - - def get_serial(self): - return self.xcvr_eeprom.read(consts.VENDOR_SERIAL_NO_FIELD) - - def get_transceiver_info(self): - serial_id = self.xcvr_eeprom.read(consts.SERIAL_ID_FIELD) - if serial_id is None: - return None - - ext_id = serial_id[consts.EXT_ID_FIELD] - power_class = ext_id[consts.POWER_CLASS_FIELD] - clei_code = ext_id[consts.CLEI_CODE_FIELD] - cdr_tx = ext_id[consts.CDR_TX_FIELD] - cdr_rx = ext_id[consts.CDR_RX_FIELD] - - smf_len = serial_id[consts.LENGTH_SMF_KM_FIELD] - om3_len = serial_id[consts.LENGTH_OM3_FIELD] - om2_len = serial_id[consts.LENGTH_OM2_FIELD] - om1_len = serial_id[consts.LENGTH_OM1_FIELD] - cable_assembly_len = serial_id[consts.LENGTH_ASSEMBLY_FIELD] - - len_types = ['Length(km)', 'Length OM3(2m)', 'Length OM2(m)', 'Length OM1(m)', 'Length Cable Assembly(m)'] - cable_len = 0 - cable_type = "Unknown" - for len, type in zip([smf_len, om3_len, om2_len, om1_len, cable_assembly_len], len_types): - if len > 0: - cable_len = len - cable_type = type - - xcvr_info = { - "type": serial_id[consts.ID_FIELD], - "type_abbrv_name": serial_id[consts.ID_ABBRV_FIELD], - "vendor_rev": serial_id[consts.VENDOR_REV_FIELD], - "serial": serial_id[consts.VENDOR_SERIAL_NO_FIELD], - "manufacturer": serial_id[consts.VENDOR_NAME_FIELD], - "model": serial_id[consts.VENDOR_PART_NO_FIELD], - "connector": serial_id[consts.CONNECTOR_FIELD], - "encoding": serial_id[consts.ENCODING_FIELD], - "ext_identifier": ", ".join([power_class, clei_code, cdr_tx, cdr_rx]), - "ext_rateselect_compliance": serial_id[consts.EXT_RATE_SELECT_COMPLIANCE_FIELD], - "cable_type": cable_type, - "cable_length": float(cable_len), - "nominal_bit_rate": serial_id[consts.NOMINAL_BR_FIELD], - "specification_compliance": str(serial_id[consts.SPEC_COMPLIANCE_FIELD]), - "vendor_date": serial_id[consts.VENDOR_DATE_FIELD], - "vendor_oui": serial_id[consts.VENDOR_OUI_FIELD], - "application_advertisement": "N/A", - } - - return xcvr_info - - def get_transceiver_bulk_status(self): - rx_los = self.get_rx_los() - tx_fault = self.get_tx_fault() - tx_disable = self.get_tx_disable() - tx_disabled_channel = self.get_tx_disable_channel() - temp = self.get_module_temperature() - voltage = self.get_voltage() - tx_bias = self.get_tx_bias() - rx_power = self.get_rx_power() - tx_power = self.get_tx_power() - read_failed = rx_los is None or \ - tx_fault is None or \ - tx_disable is None or \ - tx_disabled_channel is None or \ - temp is None or \ - voltage is None or \ - tx_bias is None or \ - rx_power is None or \ - tx_power is None - if read_failed: - return None - - bulk_status = { - "rx_los": all(rx_los) if self.get_rx_los_support() else 'N/A', - "tx_fault": all(tx_fault) if self.get_tx_fault_support() else 'N/A', - "tx_disable": all(tx_disable), - "tx_disabled_channel": tx_disabled_channel, - "temperature": temp, - "voltage": voltage - } - - for i in range(1, self.NUM_CHANNELS + 1): - bulk_status["tx%dbias" % i] = tx_bias[i - 1] - bulk_status["rx%dpower" % i] = rx_power[i - 1] - bulk_status["tx%dpower" % i] = tx_power[i - 1] - - return bulk_status - - def get_transceiver_threshold_info(self): - threshold_info_keys = ['temphighalarm', 'temphighwarning', - 'templowalarm', 'templowwarning', - 'vcchighalarm', 'vcchighwarning', - 'vcclowalarm', 'vcclowwarning', - 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', - 'txpowerhighalarm', 'txpowerhighwarning', - 'txpowerlowalarm', 'txpowerlowwarning', - 'txbiashighalarm', 'txbiashighwarning', - 'txbiaslowalarm', 'txbiaslowwarning' - ] - threshold_info_dict = dict.fromkeys(threshold_info_keys, 'N/A') - thresh_support = self.get_transceiver_thresholds_support() - if not thresh_support: - return threshold_info_dict - - temp_thresholds = self.xcvr_eeprom.read(consts.TEMP_THRESHOLDS_FIELD) - voltage_thresholds = self.xcvr_eeprom.read(consts.VOLTAGE_THRESHOLDS_FIELD) - rx_power_thresholds = self.xcvr_eeprom.read(consts.RX_POWER_THRESHOLDS_FIELD) - tx_bias_thresholds = self.xcvr_eeprom.read(consts.TX_BIAS_THRESHOLDS_FIELD) - read_failed = temp_thresholds is None or \ - voltage_thresholds is None or \ - rx_power_thresholds is None or \ - tx_bias_thresholds is None - if read_failed: - return None - - for thresh in rx_power_thresholds: - rx_power_thresholds[thresh] = self.mw_to_dbm(rx_power_thresholds[thresh]) - - return { - "temphighalarm": float("{:.3f}".format(temp_thresholds[consts.TEMP_HIGH_ALARM_FIELD])), - "templowalarm": float("{:.3f}".format(temp_thresholds[consts.TEMP_LOW_ALARM_FIELD])), - "temphighwarning": float("{:.3f}".format(temp_thresholds[consts.TEMP_HIGH_WARNING_FIELD])), - "templowwarning": float("{:.3f}".format(temp_thresholds[consts.TEMP_LOW_WARNING_FIELD])), - "vcchighalarm": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_HIGH_ALARM_FIELD])), - "vcclowalarm": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_LOW_ALARM_FIELD])), - "vcchighwarning": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_HIGH_WARNING_FIELD])), - "vcclowwarning": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_LOW_WARNING_FIELD])), - "rxpowerhighalarm": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_HIGH_ALARM_FIELD])), - "rxpowerlowalarm": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_LOW_ALARM_FIELD])), - "rxpowerhighwarning": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_HIGH_WARNING_FIELD])), - "rxpowerlowwarning": float("{:.3f}".format(rx_power_thresholds[consts.RX_POWER_LOW_WARNING_FIELD])), - "txpowerhighalarm": "N/A", - "txpowerlowalarm": "N/A", - "txpowerhighwarning": "N/A", - "txpowerlowwarning": "N/A", - "txbiashighalarm": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_HIGH_ALARM_FIELD])), - "txbiaslowalarm": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_LOW_ALARM_FIELD])), - "txbiashighwarning": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_HIGH_WARNING_FIELD])), - "txbiaslowwarning": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_LOW_WARNING_FIELD])) - } - - def get_rx_los(self): - rx_los = self.xcvr_eeprom.read(consts.RX_LOS_FIELD) - if rx_los is None: - return None - return [bool(rx_los & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def get_tx_fault(self): - tx_fault_support = self.get_tx_fault_support() - if tx_fault_support is None: - return None - if not tx_fault_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_fault = self.xcvr_eeprom.read(consts.TX_FAULT_FIELD) - if tx_fault is None: - return None - return [bool(tx_fault & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def get_tx_disable(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_disable = self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - if tx_disable is None: - return None - return [bool(tx_disable & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def get_tx_disable_channel(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return 'N/A' - return self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - - def get_module_temperature(self): - if not self.get_temperature_support(): - return 'N/A' - temp = self.xcvr_eeprom.read(consts.TEMPERATURE_FIELD) - if temp is None: - return None - return float("{:.3f}".format(temp)) - - def get_voltage(self): - if not self.get_voltage_support(): - return 'N/A' - voltage = self.xcvr_eeprom.read(consts.VOLTAGE_FIELD) - if voltage is None: - return None - return float("{:.3f}".format(voltage)) - - def get_tx_bias(self): - tx_bias = self.xcvr_eeprom.read(consts.TX_BIAS_FIELD) - if tx_bias is None: - return None - return [channel_bias for channel_bias in tx_bias.values()] - - def get_rx_power(self): - if not self.get_rx_power_support(): - return ["N/A" for _ in range(self.NUM_CHANNELS)] - rx_power = self.xcvr_eeprom.read(consts.RX_POWER_FIELD) - if rx_power is None: - return None - return [float("{:.3f}".format(channel_power)) for channel_power in rx_power.values()] - - def get_tx_power(self): - return ["N/A" for _ in range(self.NUM_CHANNELS)] - - def tx_disable(self, tx_disable): - val = 0xF if tx_disable else 0x0 - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, val) - - def tx_disable_channel(self, channel, disable): - channel_state = self.get_tx_disable_channel() - if channel_state is None or channel_state == "N/A": - return False - - for i in range(self.NUM_CHANNELS): - mask = (1 << i) - if not (channel & mask): - continue - if disable: - channel_state |= mask - else: - channel_state &= ~mask - - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, channel_state) - - def get_power_override(self): - return self.xcvr_eeprom.read(consts.POWER_OVERRIDE_FIELD) - - def get_power_set(self): - return self.xcvr_eeprom.read(consts.POWER_SET_FIELD) - - def set_power_override(self, power_override, power_set): - ret = self.xcvr_eeprom.write(consts.POWER_OVERRIDE_FIELD, power_override) - if power_override: - ret &= self.xcvr_eeprom.write(consts.POWER_SET_FIELD, power_set) - return ret - - def is_flat_memory(self): - return self.xcvr_eeprom.read(consts.FLAT_MEM_FIELD) - - def get_tx_power_support(self): - return False - - def get_rx_power_support(self): - return not self.is_copper() - - def is_copper(self): - if self._is_copper is None: - eth_compliance = self.xcvr_eeprom.read(consts.ETHERNET_10_40G_COMPLIANCE_FIELD) - if eth_compliance is None: - return None - else: - self._is_copper = eth_compliance == "40GBASE-CR4" - return self._is_copper - - def get_temperature_support(self): - return not self.is_copper() - - def get_voltage_support(self): - return not self.is_copper() - - def get_rx_los_support(self): - return True - - def get_tx_bias_support(self): - return True - - def get_tx_fault_support(self): - return self.xcvr_eeprom.read(consts.TX_FAULT_SUPPORT_FIELD) - - def get_tx_disable_support(self): - return self.xcvr_eeprom.read(consts.TX_DISABLE_SUPPORT_FIELD) - - def get_transceiver_thresholds_support(self): - return not self.is_copper() and not self.is_flat_memory() - - def get_lpmode_support(self): - power_class = self.xcvr_eeprom.read(consts.POWER_CLASS_FIELD) - if power_class is None: - return False - return "Power Class 1" not in power_class - - def get_power_override_support(self): - return not self.is_copper() diff --git a/sonic_platform_base/sonic_xcvr/api/public/sff8472.py b/sonic_platform_base/sonic_xcvr/api/public/sff8472.py deleted file mode 100644 index 3ccfcfb0e..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/sff8472.py +++ /dev/null @@ -1,299 +0,0 @@ -""" - sff8472.py - - Implementation of XcvrApi that corresponds to the SFF-8472 specification for - SFP+ pluggable transceivers. -""" -from ...fields import consts -from ..xcvr_api import XcvrApi - -class Sff8472Api(XcvrApi): - NUM_CHANNELS = 1 - - def __init__(self, xcvr_eeprom): - super(Sff8472Api, self).__init__(xcvr_eeprom) - - def get_model(self): - return self.xcvr_eeprom.read(consts.VENDOR_PART_NO_FIELD) - - def get_serial(self): - return self.xcvr_eeprom.read(consts.VENDOR_SERIAL_NO_FIELD) - - def get_transceiver_info(self): - serial_id = self.xcvr_eeprom.read(consts.SERIAL_ID_FIELD) - if serial_id is None: - return None - smf_km_len = serial_id[consts.LENGTH_SMF_KM_FIELD] - smf_m_len = serial_id[consts.LENGTH_SMF_M_FIELD] - om4_len = serial_id[consts.LENGTH_OM4_FIELD] - om3_len = serial_id[consts.LENGTH_OM3_FIELD] - om2_len = serial_id[consts.LENGTH_OM2_FIELD] - om1_len = serial_id[consts.LENGTH_OM1_FIELD] - - len_types = ["Length SMF (km)", "Length SMF (100m)", "Length OM2 (10m)", "Length OM1(10m)", "Length OM4(10m)", "Length OM3(10m)"] - cable_len = 0 - cable_type = None - for len, type in zip([smf_km_len, smf_m_len, om2_len, om1_len, om4_len, om3_len], len_types): - if len > 0: - cable_len = len - cable_type = type - - xcvr_info = { - "type": serial_id[consts.ID_FIELD], - "type_abbrv_name": serial_id[consts.ID_ABBRV_FIELD], - "vendor_rev": serial_id[consts.VENDOR_REV_FIELD], - "serial": serial_id[consts.VENDOR_SERIAL_NO_FIELD], - "manufacturer": serial_id[consts.VENDOR_NAME_FIELD], - "model": serial_id[consts.VENDOR_PART_NO_FIELD], - "connector": serial_id[consts.CONNECTOR_FIELD], - "encoding": serial_id[consts.ENCODING_FIELD], - "ext_identifier": serial_id[consts.EXT_ID_FIELD], - "ext_rateselect_compliance": serial_id[consts.RATE_ID_FIELD], - "cable_type": cable_type, - "cable_length": float(cable_len), - "nominal_bit_rate": serial_id[consts.NOMINAL_BR_FIELD], - "specification_compliance": str(serial_id[consts.SPEC_COMPLIANCE_FIELD]), - "vendor_date": serial_id[consts.VENDOR_DATE_FIELD], - "vendor_oui": serial_id[consts.VENDOR_OUI_FIELD], - "application_advertisement": "N/A", - } - - return xcvr_info - - def get_transceiver_bulk_status(self): - rx_los = self.get_rx_los() - tx_fault = self.get_tx_fault() - tx_disable = self.get_tx_disable() - tx_disabled_channel = self.get_tx_disable_channel() - temp = self.get_module_temperature() - voltage = self.get_voltage() - tx_bias = self.get_tx_bias() - rx_power = self.get_rx_power() - tx_power = self.get_tx_power() - read_failed = rx_los is None or \ - tx_fault is None or \ - tx_disable is None or \ - tx_disabled_channel is None or \ - temp is None or \ - voltage is None or \ - tx_bias is None or \ - rx_power is None or \ - tx_power is None - if read_failed: - return None - - bulk_status = { - "rx_los": all(rx_los) if self.get_rx_los_support() else 'N/A', - "tx_fault": all(tx_fault) if self.get_tx_fault_support() else 'N/A', - "tx_disable": all(tx_disable), - "tx_disabled_channel": tx_disabled_channel, - "temperature": temp, - "voltage": voltage - } - - for i in range(1, self.NUM_CHANNELS + 1): - bulk_status["tx%dbias" % i] = tx_bias[i - 1] - bulk_status["rx%dpower" % i] = rx_power[i - 1] - bulk_status["tx%dpower" % i] = tx_power[i - 1] - - # Added to avoid failing xcvrd. Ideally xcvrd should be fixed so that this is not necessary - for i in range(2, 5): - bulk_status["tx%dbias" % i] = 'N/A' - bulk_status["rx%dpower" % i] = 'N/A' - bulk_status["tx%dpower" % i] = 'N/A' - - return bulk_status - - def get_transceiver_threshold_info(self): - threshold_info_keys = ['temphighalarm', 'temphighwarning', - 'templowalarm', 'templowwarning', - 'vcchighalarm', 'vcchighwarning', - 'vcclowalarm', 'vcclowwarning', - 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', - 'txpowerhighalarm', 'txpowerhighwarning', - 'txpowerlowalarm', 'txpowerlowwarning', - 'txbiashighalarm', 'txbiashighwarning', - 'txbiaslowalarm', 'txbiaslowwarning' - ] - threshold_info_dict = dict.fromkeys(threshold_info_keys, 'N/A') - thresh_support = self.get_transceiver_thresholds_support() - if thresh_support is None: - return None - if not thresh_support: - return threshold_info_dict - thresholds = self.xcvr_eeprom.read(consts.THRESHOLDS_FIELD) - if thresholds is None: - return threshold_info_dict - - return { - "temphighalarm": float("{:.3f}".format(thresholds[consts.TEMP_HIGH_ALARM_FIELD])), - "templowalarm": float("{:.3f}".format(thresholds[consts.TEMP_LOW_ALARM_FIELD])), - "temphighwarning": float("{:.3f}".format(thresholds[consts.TEMP_HIGH_WARNING_FIELD])), - "templowwarning": float("{:.3f}".format(thresholds[consts.TEMP_LOW_WARNING_FIELD])), - "vcchighalarm": float("{:.3f}".format(thresholds[consts.VOLTAGE_HIGH_ALARM_FIELD])), - "vcclowalarm": float("{:.3f}".format(thresholds[consts.VOLTAGE_LOW_ALARM_FIELD])), - "vcchighwarning": float("{:.3f}".format(thresholds[consts.VOLTAGE_HIGH_WARNING_FIELD])), - "vcclowwarning": float("{:.3f}".format(thresholds[consts.VOLTAGE_LOW_WARNING_FIELD])), - "rxpowerhighalarm": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.RX_POWER_HIGH_ALARM_FIELD]))), - "rxpowerlowalarm": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.RX_POWER_LOW_ALARM_FIELD]))), - "rxpowerhighwarning": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.RX_POWER_HIGH_WARNING_FIELD]))), - "rxpowerlowwarning": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.RX_POWER_LOW_WARNING_FIELD]))), - "txpowerhighalarm": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.TX_POWER_HIGH_ALARM_FIELD]))), - "txpowerlowalarm": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.TX_POWER_LOW_ALARM_FIELD]))), - "txpowerhighwarning": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.TX_POWER_HIGH_WARNING_FIELD]))), - "txpowerlowwarning": float("{:.3f}".format(self.mw_to_dbm(thresholds[consts.TX_POWER_LOW_WARNING_FIELD]))), - "txbiashighalarm": float("{:.3f}".format(thresholds[consts.TX_BIAS_HIGH_ALARM_FIELD])), - "txbiaslowalarm": float("{:.3f}".format(thresholds[consts.TX_BIAS_LOW_ALARM_FIELD])), - "txbiashighwarning": float("{:.3f}".format(thresholds[consts.TX_BIAS_HIGH_WARNING_FIELD])), - "txbiaslowwarning": float("{:.3f}".format(thresholds[consts.TX_BIAS_LOW_WARNING_FIELD])) - } - - def get_rx_los(self): - rx_los_support = self.get_rx_los_support() - if rx_los_support is None: - return None - if not rx_los_support: - return ["N/A"] - rx_los = self.xcvr_eeprom.read(consts.RX_LOS_FIELD) - if rx_los is None: - return None - return [rx_los] - - def get_tx_fault(self): - tx_fault_support = self.get_tx_fault_support() - if tx_fault_support is None: - return None - if not tx_fault_support: - return ["N/A"] - tx_fault = self.xcvr_eeprom.read(consts.TX_FAULT_FIELD) - if tx_fault is None: - return None - return [tx_fault] - - def get_tx_disable(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return ["N/A"] - tx_disable = self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - tx_disable_select = self.xcvr_eeprom.read(consts.TX_DISABLE_SELECT_FIELD) - if tx_disable is None or tx_disable_select is None: - return None - return [tx_disable or tx_disable_select] - - def get_tx_disable_channel(self): - tx_disable_list = self.get_tx_disable() - if tx_disable_list is None: - return None - if tx_disable_list[0] == "N/A": - return "N/A" - return int(tx_disable_list[0]) - - def get_module_temperature(self): - if not self.get_temperature_support(): - return 'N/A' - temp = self.xcvr_eeprom.read(consts.TEMPERATURE_FIELD) - if temp is None: - return None - return float("{:.3f}".format(temp)) - - def get_voltage(self): - voltage_support = self.get_voltage_support() - if voltage_support is None: - return None - if not voltage_support: - return 'N/A' - voltage = self.xcvr_eeprom.read(consts.VOLTAGE_FIELD) - if voltage is None: - return None - return float("{:.3f}".format(voltage)) - - def get_tx_bias(self): - tx_bias_support = self.get_tx_bias_support() - if tx_bias_support is None: - return None - if not tx_bias_support: - return ["N/A"] - tx_bias = self.xcvr_eeprom.read(consts.TX_BIAS_FIELD) - if tx_bias is None: - return None - return [float("{:.3f}".format(tx_bias))] - - def get_rx_power(self): - rx_power_support = self.get_rx_power_support() - if rx_power_support is None: - return None - if not rx_power_support: - return ["N/A"] - rx_power = self.xcvr_eeprom.read(consts.RX_POWER_FIELD) - if rx_power is None: - return None - return [float("{:.3f}".format(rx_power))] - - def get_tx_power(self): - tx_power_support = self.get_tx_power_support() - if tx_power_support is None: - return None - if not tx_power_support: - return ["N/A"] - tx_power = self.xcvr_eeprom.read(consts.TX_POWER_FIELD) - if tx_power is None: - return None - return [float("{:.3f}".format(tx_power))] - - def tx_disable(self, tx_disable): - return self.xcvr_eeprom.write(consts.TX_DISABLE_SELECT_FIELD, tx_disable) - - def tx_disable_channel(self, channel, disable): - channel_state = self.get_tx_disable_channel() - if channel_state is None or channel_state == "N/A": - return False - - for i in range(self.NUM_CHANNELS): - mask = (1 << i) - if not (channel & mask): - continue - if disable: - channel_state |= mask - else: - channel_state &= ~mask - - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, channel_state) - - def is_flat_memory(self): - return not self.xcvr_eeprom.read(consts.PAGING_SUPPORT_FIELD) - - def get_temperature_support(self): - return self.xcvr_eeprom.read(consts.DDM_SUPPORT_FIELD) - - def get_voltage_support(self): - return self.xcvr_eeprom.read(consts.DDM_SUPPORT_FIELD) - - def get_tx_power_support(self): - return self.xcvr_eeprom.read(consts.DDM_SUPPORT_FIELD) - - def get_rx_power_support(self): - return self.xcvr_eeprom.read(consts.DDM_SUPPORT_FIELD) - - def get_rx_los_support(self): - return self.xcvr_eeprom.read(consts.RX_LOS_SUPPORT_FIELD) - - def get_tx_bias_support(self): - return self.xcvr_eeprom.read(consts.DDM_SUPPORT_FIELD) - - def get_tx_fault_support(self): - return self.xcvr_eeprom.read(consts.TX_FAULT_SUPPORT_FIELD) - - def get_tx_disable_support(self): - return self.xcvr_eeprom.read(consts.TX_DISABLE_SUPPORT_FIELD) - - def get_transceiver_thresholds_support(self): - return self.xcvr_eeprom.read(consts.DDM_SUPPORT_FIELD) - - def get_lpmode_support(self): - return False - - def get_power_override_support(self): - return False diff --git a/sonic_platform_base/sonic_xcvr/api/public/sff8636.py b/sonic_platform_base/sonic_xcvr/api/public/sff8636.py deleted file mode 100644 index 8f98fb4c7..000000000 --- a/sonic_platform_base/sonic_xcvr/api/public/sff8636.py +++ /dev/null @@ -1,362 +0,0 @@ -""" - sff8636.py - - Implementation of XcvrApi that corresponds to the SFF-8636 specification for - QSFP28 pluggable transceivers. -""" - -from ...fields import consts -from ..xcvr_api import XcvrApi - -from ...codes.public.sff8636 import Sff8636Codes - -class Sff8636Api(XcvrApi): - NUM_CHANNELS = 4 - - def __init__(self, xcvr_eeprom): - super(Sff8636Api, self).__init__(xcvr_eeprom) - self._temp_support = None - self._voltage_support = None - self._is_copper = None - - def get_model(self): - return self.xcvr_eeprom.read(consts.VENDOR_PART_NO_FIELD) - - def get_serial(self): - return self.xcvr_eeprom.read(consts.VENDOR_SERIAL_NO_FIELD) - - def get_transceiver_info(self): - serial_id = self.xcvr_eeprom.read(consts.SERIAL_ID_FIELD) - if serial_id is None: - return None - - ext_id = serial_id[consts.EXT_ID_FIELD] - power_class = ext_id[consts.POWER_CLASS_FIELD] - clei_code = ext_id[consts.CLEI_CODE_FIELD] - cdr_tx = ext_id[consts.CDR_TX_FIELD] - cdr_rx = ext_id[consts.CDR_RX_FIELD] - - spec_compliance = serial_id[consts.SPEC_COMPLIANCE_FIELD] - spec_compliance[consts.EXT_SPEC_COMPLIANCE_FIELD] = serial_id[consts.EXT_SPEC_COMPLIANCE_FIELD] - - smf_len = serial_id[consts.LENGTH_SMF_KM_FIELD] - om3_len = serial_id[consts.LENGTH_OM3_FIELD] - om2_len = serial_id[consts.LENGTH_OM2_FIELD] - om1_len = serial_id[consts.LENGTH_OM1_FIELD] - cable_assembly_len = serial_id[consts.LENGTH_ASSEMBLY_FIELD] - - len_types = ['Length(km)', 'Length OM3(2m)', 'Length OM2(m)', 'Length OM1(m)', 'Length Cable Assembly(m)'] - cable_len = 0 - cable_type = "Unknown" - for len, type in zip([smf_len, om3_len, om2_len, om1_len, cable_assembly_len], len_types): - if len > 0: - cable_len = len - cable_type = type - - xcvr_info = { - "type": serial_id[consts.ID_FIELD], - "type_abbrv_name": serial_id[consts.ID_ABBRV_FIELD], - "vendor_rev": serial_id[consts.VENDOR_REV_FIELD], - "serial": serial_id[consts.VENDOR_SERIAL_NO_FIELD], - "manufacturer": serial_id[consts.VENDOR_NAME_FIELD], - "model": serial_id[consts.VENDOR_PART_NO_FIELD], - "connector": serial_id[consts.CONNECTOR_FIELD], - "encoding": serial_id[consts.ENCODING_FIELD], - "ext_identifier": ", ".join([power_class, clei_code, cdr_tx, cdr_rx]), - "ext_rateselect_compliance": serial_id[consts.EXT_RATE_SELECT_COMPLIANCE_FIELD], - "cable_type": cable_type, - "cable_length": float(cable_len), - "nominal_bit_rate": serial_id[consts.NOMINAL_BR_FIELD], - "specification_compliance": str(spec_compliance), - "vendor_date": serial_id[consts.VENDOR_DATE_FIELD], - "vendor_oui": serial_id[consts.VENDOR_OUI_FIELD], - "application_advertisement": "N/A", - } - - return xcvr_info - - def get_transceiver_bulk_status(self): - rx_los = self.get_rx_los() - tx_fault = self.get_tx_fault() - tx_disable = self.get_tx_disable() - tx_disabled_channel = self.get_tx_disable_channel() - temp = self.get_module_temperature() - voltage = self.get_voltage() - tx_bias = self.get_tx_bias() - rx_power = self.get_rx_power() - tx_power = self.get_tx_power() - read_failed = rx_los is None or \ - tx_fault is None or \ - tx_disable is None or \ - tx_disabled_channel is None or \ - temp is None or \ - voltage is None or \ - tx_bias is None or \ - rx_power is None or \ - tx_power is None - if read_failed: - return None - - bulk_status = { - "rx_los": all(rx_los) if self.get_rx_los_support() else 'N/A', - "tx_fault": all(tx_fault) if self.get_tx_fault_support() else 'N/A', - "tx_disable": all(tx_disable), - "tx_disabled_channel": tx_disabled_channel, - "temperature": temp, - "voltage": voltage - } - - for i in range(1, self.NUM_CHANNELS + 1): - bulk_status["tx%dbias" % i] = tx_bias[i - 1] - bulk_status["rx%dpower" % i] = rx_power[i - 1] - bulk_status["tx%dpower" % i] = tx_power[i - 1] - - return bulk_status - - def get_transceiver_threshold_info(self): - threshold_info_keys = ['temphighalarm', 'temphighwarning', - 'templowalarm', 'templowwarning', - 'vcchighalarm', 'vcchighwarning', - 'vcclowalarm', 'vcclowwarning', - 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', - 'txpowerhighalarm', 'txpowerhighwarning', - 'txpowerlowalarm', 'txpowerlowwarning', - 'txbiashighalarm', 'txbiashighwarning', - 'txbiaslowalarm', 'txbiaslowwarning' - ] - threshold_info_dict = dict.fromkeys(threshold_info_keys, 'N/A') - thresh_support = self.get_transceiver_thresholds_support() - if not thresh_support: - return threshold_info_dict - temp_thresholds = self.xcvr_eeprom.read(consts.TEMP_THRESHOLDS_FIELD) - voltage_thresholds = self.xcvr_eeprom.read(consts.VOLTAGE_THRESHOLDS_FIELD) - rx_power_thresholds = self.xcvr_eeprom.read(consts.RX_POWER_THRESHOLDS_FIELD) - tx_bias_thresholds = self.xcvr_eeprom.read(consts.TX_BIAS_THRESHOLDS_FIELD) - tx_power_thresholds = self.xcvr_eeprom.read(consts.TX_POWER_THRESHOLDS_FIELD) - tx_power_support = self.get_tx_power_support() - read_failed = temp_thresholds is None or \ - voltage_thresholds is None or \ - rx_power_thresholds is None or \ - tx_bias_thresholds is None or \ - tx_power_thresholds is None or \ - tx_power_support is None - if read_failed: - return None - - for thresh in rx_power_thresholds: - rx_power_thresholds[thresh] = float("{:.3f}".format(self.mw_to_dbm(rx_power_thresholds[thresh]))) - - for thresh in tx_power_thresholds: - if tx_power_support: - tx_power_thresholds[thresh] = float("{:.3f}".format(self.mw_to_dbm(tx_power_thresholds[thresh]))) - else: - tx_power_thresholds[thresh] = "N/A" - - - return { - "temphighalarm": float("{:.3f}".format(temp_thresholds[consts.TEMP_HIGH_ALARM_FIELD])), - "templowalarm": float("{:.3f}".format(temp_thresholds[consts.TEMP_LOW_ALARM_FIELD])), - "temphighwarning": float("{:.3f}".format(temp_thresholds[consts.TEMP_HIGH_WARNING_FIELD])), - "templowwarning": float("{:.3f}".format(temp_thresholds[consts.TEMP_LOW_WARNING_FIELD])), - "vcchighalarm": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_HIGH_ALARM_FIELD])), - "vcclowalarm": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_LOW_ALARM_FIELD])), - "vcchighwarning": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_HIGH_WARNING_FIELD])), - "vcclowwarning": float("{:.3f}".format(voltage_thresholds[consts.VOLTAGE_LOW_WARNING_FIELD])), - "rxpowerhighalarm": rx_power_thresholds[consts.RX_POWER_HIGH_ALARM_FIELD], - "rxpowerlowalarm": rx_power_thresholds[consts.RX_POWER_LOW_ALARM_FIELD], - "rxpowerhighwarning": rx_power_thresholds[consts.RX_POWER_HIGH_WARNING_FIELD], - "rxpowerlowwarning": rx_power_thresholds[consts.RX_POWER_LOW_WARNING_FIELD], - "txpowerhighalarm": tx_power_thresholds[consts.TX_POWER_HIGH_ALARM_FIELD], - "txpowerlowalarm": tx_power_thresholds[consts.TX_POWER_LOW_ALARM_FIELD], - "txpowerhighwarning": tx_power_thresholds[consts.TX_POWER_HIGH_WARNING_FIELD], - "txpowerlowwarning": tx_power_thresholds[consts.TX_POWER_LOW_WARNING_FIELD], - "txbiashighalarm": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_HIGH_ALARM_FIELD])), - "txbiaslowalarm": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_LOW_ALARM_FIELD])), - "txbiashighwarning": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_HIGH_WARNING_FIELD])), - "txbiaslowwarning": float("{:.3f}".format(tx_bias_thresholds[consts.TX_BIAS_LOW_WARNING_FIELD])) - } - - def get_rx_los(self): - rx_los = self.xcvr_eeprom.read(consts.RX_LOS_FIELD) - if rx_los is None: - return None - return [bool(rx_los & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def get_tx_fault(self): - tx_fault_support = self.get_tx_fault_support() - if tx_fault_support is None: - return None - if not tx_fault_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_fault = self.xcvr_eeprom.read(consts.TX_FAULT_FIELD) - if tx_fault is None: - return None - return [bool(tx_fault & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def get_tx_disable(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_disable = self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - if tx_disable is None: - return None - return [bool(tx_disable & (1 << i)) for i in range(self.NUM_CHANNELS)] - - def get_tx_disable_channel(self): - tx_disable_support = self.get_tx_disable_support() - if tx_disable_support is None: - return None - if not tx_disable_support: - return 'N/A' - return self.xcvr_eeprom.read(consts.TX_DISABLE_FIELD) - - def get_module_temperature(self): - if not self.get_temperature_support(): - return 'N/A' - temp = self.xcvr_eeprom.read(consts.TEMPERATURE_FIELD) - if temp is None: - return None - return float("{:.3f}".format(temp)) - - def get_voltage(self): - if not self.get_voltage_support(): - return 'N/A' - voltage = self.xcvr_eeprom.read(consts.VOLTAGE_FIELD) - if voltage is None: - return None - return float("{:.3f}".format(voltage)) - - def get_tx_bias(self): - tx_bias = self.xcvr_eeprom.read(consts.TX_BIAS_FIELD) - if tx_bias is None: - return None - return [channel_bias for channel_bias in tx_bias.values()] - - def get_rx_power(self): - rx_power_support = self.get_rx_power_support() - if not rx_power_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - rx_power = self.xcvr_eeprom.read(consts.RX_POWER_FIELD) - if rx_power is None: - return None - return [float("{:.3f}".format(channel_power)) for channel_power in rx_power.values()] - - def get_tx_power(self): - tx_power_support = self.get_tx_power_support() - if tx_power_support is None: - return None - if not tx_power_support: - return ["N/A" for _ in range(self.NUM_CHANNELS)] - tx_power = self.xcvr_eeprom.read(consts.TX_POWER_FIELD) - if tx_power is None: - return None - return [float("{:.3f}".format(channel_power)) for channel_power in tx_power.values()] - - def tx_disable(self, tx_disable): - val = 0xF if tx_disable else 0x0 - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, val) - - def tx_disable_channel(self, channel, disable): - channel_state = self.get_tx_disable_channel() - if channel_state is None or channel_state == "N/A": - return False - - for i in range(self.NUM_CHANNELS): - mask = (1 << i) - if not (channel & mask): - continue - if disable: - channel_state |= mask - else: - channel_state &= ~mask - - return self.xcvr_eeprom.write(consts.TX_DISABLE_FIELD, channel_state) - - def get_power_override(self): - return self.xcvr_eeprom.read(consts.POWER_OVERRIDE_FIELD) - - def get_power_set(self): - return self.xcvr_eeprom.read(consts.POWER_SET_FIELD) - - def set_power_override(self, power_override, power_set): - ret = self.xcvr_eeprom.write(consts.POWER_OVERRIDE_FIELD, power_override) - if power_override: - ret &= self.xcvr_eeprom.write(consts.POWER_SET_FIELD, power_set) - return ret - - def is_flat_memory(self): - return self.xcvr_eeprom.read(consts.FLAT_MEM_FIELD) - - def get_tx_power_support(self): - if self.is_copper(): - return False - return self.xcvr_eeprom.read(consts.TX_POWER_SUPPORT_FIELD) - - def get_rx_power_support(self): - return not self.is_copper() - - def is_copper(self): - if self._is_copper is None: - eth_compliance = self.xcvr_eeprom.read(consts.ETHERNET_10_40G_COMPLIANCE_FIELD) - ext_spec_compliance = self.xcvr_eeprom.read(consts.EXT_SPEC_COMPLIANCE_FIELD) - if eth_compliance is None or ext_spec_compliance is None: - return None - else: - self._is_copper = eth_compliance == "40GBASE-CR4" or \ - "CR" in ext_spec_compliance or \ - "ACC" in ext_spec_compliance or \ - "Copper" in ext_spec_compliance - return self._is_copper - - def get_temperature_support(self): - if self.is_copper(): - return False - if self._temp_support is None: - rev_compliance = self.xcvr_eeprom.read(consts.REV_COMPLIANCE_FIELD) - # TODO: instead of checking for specific decoded value, should - # get the raw code and check if it is >= 0x08, i.e. Rev 2.8 or higher - if rev_compliance == Sff8636Codes.REV_COMPLIANCE[8]: - self._temp_support = self.xcvr_eeprom.read(consts.TEMP_SUPPORT_FIELD) - else: - self._temp_support = True - return self._temp_support - - def get_voltage_support(self): - if self.is_copper(): - return False - if self._voltage_support is None: - rev_compliance = self.xcvr_eeprom.read(consts.REV_COMPLIANCE_FIELD) - # TODO: instead of checking for specific decoded value, should - # get the raw code and check if it is >= 0x08, i.e. Rev 2.8 or higher - if rev_compliance == Sff8636Codes.REV_COMPLIANCE[8]: - self._voltage_support = self.xcvr_eeprom.read(consts.VOLTAGE_SUPPORT_FIELD) - else: - self._voltage_support = True - return self._voltage_support - - def get_rx_los_support(self): - return True - - def get_tx_bias_support(self): - return True - - def get_tx_fault_support(self): - return self.xcvr_eeprom.read(consts.TX_FAULT_SUPPORT_FIELD) - - def get_tx_disable_support(self): - return self.xcvr_eeprom.read(consts.TX_DISABLE_SUPPORT_FIELD) - - def get_transceiver_thresholds_support(self): - return not self.is_copper() and not self.is_flat_memory() - - def get_lpmode_support(self): - power_class = self.xcvr_eeprom.read(consts.POWER_CLASS_FIELD) - if power_class is None: - return False - return "Power Class 1" not in power_class - - def get_power_override_support(self): - return not self.is_copper() diff --git a/sonic_platform_base/sonic_xcvr/api/xcvr_api.py b/sonic_platform_base/sonic_xcvr/api/xcvr_api.py deleted file mode 100644 index e759f794e..000000000 --- a/sonic_platform_base/sonic_xcvr/api/xcvr_api.py +++ /dev/null @@ -1,634 +0,0 @@ -""" - xcvr_api.py - - Abstract base class for platform-independent APIs used to interact with - xcvrs in SONiC -""" -from math import log10 -class XcvrApi(object): - def __init__(self, xcvr_eeprom): - self.xcvr_eeprom = xcvr_eeprom - - @staticmethod - def mw_to_dbm(mW): - if mW == 0: - return float("-inf") - elif mW < 0: - return float("NaN") - return 10. * log10(mW) - - def get_model(self): - """ - Retrieves the model (part number) of the xcvr - - Returns: - A string, the model/part number of the xcvr - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_serial(self): - """ - Retrieves the serial number of the xcvr - - Returns: - A string, the serial number of the xcvr - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_transceiver_info(self): - """ - Retrieves general info about this xcvr - - Returns: - A dict containing the following keys/values : - ================================================================================ - keys |Value Format |Information - ---------------------------|---------------|---------------------------- - type |string |type of xcvr - type_abbrv_name |string |type of SFP, abbreviated - hardware_rev |string |hardware version of xcvr - serial |string |serial number of the xcvr - manufacturer |string |xcvr vendor name - model |string |xcvr model name - connector |string |connector information - encoding |string |encoding information - ext_identifier |string |extend identifier - ext_rateselect_compliance |string |extended rateSelect compliance - cable_length |float |cable length in m - nominal_bit_rate |int |nominal bit rate by 100Mbs - specification_compliance |string |specification compliance - vendor_date |string |vendor date - vendor_oui |string |vendor OUI - application_advertisement |string |supported applications advertisement - ================================================================================ - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_transceiver_bulk_status(self): - """ - Retrieves bulk status info for this xcvr - - Returns: - A dict containing the following keys/values : - ======================================================================== - keys |Value Format |Information - ---------------------------|---------------|---------------------------- - rx_los |bool |RX loss-of-signal status, True if has RX los, False if not. - tx_fault |bool |TX fault status, True if has TX fault, False if not. - tx_disable |bool |TX disable status, True TX disabled, False if not. - tx_disabled_channel |int |disabled TX channels in hex, bits 0 to 3 represent channel 0 - | |to channel 3 (for example). - temperature |float |module temperature in Celsius - voltage |float |supply voltage in mV - txbias |float |TX Bias Current in mA, n is the channel number, - | |for example, tx2bias stands for tx bias of channel 2. - rxpower |float |received optical power in mW, n is the channel number, - | |for example, rx2power stands for rx power of channel 2. - txpower |float |TX output power in mW, n is the channel number, - | |for example, tx2power stands for tx power of channel 2. - ======================================================================== - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_transceiver_threshold_info(self): - """ - Retrieves threshold info for this xcvr - - Returns: - A dict containing the 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. - ======================================================================== - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_transceiver_status(self): - """ - Retrieves transceiver status of this SFP (applicable for CMIS/C-CMIS) - - Returns: - A dict which may contain following keys/values (there could be more for C-CMIS) : - ================================================================================ - key = TRANSCEIVER_STATUS|ifname ; Error information for module on port - ; field = value - module_state = 1*255VCHAR ; current module state (ModuleLowPwr, ModulePwrUp, ModuleReady, ModulePwrDn, Fault) - module_fault_cause = 1*255VCHAR ; reason of entering the module fault state - datapath_firmware_fault = BOOLEAN ; datapath (DSP) firmware fault - module_firmware_fault = BOOLEAN ; module firmware fault - module_state_changed = BOOLEAN ; module state changed - datapath_hostlane1 = 1*255VCHAR ; data path state indicator on host lane 1 - datapath_hostlane2 = 1*255VCHAR ; data path state indicator on host lane 2 - datapath_hostlane3 = 1*255VCHAR ; data path state indicator on host lane 3 - datapath_hostlane4 = 1*255VCHAR ; data path state indicator on host lane 4 - datapath_hostlane5 = 1*255VCHAR ; data path state indicator on host lane 5 - datapath_hostlane6 = 1*255VCHAR ; data path state indicator on host lane 6 - datapath_hostlane7 = 1*255VCHAR ; data path state indicator on host lane 7 - datapath_hostlane8 = 1*255VCHAR ; data path state indicator on host lane 8 - txoutput_status = BOOLEAN ; tx output status on media lane - rxoutput_status_hostlane1 = BOOLEAN ; rx output status on host lane 1 - rxoutput_status_hostlane2 = BOOLEAN ; rx output status on host lane 2 - rxoutput_status_hostlane3 = BOOLEAN ; rx output status on host lane 3 - rxoutput_status_hostlane4 = BOOLEAN ; rx output status on host lane 4 - rxoutput_status_hostlane5 = BOOLEAN ; rx output status on host lane 5 - rxoutput_status_hostlane6 = BOOLEAN ; rx output status on host lane 6 - rxoutput_status_hostlane7 = BOOLEAN ; rx output status on host lane 7 - rxoutput_status_hostlane8 = BOOLEAN ; rx output status on host lane 8 - txfault = BOOLEAN ; tx fault flag on media lane - txlos_hostlane1 = BOOLEAN ; tx loss of signal flag on host lane 1 - txlos_hostlane2 = BOOLEAN ; tx loss of signal flag on host lane 2 - txlos_hostlane3 = BOOLEAN ; tx loss of signal flag on host lane 3 - txlos_hostlane4 = BOOLEAN ; tx loss of signal flag on host lane 4 - txlos_hostlane5 = BOOLEAN ; tx loss of signal flag on host lane 5 - txlos_hostlane6 = BOOLEAN ; tx loss of signal flag on host lane 6 - txlos_hostlane7 = BOOLEAN ; tx loss of signal flag on host lane 7 - txlos_hostlane8 = BOOLEAN ; tx loss of signal flag on host lane 8 - txcdrlol_hostlane1 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 1 - txcdrlol_hostlane2 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 2 - txcdrlol_hostlane3 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 3 - txcdrlol_hostlane4 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 4 - txcdrlol_hostlane5 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 5 - txcdrlol_hostlane6 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 6 - txcdrlol_hostlane7 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 7 - txcdrlol_hostlane8 = BOOLEAN ; tx clock and data recovery loss of lock on host lane 8 - rxlos = BOOLEAN ; rx loss of signal flag on media lane - rxcdrlol = BOOLEAN ; rx clock and data recovery loss of lock on media lane - config_state_hostlane1 = 1*255VCHAR ; configuration status for the data path of host line 1 - config_state_hostlane2 = 1*255VCHAR ; configuration status for the data path of host line 2 - config_state_hostlane3 = 1*255VCHAR ; configuration status for the data path of host line 3 - config_state_hostlane4 = 1*255VCHAR ; configuration status for the data path of host line 4 - config_state_hostlane5 = 1*255VCHAR ; configuration status for the data path of host line 5 - config_state_hostlane6 = 1*255VCHAR ; configuration status for the data path of host line 6 - config_state_hostlane7 = 1*255VCHAR ; configuration status for the data path of host line 7 - config_state_hostlane8 = 1*255VCHAR ; configuration status for the data path of host line 8 - dpinit_pending_hostlane1 = BOOLEAN ; data path configuration updated on host lane 1 - dpinit_pending_hostlane2 = BOOLEAN ; data path configuration updated on host lane 2 - dpinit_pending_hostlane3 = BOOLEAN ; data path configuration updated on host lane 3 - dpinit_pending_hostlane4 = BOOLEAN ; data path configuration updated on host lane 4 - dpinit_pending_hostlane5 = BOOLEAN ; data path configuration updated on host lane 5 - dpinit_pending_hostlane6 = BOOLEAN ; data path configuration updated on host lane 6 - dpinit_pending_hostlane7 = BOOLEAN ; data path configuration updated on host lane 7 - dpinit_pending_hostlane8 = BOOLEAN ; data path configuration updated on host lane 8 - temphighalarm_flag = BOOLEAN ; temperature high alarm flag - temphighwarning_flag = BOOLEAN ; temperature high warning flag - templowalarm_flag = BOOLEAN ; temperature low alarm flag - templowwarning_flag = BOOLEAN ; temperature low warning flag - vcchighalarm_flag = BOOLEAN ; vcc high alarm flag - vcchighwarning_flag = BOOLEAN ; vcc high warning flag - vcclowalarm_flag = BOOLEAN ; vcc low alarm flag - vcclowwarning_flag = BOOLEAN ; vcc low warning flag - txpowerhighalarm_flag = BOOLEAN ; tx power high alarm flag - txpowerlowalarm_flag = BOOLEAN ; tx power low alarm flag - txpowerhighwarning_flag = BOOLEAN ; tx power high warning flag - txpowerlowwarning_flag = BOOLEAN ; tx power low alarm flag - rxpowerhighalarm_flag = BOOLEAN ; rx power high alarm flag - rxpowerlowalarm_flag = BOOLEAN ; rx power low alarm flag - rxpowerhighwarning_flag = BOOLEAN ; rx power high warning flag - rxpowerlowwarning_flag = BOOLEAN ; rx power low warning flag - txbiashighalarm_flag = BOOLEAN ; tx bias high alarm flag - txbiaslowalarm_flag = BOOLEAN ; tx bias low alarm flag - txbiashighwarning_flag = BOOLEAN ; tx bias high warning flag - txbiaslowwarning_flag = BOOLEAN ; tx bias low warning flag - lasertemphighalarm_flag = BOOLEAN ; laser temperature high alarm flag - lasertemplowalarm_flag = BOOLEAN ; laser temperature low alarm flag - lasertemphighwarning_flag = BOOLEAN ; laser temperature high warning flag - lasertemplowwarning_flag = BOOLEAN ; laser temperature low warning flag - prefecberhighalarm_flag = BOOLEAN ; prefec ber high alarm flag - prefecberlowalarm_flag = BOOLEAN ; prefec ber low alarm flag - prefecberhighwarning_flag = BOOLEAN ; prefec ber high warning flag - prefecberlowwarning_flag = BOOLEAN ; prefec ber low warning flag - postfecberhighalarm_flag = BOOLEAN ; postfec ber high alarm flag - postfecberlowalarm_flag = BOOLEAN ; postfec ber low alarm flag - postfecberhighwarning_flag = BOOLEAN ; postfec ber high warning flag - postfecberlowwarning_flag = BOOLEAN ; postfec ber low warning flag - ================================================================================ - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_transceiver_pm(self): - """ - Retrieves PM (Performance Monitoring) info for this xcvr (applicable for C-CMIS) - - Returns: - A dict containing the following keys/values : - ======================================================================== - key = TRANSCEIVER_PM|ifname ; information of PM on port - ; field = value - prefec_ber_avg = FLOAT ; prefec ber avg - prefec_ber_min = FLOAT ; prefec ber min - prefec_ber_max = FLOAT ; prefec ber max - uncorr_frames_avg = FLOAT ; uncorrected frames ratio avg - uncorr_frames_min = FLOAT ; uncorrected frames ratio min - uncorr_frames_max = FLOAT ; uncorrected frames ratio max - cd_avg = FLOAT ; chromatic dispersion avg - cd_min = FLOAT ; chromatic dispersion min - cd_max = FLOAT ; chromatic dispersion max - dgd_avg = FLOAT ; differential group delay avg - dgd_min = FLOAT ; differential group delay min - dgd_max = FLOAT ; differential group delay max - sopmd_avg = FLOAT ; second order polarization mode dispersion avg - sopmd_min = FLOAT ; second order polarization mode dispersion min - sopmd_max = FLOAT ; second order polarization mode dispersion max - pdl_avg = FLOAT ; polarization dependent loss avg - pdl_min = FLOAT ; polarization dependent loss min - pdl_max = FLOAT ; polarization dependent loss max - osnr_avg = FLOAT ; optical signal to noise ratio avg - osnr_min = FLOAT ; optical signal to noise ratio min - osnr_max = FLOAT ; optical signal to noise ratio max - esnr_avg = FLOAT ; electrical signal to noise ratio avg - esnr_min = FLOAT ; electrical signal to noise ratio min - esnr_max = FLOAT ; electrical signal to noise ratio max - cfo_avg = FLOAT ; carrier frequency offset avg - cfo_min = FLOAT ; carrier frequency offset min - cfo_max = FLOAT ; carrier frequency offset max - soproc_avg = FLOAT ; state of polarization rate of change avg - soproc_min = FLOAT ; state of polarization rate of change min - soproc_max = FLOAT ; state of polarization rate of change max - tx_power_avg = FLOAT ; tx output power avg - tx_power_min = FLOAT ; tx output power min - tx_power_max = FLOAT ; tx output power max - rx_tot_power_avg = FLOAT ; rx total power avg - rx_tot_power_min = FLOAT ; rx total power min - rx_tot_power_max = FLOAT ; rx total power max - rx_sig_power_avg = FLOAT ; rx signal power avg - rx_sig_power_min = FLOAT ; rx signal power min - rx_sig_power_max = FLOAT ; rx signal power max - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_rx_los(self): - """ - Retrieves the RX LOS (loss-of-signal) status of this xcvr - - Returns: - A list of boolean values, representing the RX LOS status - of each available channel, value is True if xcvr channel - has RX LOS, False if not. - E.g., for a tranceiver with four channels: [False, False, True, False] - - If Rx LOS status is unsupported on the xcvr, each list element should be "N/A" instead. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_tx_fault(self): - """ - Retrieves the TX fault status of this xcvr - - Returns: - A list of boolean values, representing the TX fault status - of each available channel, value is True if xcvr channel - has TX fault, False if not. - E.g., for a tranceiver with four channels: [False, False, True, False] - - If TX fault status is unsupported on the xcvr, each list element should be "N/A" instead. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_tx_disable(self): - """ - Retrieves the tx_disable status of this xcvr - - Returns: - A list of boolean values, representing the TX disable status - of each available channel, value is True if xcvr channel - is TX disabled, False if not. - E.g., for a tranceiver with four channels: [False, False, True, False] - - If TX disable status is unsupported on the xcvr, each list element should be "N/A" instead. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_tx_disable_channel(self): - """ - Retrieves the TX disabled channels in this xcvr - - 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 xcvr. - As an example, a returned value of 0x5 indicates that channel 0 - and channel 2 have been disabled. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_module_temperature(self): - """ - Retrieves the temperature of this xcvr - - Returns: - A float representing the current temperature in Celsius, or "N/A" if temperature - measurements are unsupported on the xcvr. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_voltage(self): - """ - Retrieves the supply voltage of this xcvr - - Returns: - A float representing the supply voltage in mV, or "N/A" if voltage measurements are - unsupported on the xcvr. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_tx_bias(self): - """ - Retrieves the TX bias current of all xcvr channels - - Returns: - A list of floats, representing TX bias in mA - for each available channel - E.g., for a tranceiver with four channels: ['110.09', '111.12', '108.21', '112.09'] - - If TX bias is unsupported on the xcvr, each list element should be "N/A" instead. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_rx_power(self): - """ - Retrieves the received optical power of all xcvr channels - - Returns: - A list of floats, representing received optical - power in mW for each available channel - E.g., for a tranceiver with four channels: ['1.77', '1.71', '1.68', '1.70'] - - If RX power is unsupported on the xcvr, each list element should be "N/A" instead. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_tx_power(self): - """ - Retrieves the TX power of all xcvr channels - - Returns: - A list of floats, representing TX power in mW - for each available channel - E.g., for a tranceiver with four channels: ['1.86', '1.86', '1.86', '1.86'] - - If TX power is unsupported on the xcvr, each list element should be "N/A" instead. - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def tx_disable(self, tx_disable): - """ - Disable xcvr 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 - """ - raise NotImplementedError - - def tx_disable_channel(self, channel, disable): - """ - Sets the tx_disable for specified xcvr 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 - """ - raise NotImplementedError - - def get_power_override(self): - """ - Retrieves the power-override status of this xcvr - - Returns: - A boolean, True if power-override is enabled, False if disabled - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def set_power_override(self, power_override, power_set): - """ - Sets xcvr power level using power_override and power_set - - Args: - power_override : - A Boolean, True to override set_lpmode and use power_set - to control xcvr power, False to disable xcvr power control - through power_override/power_set and use set_lpmode - to control xcvr power. - power_set : - Only valid when power_override is True. - A Boolean, True to set xcvr to low power mode, False to set - xcvr to high power mode. - - Returns: - A boolean, True if power-override and power_set are set successfully, - False if not - """ - raise NotImplementedError - - def is_flat_memory(self): - """ - Determines whether the xcvr's memory map is flat or paged - - Returns: - A Boolean, True if flat memory, False if paging is implemented - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_tx_power_support(self): - """ - Retrieves the tx power measurement capability of this xcvr - - Returns: - A Boolean, True if tx power measurement is supported, False otherwise - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_rx_power_support(self): - """ - Retrieves the tx power measurement capability of this xcvr - - Returns: - A Boolean, True if tx power measurement is supported, False otherwise - """ - raise NotImplementedError - - def is_copper(self): - """ - Returns: - A Boolean, True if xcvr is copper, False if optical - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_temperature_support(self): - """ - Retrieves the temperature measurement capability of this xcvr - - Returns: - A Boolean, True if module temperature is supported, False otherwise - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_voltage_support(self): - """ - Retrieves the temperature measurement capability of this xcvr - - Returns: - A Boolean, True if module voltage measurement is supported, False otherwise - - If there is an issue with reading the xcvr, None should be returned. - """ - raise NotImplementedError - - def get_rx_los_support(self): - """ - Retrieves the RX LOS status reporting capability of this xcvr - - Returns: - A Boolean, True if xcvr reports RX LOS status, False otherwise - """ - raise NotImplementedError - - def get_tx_bias_support(self): - """ - Retrieves the TX bias measurement capability of this xcvr - - Returns: - A Boolean, True if TX bias is supported, False otherwise - """ - raise NotImplementedError - - def get_tx_fault_support(self): - """ - Retrieves the TX fault status reporting capability of this xcvr - - Returns: - A Boolean, True if xcvr reports TX fault, False otherwise - """ - raise NotImplementedError - - def get_tx_disable_support(self): - """ - Retrieves the TX disable capability of this xcvr - - Returns: - A Boolean, True if Tx can be disabled, False otherwise - """ - raise NotImplementedError - - def get_transceiver_thresholds_support(self): - """ - Retrieves the thresholds reporting capability by this xcvr - - Returns: - A Boolean, True if thresholds are supported, False otherwise - """ - raise NotImplementedError - - def get_lpmode_support(self): - """ - Retrieves the lpmode support of this xcvr - - Returns: - A Boolean, True if lpmode is supported, False otherwise - """ - raise NotImplementedError - - def get_power_override_support(self): - """ - Retrieves the power override support of this xcvr - - Returns: - A Boolean, True if power override is supported, False otherwise - """ - raise NotImplementedError - - def get_module_fw_info(self): - """ - Retrieves the firmware information of this xcvr. - - Returns: - A dict containing the following keys/values: - ================================================================================ - keys |Value Format |Information - ---------------------------|---------------|---------------------------- - status |bool |status of operation - info |string |human readable representation of firmware information - result |tuple |firmware information - """ - raise NotImplementedError - - def get_error_description(self): - """ - Retrives the error descriptions of the SFP module - - Returns: - String that represents the current error descriptions of vendor specific errors - In case there are multiple errors, they should be joined by '|', - like: "Bad EEPROM|Unsupported cable" - """ - raise NotImplementedError - diff --git a/sonic_platform_base/sonic_xcvr/codes/__init__.py b/sonic_platform_base/sonic_xcvr/codes/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/codes/public/__init__.py b/sonic_platform_base/sonic_xcvr/codes/public/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/codes/public/cmis.py b/sonic_platform_base/sonic_xcvr/codes/public/cmis.py deleted file mode 100644 index 7ad35610a..000000000 --- a/sonic_platform_base/sonic_xcvr/codes/public/cmis.py +++ /dev/null @@ -1,149 +0,0 @@ -from .sff8024 import Sff8024 - -class CmisCodes(Sff8024): - POWER_CLASSES = { - 0: "Power Class 1", - 1: "Power Class 2", - 2: "Power Class 3", - 3: "Power Class 4", - 4: "Power Class 5", - 5: "Power Class 6", - 6: "Power Class 7", - 7: "Power Class 8" - } - - MEDIA_INTERFACE_TECH = { - 0: '850 nm VCSEL', - 1: '1310 nm VCSEL', - 2: '1550 nm VCSEL', - 3: '1310 nm FP', - 4: '1310 nm DFB', - 5: '1550 nm DFB', - 6: '1310 nm EML', - 7: '1550 nm EML', - 8: 'Others', - 9: '1490 nm DFB', - 10: 'Copper cable unequalized', - 11: 'Copper cable passive equalized', - 12: 'Copper cable, near and far end limiting active equalizers', - 13: 'Copper cable, far end limiting active equalizers', - 14: 'Copper cable, near end limiting active equalizers', - 15: 'Copper cable, linear active equalizers', - 16: 'C-band tunable laser', - 17: 'L-band tunable laser', - } - - MODULE_STATE = { - 1: 'ModuleLowPwr', - 2: 'ModulePwrUp', - 3: 'ModuleReady', - 4: 'ModulePwrDn', - 5: 'ModuleFault', - } - - MODULE_FAULT_CAUSE = { - 0: 'No Fault detected', - 1: 'TEC runawawy', - 2: 'Data memory corrupted', - 3: 'Program memory corrupted', - } - - DATAPATH_STATE = { - 1: 'DataPathDeactivated', - 2: 'DataPathInit', - 3: 'DataPathDeinit', - 4: 'DataPathActivated', - 5: 'DataPathTxTurnOn', - 6: 'DataPathTxTurnOff', - 7: 'DataPathInitialized', - } - - CONFIG_STATUS = { - 0: 'ConfigUndefined', - 1: 'ConfigSuccess', - 2: 'ConfigRejected', - 3: 'ConfigRejectedInvalidAppSel', - 4: 'ConfigRejectedInvalidDataPath', - 5: 'ConfigRejectedInvalidSI', - 6: 'ConfigRejectedLaneInUse', - 7: 'ConfigRejectedPartialDataPath', - 12: 'ConfigInProgress', - } - - VDM_TYPE = { - # VDM_ID: [VDM_NAME, DATA_TYPE, SCALE] - 1: ['Laser Age [%]', 'U16', 1], - 2: ['TEC Current [%]', 'S16', 100.0/32767], - 3: ['Laser Frequency Error [MHz]', 'S16', 10], - 4: ['Laser Temperature [C]', 'S16', 1.0/256], - 5: ['eSNR Media Input [dB]', 'U16', 1.0/256], - 6: ['eSNR Host Input [dB]', 'U16', 1.0/256], - 7: ['PAM4 Level Transition Parameter Media Input [dB]', 'U16', 1.0/256], - 8: ['PAM4 Level Transition Parameter Host Input [dB]', 'U16', 1.0/256], - 9: ['Pre-FEC BER Minimum Media Input', 'F16', 1], - 10: ['Pre-FEC BER Minimum Host Input', 'F16', 1], - 11: ['Pre-FEC BER Maximum Media Input', 'F16', 1], - 12: ['Pre-FEC BER Maximum Host Input', 'F16', 1], - 13: ['Pre-FEC BER Average Media Input', 'F16', 1], - 14: ['Pre-FEC BER Average Host Input', 'F16', 1], - 15: ['Pre-FEC BER Current Value Media Input', 'F16', 1], - 16: ['Pre-FEC BER Current Value Host Input', 'F16', 1], - 17: ['Errored Frames Minimum Media Input', 'F16', 1], - 18: ['Errored Frames Minimum Host Input', 'F16', 1], - 19: ['Errored Frames Maximum Media Input', 'F16', 1], - 20: ['Errored Frames Maximum Host Input', 'F16', 1], - 21: ['Errored Frames Average Media Input', 'F16', 1], - 22: ['Errored Frames Average Host Input', 'F16', 1], - 23: ['Errored Frames Current Value Media Input', 'F16', 1], - 24: ['Errored Frames Current Value Host Input', 'F16', 1], - 128: ['Modulator Bias X/I [%]', 'U16', 100.0/65535], - 129: ['Modulator Bias X/Q [%]', 'U16', 100.0/65535], - 130: ['Modulator Bias Y/I [%]', 'U16', 100.0/65535], - 131: ['Modulator Bias Y/Q [%]', 'U16', 100.0/65535], - 132: ['Modulator Bias X_Phase [%]', 'U16', 100.0/65535], - 133: ['Modulator Bias Y_Phase [%]', 'U16', 100.0/65535], - 134: ['CD high granularity, short link [ps/nm]', 'S16', 1], - 135: ['CD low granularity, long link [ps/nm]', 'S16', 20], - 136: ['DGD [ps]', 'U16', 0.01], - 137: ['SOPMD [ps^2]', 'U16', 0.01], - 138: ['PDL [dB]', 'U16', 0.1], - 139: ['OSNR [dB]', 'U16', 0.1], - 140: ['eSNR [dB]', 'U16', 0.1], - 141: ['CFO [MHz]', 'S16', 1], - 142: ['EVM_modem [%]', 'U16', 100.0/65535], - 143: ['Tx Power [dBm]', 'S16', 0.01], - 144: ['Rx Total Power [dBm]', 'S16', 0.01], - 145: ['Rx Signal Power [dBm]', 'S16', 0.01], - 146: ['SOP ROC [krad/s]', 'U16', 1], - 147: ['MER [dB]', 'U16', 0.1] - } - - CDB_FAIL_STATUS = { - 0: 'reserved', - 1: 'CMDID unknown', - 2: 'Parameter range error or parameter not supported', - 3: 'Previous CMD was not properly ABORTED', - 4: 'Command checking time out', - 5: 'CdbChkCode Error', - 6: 'Password related error', - 7: 'Command not compatible with operating status' - } - - DP_PATH_TIMINGS = { - 0: '1', - 1: '5', - 2: '10', - 3: '50', - 4: '100', - 5: '500', - 6: '1000', - 7: '5000', - 8: '10000', - 9: '60000', - 10: '300000', - 11: '600000', - 12: '3000000', - 13: '6000000', - } - - # TODO: Add other codes diff --git a/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py b/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py deleted file mode 100644 index 73f6529fc..000000000 --- a/sonic_platform_base/sonic_xcvr/codes/public/sff8024.py +++ /dev/null @@ -1,369 +0,0 @@ -""" - sff8024.py - - Implementation of SFF-8024 Rev 4.8a -""" - -from ..xcvr_codes import XcvrCodes - -class Sff8024(XcvrCodes): - XCVR_IDENTIFIERS = { - 0: 'Unknown or unspecified', - 1: 'GBIC', - 2: 'Module/connector soldered to motherboard', - 3: 'SFP/SFP+/SFP28', - 4: '300 pin XBI', - 5: 'XENPAK', - 6: 'XFP', - 7: 'XFF', - 8: 'XFP-E', - 9: 'XPAK', - 10: 'X2', - 11: 'DWDM-SFP/SFP+', - 12: 'QSFP', - 13: 'QSFP+ or later with SFF-8636 or SFF-8436', - 14: 'CXP or later', - 15: 'Shielded Mini Multilane HD 4X', - 16: 'Shielded Mini Multilane HD 8X', - 17: 'QSFP28 or later', - 18: 'CXP2 (aka CXP28) or later', - 19: 'CDFP (Style 1/Style2)', - 20: 'Shielded Mini Multilane HD 4X Fanout Cable', - 21: 'Shielded Mini Multilane HD 8X Fanout Cable', - 22: 'CDFP (Style 3)', - 23: 'microQSFP', - 24: 'QSFP-DD Double Density 8X Pluggable Transceiver', - 25: 'OSFP 8X Pluggable Transceiver', - 26: 'SFP-DD Double Density 2X Pluggable Transceiver', - 27: 'DSFP Dual Small Form Factor Pluggable Transceiver', - 28: 'x4 MiniLink/OcuLink', - 29: 'x8 MiniLink', - 30: 'QSFP+ or later with CMIS' - } - - XCVR_IDENTIFIER_ABBRV = { - 0: 'Unknown', - 1: 'GBIC', - 2: 'Soldered', - 3: 'SFP', - 4: 'XBI300', - 5: 'XENPAK', - 6: 'XFP', - 7: 'XFF', - 8: 'XFP-E', - 9: 'XPAK', - 10: 'X2', - 11: 'DWDM-SFP', - 12: 'QSFP', - 13: 'QSFP+', - 14: 'CXP', - 15: 'HD4X', - 16: 'HD8X', - 17: 'QSFP28', - 18: 'CXP2', - 19: 'CDFP-1/2', - 20: 'HD4X-Fanout', - 21: 'HD8X-Fanout', - 22: 'CDFP-3', - 23: 'MicroQSFP', - 24: 'QSFP-DD', - 25: 'OSFP-8X', - 26: 'SFP-DD', - 27: 'DSFP', - 28: 'Link-x4', - 29: 'Link-x8', - 30: 'QSFP+C' - } - - CONNECTORS = { - 0: 'Unknown or unspecified', - 1: 'SC', - 2: 'FC Style 1 copper connector', - 3: 'FC Style 2 copper connector', - 4: 'BNC/TNC', - 5: 'FC coax headers', - 6: 'Fiberjack', - 7: 'LC', - 8: 'MT-RJ', - 9: 'MU', - 10: 'SG', - 11: 'Optical Pigtail', - 12: 'MPO 1x12', - 13: 'MPO 2x16', - 32: 'HSSDC II', - 33: 'Copper pigtail', - 34: 'RJ45', - 35: 'No separable connector', - 36: 'MXC 2x16', - 37: 'CS optical connector', - 38: 'SN optical connector', - 39: 'MPO 2x12', - 40: 'MPO 1x16' - } - - ENCODINGS = { - 0: "Unspecified", - 1: "8B/10B", - 2: "4B/5B", - 3: "NRZ", - # 4-6 differ between 8472 and 8436/8636 - 7: "256B/257B (transcoded FEC-enabled data)", - 8: "PAM4" - } - - EXT_SPEC_COMPLIANCE = { - 0: 'Unspecified', - 1: '100G AOC (Active Optical Cable) or 25GAUI C2M AOC', - 2: '100GBASE-SR4 or 25GBASE-SR', - 3: '100GBASE-LR4 or 25GBASE-LR', - 4: '100GBASE-ER4 or 25GBASE-ER', - 5: '100GBASE-SR10', - 6: '100G CWDM4', - 7: '100G PSM4 Parallel SMF', - 8: '100G ACC (Active Copper Cable) or 25GAUI C2M ACC', - 9: 'Obsolete (assigned before 100G CWDM4 MSA required FEC)', - 11: '100GBASE-CR4, 25GBASE-CR CA-25G-L or 50GBASE-CR2 with RS', - 12: '25GBASE-CR CA-25G-S or 50GBASE-CR2 with BASE-R', - 13: '25GBASE-CR CA-25G-N or 50GBASE-CR2 with no FEC', - 14: '10 Mb/s Single Pair Ethernet', - 16: '40GBASE-ER4', - 17: '4 x 10GBASE-SR', - 18: '40G PSM4 Parallel SMF', - 19: 'G959.1 profile P1I1-2D1 (10709 MBd, 2km, 1310 nm SM)', - 20: 'G959.1 profile P1S1-2D2 (10709 MBd, 40km, 1550 nm SM)', - 21: 'G959.1 profile P1L1-2D2 (10709 MBd, 80km, 1550 nm SM)', - 22: '10GBASE-T with SFI electrical interface', - 23: '100G CLR4', - 24: '100G AOC or 25GAUI C2M AOC', - 25: '100G ACC or 25GAUI C2M ACC', - 26: '100GE-DWDM2', - 27: '100G 1550nm WDM', - 28: '10GBASE-T Short Reach', - 29: '5GBASE-T', - 30: '2.5GBASE-T', - 31: '40G SWDM4', - 32: '100G SWDM4', - 33: '100G PAM4 BiDi', - 34: '4WDM-10 MSA', - 35: '4WDM-20 MSA', - 36: '4WDM-40 MSA', - 37: '100GBASE-DR', - 38: '100G-FR or 100GBASE-FR1', - 39: '100G-LR or 100GBASE-LR1', - 40: '100G-SR1', - 41: '100GBASE-SR1, 200GBASE-SR2 or 400GBASE-SR4', - 42: '100GBASE-FR1', - 43: '100GBASE-LR1', - 48: 'Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below', - 49: 'Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below', - 50: 'Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below', - 51: 'Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for AOC, 10-5 for AUI, or below', - 63: '100GBASE-CR1, 200GBASE-CR2 or 400GBASE-CR4', - 64: '50GBASE-CR, 100GBASE-CR2, or 200GBASE-CR4', - 65: '50GBASE-SR, 100GBASE-SR2, or 200GBASE-SR4', - 66: '50GBASE-FR or 200GBASE-DR4', - 67: '200GBASE-FR4', - 68: '200G 1550 nm PSM4', - 69: '50GBASE-LR', - 70: '200GBASE-LR4', - 71: '400GBASE-DR4, 100GAUI-1 C2M', - 72: '400GBASE-FR4', - 73: '400GBASE-LR4-6', - 127: '256GFC-SW4', - 128: 'Capable of 64GFC', - 129: 'Capable of 128GFC' - } - - MODULE_MEDIA_TYPE = { - 0: 'Undefined', - 1: 'nm_850_media_interface', - 2: 'sm_media_interface', - 3: 'passive_copper_media_interface', - 4: 'active_cable_media_interface', - 5: 'base_t_media_interface' - } - - HOST_ELECTRICAL_INTERFACE = { - 0: 'Undefined', - 1: '1000BASE -CX(Clause 39)', - 2: 'XAUI(Clause 47)', - 3: 'XFI (SFF INF-8071i)', - 4: 'SFI (SFF-8431)', - 5: '25GAUI C2M (Annex 109B)', - 6: 'XLAUI C2M (Annex 83B)', - 7: 'XLPPI (Annex 86A)', - 8: 'LAUI-2 C2M (Annex 135C)', - 9: '50GAUI-2 C2M (Annex 135E)', - 10: '50GAUI-1 C2M (Annex 135G)', - 11: 'CAUI-4 C2M (Annex 83E)', - 12: '100GAUI-4 C2M (Annex 135E)', - 13: '100GAUI-2 C2M (Annex 135G)', - 14: '200GAUI-8 C2M (Annex 120C)', - 15: '200GAUI-4 C2M (Annex 120E)', - 16: '400GAUI-16 C2M (Annex 120C)', - 17: '400GAUI-8 C2M (Annex 120E)', - 19: '10GBASE-CX4 (Clause 54)', - 20: '25GBASE-CR CA-L (Clause 110)', - 21: '25GBASE-CR CA-S (Clause 110)', - 22: '25GBASE-CR CA-N (Clause 110)', - 23: '40GBASE-CR4 (Clause 85)', - 24: '50GBASE-CR (Clause 126)', - 25: '100GBASE-CR10 (Clause 85)', - 26: '100GBASE-CR4 (Clause 92)', - 27: '100GBASE-CR2 (Clause 136)', - 28: '200GBASE-CR4 (Clause 136)', - 29: '400G CR8', - 30: '1000BASE-T (Clause 40)', - 31: '2.5GBASE-T (Clause 126)', - 32: '5GBASE-T (Clause 126)', - 33: '10GBASE-T (Clause 55)', - 34: '25GBASE-T (Clause 113)', - 35: '40GBASE-T (Clause 113)', - 36: '50GBASE-T (Placeholder)', - 37: '8GFC (FC-PI-4)', - 38: '10GFC (10GFC)', - 39: '16GFC (FC-PI-5)', - 40: '32GFC (FC-PI-6)', - 41: '64GFC (FC-PI-7)', - 42: '128GFC (FC-PI-6P)', - 43: '256GFC (FC-PI-7P)', - 44: 'IB SDR (Arch.Spec.Vol.2)', - 45: 'IB DDR (Arch.Spec.Vol.2)', - 46: 'IB QDR (Arch.Spec.Vol.2)', - 47: 'IB FDR (Arch.Spec.Vol.2)', - 48: 'IB EDR (Arch.Spec.Vol.2)', - 49: 'IB HDR (Arch.Spec.Vol.2)', - 50: 'IB NDR', - 51: 'E.96 (CPRI Specification V7.0)', - 52: 'E.99 (CPRI Specification V7.0)', - 53: 'E.119 (CPRI Specification V7.0)', - 54: 'E.238 (CPRI Specification V7.0)', - 55: 'OTL3.4 (ITU-T G.709/Y.1331 G.Sup58)', - 56: 'OTL4.10 (ITU-T G.709/Y.1331 G.Sup58)', - 57: 'OTL4.4 (ITU-T G.709/Y.1331 G.Sup58)', - 58: 'OTLC.4 (ITU-T G.709.1/Y.1331 G.Sup58)', - 59: 'FOIC1.4 (ITU-T G.709.1/Y.1331 G.Sup58)', - 60: 'FOIC1.2 (ITU-T G.709.1/Y.1331 G.Sup58)', - 61: 'FOIC2.8 (ITU-T G.709.1/Y.1331 G.Sup58)', - 62: 'FOIC2.4 (ITU-T G.709.1/Y.1331 G.Sup58)', - 63: 'FOIC4.16 (ITU-T G.709.1 G.Sup58)', - 64: 'FOIC4.8 (ITU-T G.709.1 G.Sup58)' - } - - NM_850_MEDIA_INTERFACE = { - 0: 'Undefined', - 1: '10GBASE-SW (Clause 52)', - 2: '10GBASE-SR (Clause 52)', - 3: '25GBASE-SR (Clause 112)', - 4: '40GBASE-SR4 (Clause 86)', - 5: '40GE SWDM4 MSA Spec', - 6: '40GE BiDi', - 7: '50GBASE-SR (Clause 138)', - 8: '100GBASE-SR10 (Clause 86)', - 9: '100GBASE-SR4 (Clause 95)', - 10: '100GE SWDM4 MSA Spec', - 11: '100GE BiDi', - 12: '100GBASE-SR2 (Clause 138)', - 13: '100G-SR (Placeholder)', - 14: '200GBASE-SR4 (Clause 138)', - 15: '400GBASE-SR16 (Clause 123)', - 16: '400GBASE-SR8 (Clause 138)', - 17: '400G-SR4 (Placeholder)', - 18: '800G-SR8 (Placeholder)', - 26: '400GBASE-SR4.2 (Clause 150) (400GE BiDi)', - 19: '8GFC-MM (FC-PI-4)', - 20: '10GFC-MM (10GFC)', - 21: '16GFC-MM (FC-PI-5)', - 22: '32GFC-MM (FC-PI-6)', - 23: '64GFC-MM (FC-PI 7)', - 24: '128GFC-MM4 (FC-PI-6P)', - 25: '256GFC-MM4 (FC-PI-7P)' - } - - SM_MEDIA_INTERFACE = { - 0: 'Undefined', - 1: '10GBASE-LW (Cl 52)', - 2: '10GBASE-EW (Cl 52)', - 3: '10G-ZW', - 4: '10GBASE-LR (Cl 52)', - 5: '10GBASE-ER (Cl 52)', - 6: '10G-ZR', - 7: '25GBASE-LR (Cl 114)', - 8: '25GBASE-ER (Cl 114)', - 9: '40GBASE-LR4 (Cl 87)', - 10: '40GBASE-FR (Cl 89)', - 11: '50GBASE-FR (Cl 139)', - 12: '50GBASE-LR (Cl 139)', - 13: '100GBASE-LR4 (Cl 88)', - 14: '100GBASE-ER4 (Cl 88)', - 15: '100G PSM4 MSA Spec', - 16: '100G CWDM4 MSA Spec', - 17: '100G 4WDM-10 MSA Spec', - 18: '100G 4WDM-20 MSA Spec', - 19: '100G 4WDM-40 MSA Spec', - 20: '100GBASE-DR (Cl 140)', - 21: '100G-FR/100GBASE-FR1 (Cl 140)', - 22: '100G-LR/100GBASE-LR1 (Cl 140)', - 23: '200GBASE-DR4 (Cl 121)', - 24: '200GBASE-FR4 (Cl 122)', - 25: '200GBASE-LR4 (Cl 122)', - 26: '400GBASE-FR8 (Cl 122)', - 27: '400GBASE-LR8 (Cl 122)', - 28: '400GBASE-DR4 (Cl 124)', - 29: '400G-FR4/400GBASE-FR4 (Cl 151)', - 30: '400G-LR4-10', - 31: '8GFC-SM (FC-PI-4)', - 32: '10GFC-SM (10GFC)', - 33: '16GFC-SM (FC-PI-5)', - 34: '32GFC-SM (FC-PI-6)', - 35: '64GFC-SM (FC-PI-7)', - 36: '128GFC-PSM4 (FC-PI-6P)', - 37: '256GFC-PSM4 (FC-PI-7P)', - 38: '128GFC-CWDM4 (FC-PI-6P)', - 39: '256GFC-CWDM4 (FC-PI-7P)', - 44: '4I1-9D1F (G.959.1)', - 45: '4L1-9C1F (G.959.1)', - 46: '4L1-9D1F (G.959.1)', - 47: 'C4S1-9D1F (G.695)', - 48: 'C4S1-4D1F (G.695)', - 49: '4I1-4D1F (G.959.1)', - 50: '8R1-4D1F (G.959.1)', - 51: '8I1-4D1F (G.959.1)', - 56: '10G-SR', - 57: '10G-LR', - 58: '25G-SR', - 59: '25G-LR', - 60: '10G-LR-BiDi', - 61: '25G-LR-BiDi', - 62: '400ZR, DWDM, amplified', - 63: '400ZR, Single Wavelength, Unamplified', - 70: 'ZR400-OFEC-16QAM', - 71: 'ZR300-OFEC-8QAM', - 72: 'ZR200-OFEC-QPSK', - 73: 'ZR100-OFEC-QPSK' - } - - PASSIVE_COPPER_MEDIA_INTERFACE = { - 0: 'Undefined', - 1: 'Copper cable', - 2: 'Passive Loopback module' - } - - ACTIVE_CABLE_MEDIA_INTERFACE = { - 0: 'Undefined', - 1: 'Active Cable assembly with BER < 10^-12', - 2: 'Active Cable assembly with BER < 5x10^-5', - 3: 'Active Cable assembly with BER < 2.6x10^-4', - 4: 'Active Cable assembly with BER < 10^-6', - 191: 'Active Loopback module' - } - - BASE_T_MEDIA_INTERFACE = { - 0: 'Undefined', - 1: '1000BASE-T (Clause 40)', - 2: '2.5GBASE-T (Clause 126)', - 3: '5GBASE-T (Clause 126)', - 4: '10GBASE-T (Clause 55)' - } - - # TODO: Add other codes diff --git a/sonic_platform_base/sonic_xcvr/codes/public/sff8436.py b/sonic_platform_base/sonic_xcvr/codes/public/sff8436.py deleted file mode 100644 index 3d3e041d2..000000000 --- a/sonic_platform_base/sonic_xcvr/codes/public/sff8436.py +++ /dev/null @@ -1,106 +0,0 @@ -from .sff8024 import Sff8024 - -class Sff8436Codes(Sff8024): - ENCODINGS = { - 0: "Unspecified", - 1: "8B/10B", - 2: "4B/5B", - 3: "NRZ", - 4: "SONET Scrambled", - 5: "64B/66B", - 6: "Manchester", - 7: "256B/257B (transcoded FEC-enabled data)", - 8: "PAM4", - } - - POWER_CLASSES = { - 0: "Power Class 1 Module (1.5W max. Power consumption)", - 1: "Power Class 2 Module (2.0W max. Power consumption)", - 2: "Power Class 3 Module (2.5W max. Power consumption)", - 3: "Power Class 4 Module (3.5W max. Power consumption)", - } - - CLEI_CODE = { - 0: "No CLEI code present in Page 02h", - 1: "CLEI code present in Page 02h" - } - - CDR_TX = { - 0: "No CDR in TX", - 1: "CDR present in TX" - } - - CDR_RX = { - 0: "No CDR in RX", - 1: "CDR present in RX" - } - - ETHERNET_10_40G_COMPLIANCE = { - 1: "40G Active Cable (XLPPI)", - 2: "40GBASE-LR4", - 4: "40GBASE-SR4", - 8: "40GBASE-CR4", - 16: "10GBASE-SR", - 32: "10GBASE-LR", - 64: "10GBASE-LRM" - } - - SONET_COMPLIANCE = { - 1: "OC 48 short reach", - 2: "OC 48, intermediate reach", - 4: "OC 48, long reach", - 16: "40G OTN (OTU3B/OTU3C)" - } - - SAS_SATA_COMPLIANCE = { - 8: "SAS 3.0G", - 16: "SAS 6.0G", - } - - GIGABIT_ETHERNET_COMPLIANCE = { - 1: "1000BASE-SX", - 2: "1000BASE-LX", - 4: "1000BASE-CX", - 8: "1000BASE-T" - } - - FIBRE_CHANNEL_LINK_LENGTH = { - 1: "Medium (M)", - 2: "Long distance (L)", - 4: "Intermediate distance (I)", - 8: "Short distance (S)", - 16: "Very long distance (V)" - } - - FIBRE_CHANNEL_TRANSMITTER_TECH = { - 1: "Longwave Laser (LL)", - 2: "Shortwave laser w OFC (SL)", - 4: "Shortwave laser w/o OFC (SN)", - 8: "Electrical intra-enclosure", - 16: "Electrical inter-enclosure (EN)", - 32: "Longwave laser (LC)" - } - - FIBRE_CHANNEL_TRANSMISSION_MEDIA = { - 1: "Single Mode (SM)", - 2: "Multi-mode 50 um (OM3)", - 4: "Multi-mode 50m (M5)", - 8: "Multi-mode 62.5m (M6)", - 16: "Video Coax (TV)", - 32: "Miniature Coax (MI)", - 64: "Shielded Twisted Pair (TP", - 128: "Twin Axial Pair (TW)" - } - - FIBRE_CHANNEL_SPEED = { - 1: "100 Mbytes/Sec", - 4: "200 Mbytes/Sec", - 16: "400 Mbytes/Sec", - 32: "1600 Mbytes/Sec", - 64: "800 Mbytes/Sec", - 128: "1200 Mbytes/Sec" - } - - EXT_RATESELECT_COMPLIANCE = { - 0: "QSFP+ Rate Select Version 1" - } diff --git a/sonic_platform_base/sonic_xcvr/codes/public/sff8472.py b/sonic_platform_base/sonic_xcvr/codes/public/sff8472.py deleted file mode 100644 index 832ae75e2..000000000 --- a/sonic_platform_base/sonic_xcvr/codes/public/sff8472.py +++ /dev/null @@ -1,143 +0,0 @@ -""" - sff8472.py - - SFF-8472 Rev 12.3 -""" - -from .sff8024 import Sff8024 - -class Sff8472Codes(Sff8024): - ENCODINGS = { - 0: "Unspecified", - 1: "8B/10B", - 2: "4B/5B", - 3: "NRZ", - 4: "Manchester", - 5: "SONET Scrambled", - 6: "64B/66B", - 7: "256B/257B (transcoded FEC-enabled data)", - 8: "PAM4", - } - - EXT_IDENTIFIERS = { - 0: "GBIC definition is not specified", - 1: "GBIC is compliant with MOD_DEF 1", - 2: "GBIC is compliant with MOD_DEF 2", - 3: "GBIC is compliant with MOD_DEF 3", - 4: "GBIC/SFP defined by two-wire interface ID", - 5: "GBIC is compliant with MOD_DEF 5", - 6: "GBIC is compliant with MOD_DEF 6", - 7: "GBIC is compliant with MOD_DEF 7" - } - - POWER_CLASSES = { - 0: "Power Class 1 Module (1.5W max.)", - 64: "Power Class 2 Module (2.0W max.)", - 128: "Power Class 3 Module (2.5W max.)", - 192: "Power Class 4 Module (3.5W max.)", - 193: "Power Class 5 Module (4.0W max.)", - 194: "Power Class 6 Module (4.5W max.)", - 195: "Power Class 7 Module (5.0W max.)", - 32: "Power Class 8 Module", - } - - ETHERNET_10G_COMPLIANCE = { - 1: "10GBASE-SR", - 2: "10GBASE-LR", - 4: "10GBASE-LRM", - 8: "10GBASE-ER", - } - - INFINIBAND_COMPLIANCE = { - 1: "1X Copper Passive", - 2: "1X Copper Active", - 4: "1X LX", - 8: "1X SX" - } - - ESCON_COMPLIANCE = { - 2: "ESCON MMF, 1310nm LED", - 1: "ESCON SMF, 1310nm Laser" - } - - SONET_COMPLIANCE = { - 1: "OC 3 short reach", - 2: "OC 3, single mode, intermediate reach", - 4: "OC 3, single mode, long reach", - 16: "OC 12, short reach", - 32: "OC 12, single mode, intermediate reach", - 64: "OC 12, single mode, long reach", - 256: "OC 48, short reach", - 512: "OC 48, intermediate reach", - 1024: "OC 48, long reach", - 2048: "SONET reach specifier bit 2", - 4096: "SONET reach specifier bit 1", - 8192: "OC 192, short reach" - } - - ETHERNET_COMPLIANCE = { - 1: "1000BASE-SX", - 2: "1000BASE-LX", - 4: "1000BASE-CX", - 8: "1000BASE-T", - 16: "100BASE-LX/LX10", - 32: "100BASE-FX", - 64: "BASE-BX10", - 128: "BASE-PX" - } - - FIBRE_CHANNEL_LINK_LENGTH = { - 1: "Medium (M)", - 2: "Long distance (L)", - 4: "Intermediate distance (I)", - 8: "Short distance (S)", - 16: "Very long distance (V)" - } - - FIBRE_CHANNEL_TRANSMITTER_TECH = { - 1: "Longwave Laser (LL)", - 2: "Shortwave laser w OFC (SL)", - 4: "Shortwave laser w/o OFC (SN)", - 8: "Electrical intra-enclosure (EL)", - 16: "Electrical inter-enclosure (EL)", - 32: "Longwave laser (LC)", - 64: "Shortwave laser, linear RX (SA)" - } - - SFP_CABLE_TECH = { - 4: "Passive Cable", - 8: "Active Cable" - } - - FIBRE_CHANNEL_TRANSMISSION_MEDIA = { - 1: "Single Mode (SM)", - 4: "Multi-mode 50m (M5, M5E)", - 8: "Multi-mode 62.5m (M6)", - 16: "Video Coax (TV)", - 32: "Miniature Coax (MI)", - 64: "Twisted Pair (TP", - 128: "Twin Axial Pair (TW)" - } - - FIBRE_CHANNEL_SPEED = { - 1: "100 MBytes/sec", - 2: "Extended", - 4: "200 MBytes/sec", - 8: "3200 MBytes/sec", - 16: "400 MBytes/sec", - 32: "1600 MBytes/sec", - 64: "800 MBytes/sec", - 128: "1200 MBytes/sec" - } - - RATE_IDENTIFIERS = { - 1: "SFF-8079 (4/2/1G Rate_Select & AS0/AS1)", - 2: "SFF-8431 (8/4/2G Rx Rate_Select only)", - 4: "SFF-8431 (8/4/2G Tx Rate_Select only)", - 6: "SFF-8431 (8/4/2G Independent Rx & Tx Rate_select)", - 8: "FC-PI-5 (16/8/4G Rx Rate_select only) High=16G only, Low=8G/4G", - 10: "FC-PI-5 (16/8/4G Independent Rx, Tx Rate_select) High=16G only, Low=8G/4G", - 12: "FC-PI-6 (32/16/8 Independent Rx, Tx Rate_select) High=32G only, Low=16G/8G", - 14: "10/8G Rx and Tx Rate_Select controlling the operation or locking modes of the internal signal conditioner, retimer or CDR", - 16: "FC-PI-7 (64/32/16 Independent Rx, Tx Rate_select) High=32GFC and 64GFC, Low=16GFC", - } diff --git a/sonic_platform_base/sonic_xcvr/codes/public/sff8636.py b/sonic_platform_base/sonic_xcvr/codes/public/sff8636.py deleted file mode 100644 index 3347bda92..000000000 --- a/sonic_platform_base/sonic_xcvr/codes/public/sff8636.py +++ /dev/null @@ -1,126 +0,0 @@ -from .sff8024 import Sff8024 - -class Sff8636Codes(Sff8024): - REV_COMPLIANCE = { - 0: "Unspecified", - 1: "SFF-8436 Rev 4.8 or earlier", - 2: "Includes functionality SFF-8436 Rev 4.8 and earlier, except this byte and Bytes 186-189 are as defined in this document", - 3: "SFF-8636 Rev 1.3 or earlier", - 4: "SFF-8636 Rev 1.4", - 5: "SFF-8636 Rev 1.5", - 6: "SFF-8636 Rev 2.0", - 7: "SFF-8636 Rev 2.5, 2.6, and 2.7", - 8: "SFF-8636 Rev 2.8, 2.9, and 2.10", - } - - ENCODINGS = { - 0: "Unspecified", - 1: "8B/10B", - 2: "4B/5B", - 3: "NRZ", - 4: "SONET Scrambled", - 5: "64B/66B", - 6: "Manchester", - 7: "256B/257B (transcoded FEC-enabled data)", - 8: "PAM4", - } - - POWER_CLASSES = { - 0: "Power Class 1 Module (1.5W max.)", - 64: "Power Class 2 Module (2.0W max.)", - 128: "Power Class 3 Module (2.5W max.)", - 192: "Power Class 4 Module (3.5W max.)", - 193: "Power Class 5 Module (4.0W max.)", - 194: "Power Class 6 Module (4.5W max.)", - 195: "Power Class 7 Module (5.0W max.)", - 32: "Power Class 8 Module", - } - - CLEI_CODE = { - 0: "No CLEI code present in Page 02h", - 1: "CLEI code present in Page 02h" - } - - CDR_TX = { - 0: "No CDR in TX", - 1: "CDR present in TX" - } - - CDR_RX = { - 0: "No CDR in RX", - 1: "CDR present in RX" - } - - ETHERNET_10_40G_COMPLIANCE = { - 1: "40G Active Cable (XLPPI)", - 2: "40GBASE-LR4", - 4: "40GBASE-SR4", - 8: "40GBASE-CR4", - 16: "10GBASE-SR", - 32: "10GBASE-LR", - 64: "10GBASE-LRM", - 128: "Extended", - } - - SONET_COMPLIANCE = { - 1: "OC 48 short reach", - 2: "OC 48, intermediate reach", - 4: "OC 48, long reach", - } - - SAS_SATA_COMPLIANCE = { - 16: "SAS 3.0G", - 32: "SAS 6.0G", - 64: "SAS 12.0G", - 128: "SAS 24.0G", - } - - GIGABIT_ETHERNET_COMPLIANCE = { - 1: "1000BASE-SX", - 2: "1000BASE-LX", - 4: "1000BASE-CX", - 8: "1000BASE-T" - } - - FIBRE_CHANNEL_LINK_LENGTH = { - 1: "Medium (M)", - 2: "Long distance (L)", - 4: "Intermediate distance (I)", - 8: "Short distance (S)", - 16: "Very long distance (V)" - } - - FIBRE_CHANNEL_TRANSMITTER_TECH = { - 1: "Longwave Laser (LL)", - 2: "Shortwave laser w OFC (SL)", - 4: "Shortwave laser w/o OFC (SN)", - 8: "Electrical intra-enclosure", - 16: "Electrical inter-enclosure (EN)", - 32: "Longwave laser (LC)" - } - - FIBRE_CHANNEL_TRANSMISSION_MEDIA = { - 1: "Single Mode (SM)", - 2: "Multi-mode 50 um (OM3)", - 4: "Multi-mode 50m (M5)", - 8: "Multi-mode 62.5m (M6)", - 16: "Video Coax (TV)", - 32: "Miniature Coax (MI)", - 64: "Shielded Twisted Pair (TP", - 128: "Twin Axial Pair (TW)" - } - - FIBRE_CHANNEL_SPEED = { - 1: "100 Mbytes/Sec", - 2: "Extended", - 4: "200 Mbytes/Sec", - 16: "400 Mbytes/Sec", - 32: "1600 Mbytes/Sec", - 64: "800 Mbytes/Sec", - 128: "1200 Mbytes/Sec" - } - - EXT_RATESELECT_COMPLIANCE = { - 1: "Rate Select Version 1", - 2: "Rate Select Version 2" - } diff --git a/sonic_platform_base/sonic_xcvr/codes/xcvr_codes.py b/sonic_platform_base/sonic_xcvr/codes/xcvr_codes.py deleted file mode 100644 index 27257beec..000000000 --- a/sonic_platform_base/sonic_xcvr/codes/xcvr_codes.py +++ /dev/null @@ -1,8 +0,0 @@ -""" - xcvr_codes.py - - Base class for representing codes used in xcvr memory maps -""" - -class XcvrCodes(object): - pass diff --git a/sonic_platform_base/sonic_xcvr/fields/__init__.py b/sonic_platform_base/sonic_xcvr/fields/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/fields/consts.py b/sonic_platform_base/sonic_xcvr/fields/consts.py deleted file mode 100644 index 0ee4b2386..000000000 --- a/sonic_platform_base/sonic_xcvr/fields/consts.py +++ /dev/null @@ -1,379 +0,0 @@ -# COMMON - -ID_FIELD = "Identifier" -ID_ABBRV_FIELD = "Identifier Abbreviation" - -STATUS_FIELD = "Status Indicators" -STATUS_IND_BITS_FIELD = "Status Indicator Bits" - -FLAT_MEM_FIELD = "Flat_mem" -CONNECTOR_FIELD = "Connector" - -DIAG_MON_TYPE_FIELD = "Diagnostic Monitoring Type" -DEVICE_TECH_FIELD = "Device Technology" -EXT_SPEC_COMPLIANCE_FIELD = "Extended Specification Compliance" - -LENGTH_SMF_KM_FIELD = "Length SMF (km)" -LENGTH_SMF_M_FIELD = "Length SMF (m)" -LENGTH_OM4_FIELD = "Length OM4" -LENGTH_OM3_FIELD = "Length OM3" -LENGTH_OM2_FIELD = "Length OM2" -LENGTH_OM1_FIELD = "Length OM1" - -MODULE_MONITORS_FIELD = "Module Monitors" - -RX_LOS_FIELD = "RxLOS" -RX_LOS_SUPPORT = "RxLOSSupported" -RX_POWER_FIELD = "RxPower" -RX_POWER_SUPPORT_FIELD = "RxPowerSupported" -RX_POWER_THRESHOLDS_FIELD = "RxPowerThresholds" -RX_POWER_HIGH_ALARM_FIELD = "RxPowerHighAlarm" -RX_POWER_LOW_ALARM_FIELD = "RxPowerLowAlarm" -RX_POWER_HIGH_WARNING_FIELD = "RxPowerHighWarning" -RX_POWER_LOW_WARNING_FIELD = "RxPowerLowWarning" - -TEMPERATURE_FIELD = "Temperature" -TEMP_SUPPORT_FIELD = "Temperature Monitoring Implemented" -TEMP_THRESHOLDS_FIELD = "TempThresholds" -TEMP_HIGH_ALARM_FIELD = "TempHighAlarm" -TEMP_LOW_ALARM_FIELD = "TempLowAlarm" -TEMP_HIGH_WARNING_FIELD = "TempHighWarning" -TEMP_LOW_WARNING_FIELD = "TempLowWarning" - -THRESHOLDS_FIELD = "Thresholds" - -TX_BIAS_FIELD = "TxBias" -TX_BIAS_SUPPORT_FIELD = "TxBiasSupported" -TX_BIAS_SCALE = "TxBiasScalingFactor" -TX_BIAS_THRESHOLDS_FIELD = "TxBiasThresholds" -TX_BIAS_HIGH_ALARM_FIELD = "TxHighAlarm" -TX_BIAS_LOW_ALARM_FIELD = "TxLowAlarm" -TX_BIAS_HIGH_WARNING_FIELD = "TxHighWarning" -TX_BIAS_LOW_WARNING_FIELD = "TxLowWarning" - -TX_FAULT_FIELD = "TxFault" -TX_FAULT_SUPPORT_FIELD = "TxFaultSupported" -TX_DISABLE_FIELD = "TxDisable" -TX_DISABLE_SUPPORT_FIELD = "TxDisableSupported" - -TX_POWER_FIELD = "TxPower" -TX_POWER_SUPPORT_FIELD = "TxPowerSupported" -TX_POWER_THRESHOLDS_FIELD = "TxPowerThresholds" -TX_POWER_HIGH_ALARM_FIELD = "TxPowerHighAlarm" -TX_POWER_LOW_ALARM_FIELD = "TxPowerLowAlarm" -TX_POWER_HIGH_WARNING_FIELD = "TxPowerHighWarning" -TX_POWER_LOW_WARNING_FIELD = "TxPowerLowWarning" - -VENDOR_NAME_FIELD = "VendorName" -VENDOR_DATE_FIELD = "VendorDate" -VENDOR_OUI_FIELD = "VendorOUI" -VENDOR_PART_NO_FIELD = "VendorPN" -VENDOR_REV_FIELD = "VendorRev" -VENDOR_SERIAL_NO_FIELD = "VendorSN" -VOLTAGE_FIELD = "Voltage" -VOLTAGE_SUPPORT_FIELD = "Supply Voltage Monitoring Implemented" -VOLTAGE_THRESHOLDS_FIELD = "VoltageThresholds" -VOLTAGE_HIGH_ALARM_FIELD = "VoltageHighAlarm" -VOLTAGE_LOW_ALARM_FIELD = "VoltageLowAlarm" -VOLTAGE_HIGH_WARNING_FIELD = "VoltageHighWarning" -VOLTAGE_LOW_WARNING_FIELD = "VoltageLowWarning" - -SERIAL_ID_FIELD = "Serial ID" -EXT_ID_FIELD = "Extended Identifier" -POWER_CLASS_FIELD = "Power Class" -CLEI_CODE_FIELD = "CLEI Code" -CDR_TX_FIELD = "CDR TX" -CDR_RX_FIELD = "CDR RX" -SPEC_COMPLIANCE_FIELD = "Specification Compliance" -ENCODING_FIELD = "Encoding" -NOMINAL_BR_FIELD = "Nominal BR" -EXT_RATE_SELECT_COMPLIANCE_FIELD = "Extended RateSelect Compliance" -LENGTH_ASSEMBLY_FIELD = "Length Cable Assembly" - -ETHERNET_10_40G_COMPLIANCE_FIELD = "10/40G Ethernet Compliance Code" -SONET_COMPLIANCE_FIELD = "SONET Compliance Codes" -SAS_SATA_COMPLIANCE_FIELD = "SAS/SATA Compliance Codes" -GIGABIT_ETHERNET_COMPLIANCE_FIELD = "Gigabit Ethernet Compliant Codes" -FIBRE_CHANNEL_LINK_LENGTH_FIELD = "Fibre Channel Link Length" -FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD = "Fibre Channel Transmitter Technology" -FIBRE_CHANNEL_TRANSMISSION_MEDIA_FIELD = "Fibre Channel Transmission Media" -FIBRE_CHANNEL_SPEED_FIELD = "Fibre Channel Speed" - -OPTIONS_FIELD = "Options" - -POWER_CTRL_FIELD = "Power Control" -POWER_OVERRIDE_FIELD = "Power Override" -POWER_SET_FIELD = "Power Set" - -# SFF-8636 - -REV_COMPLIANCE_FIELD = "Revision Compliance" - -# SFF-8472 - -ENHANCED_OPTIONS_FIELD = "Enhanced Options" -ETHERNET_10G_COMPLIANCE_FIELD = "10G Ethernet Compliance" -INFINIBAND_COMPLIANCE_FIELD = "Infiniband Compliance" -ESCON_COMPLIANCE_FIELD = "ESCON Compliance" -ETHERNET_COMPLIANCE_FIELD = "Ethernet Compliance" -SFP_CABLE_TECH_FIELD = "SFP+CableTechnology" -RATE_ID_FIELD = "Rate Identifier" -EXT_CAL_FIELD = "Externally Calibrated" -INT_CAL_FIELD = "Internally Calibrated" -DOM_EXT_CAL_CONST_FIELD = "Calibration Constants for External Calibration" -RX_LOS_SUPPORT_FIELD = "RxLOSSupported" -RX_PWR_4_FIELD = "Rx_PWR(4)" -RX_PWR_3_FIELD = "Rx_PWR(3)" -RX_PWR_2_FIELD = "Rx_PWR(2)" -RX_PWR_1_FIELD = "Rx_PWR(1)" -RX_PWR_0_FIELD = "Rx_PWR(0)" -TX_I_SLOPE_FIELD = "Tx_I(Slope)" -TX_I_OFFSET_FIELD = "Tx_I(Offset)" -TX_PWR_SLOPE_FIELD = "Tx_PWR(Slope)" -TX_PWR_OFFSET_FIELD = "Tx_PWR(Offset)" -T_SLOPE_FIELD = "T (Slope)" -T_OFFSET_FIELD = "T (Offet)" -V_SLOPE_FIELD = "V (Slope)" -V_OFFSET_FIELD = "V (Offset)" - -DDM_SUPPORT_FIELD = "Digital Diagnostic Monitoring Implemented" -DOM_FIELD = "DOM" - -PAGING_SUPPORT_FIELD = "Paging Implemented" - -STATUS_CTRL_FIELD = "Status/Control" -TX_DISABLE_SELECT_FIELD = "Soft TX Disable Select" - -# CMIS - -ADMIN_INFO_FIELD = "AdminInfo" -ADVERTISING_FIELD = "Advertising" -MEDIA_TYPE_FIELD = "ModuleMediaType" -HOST_ELECTRICAL_INTERFACE = "HostElectricalInterfaceID" -MODULE_MEDIA_INTERFACE_850NM = "ModuleMediaInterface850nm" -MODULE_MEDIA_INTERFACE_SM = "ModuleMediaInterfaceSM" -MODULE_MEDIA_INTERFACE_PASSIVE_COPPER = "ModuleMediaInterfacePassiveCopper" -MODULE_MEDIA_INTERFACE_ACTIVE_CABLE = "ModuleMediaInterfaceActiveCable" -MODULE_MEDIA_INTERFACE_BASE_T = "ModuleMediaInterfaceBaseT" -HOST_LANE_COUNT = "HostLaneCount" -MEDIA_LANE_COUNT = "MediaLaneCount" -HOST_LANE_ASSIGNMENT_OPTION = "HostLaneAssignmentOptions" -MEDIA_LANE_ASSIGNMENT_OPTION = "MediaLaneAssignmentOptions" -ACTIVE_APSEL_CODE = "ActiveAppSelCode" -ACTIVE_APSEL_HOSTLANE = "ActiveAppSelLane" -MEDIA_INTERFACE_TECH = "MediaInterfaceTechnology" -HW_MAJOR_REV = "ModuleHardwareMajorRevision" -HW_MINOR_REV = "ModuleHardwareMinorRevision" -CMIS_MAJOR_REVISION = "CmisMajorRevision" -CMIS_MINOR_REVISION = "CmisMinorRevision" -ACTIVE_FW_MAJOR_REV = "ModuleActiveFirmwareMajorRevision" -ACTIVE_FW_MINOR_REV = "ModuleActiveFirmwareMinorRevision" -INACTIVE_FW_MAJOR_REV = "ModuleInactiveFirmwareMajorRevision" -INACTIVE_FW_MINOR_REV = "ModuleInactiveFirmwareMinorRevision" -DP_PATH_INIT_DURATION = "DPInitDuration" -DP_PATH_DEINIT_DURATION = "DPDeinitDuration" - -# DOM -TRANS_DOM_FIELD = "TransceiverDom" -CASE_TEMP = "ModuleTemp" -VOLTAGE = "Supply3V3" -GRID_SPACING = "Tx1SelectedGridSpacing" -LASER_CONFIG_CHANNEL = "Tx1ChannelNumber" -LASER_CURRENT_FREQ = "Tx1CurrentLaserFrequency" -TX_CONFIG_POWER = "Tx1TargetOutputPower" -AUX_MON_TYPE = "AuxMonitorType" -AUX1_MON = "Aux1MonValue" -AUX2_MON = "Aux2MonValue" -AUX3_MON = "Aux3MonValue" -CUSTOM_MON = "CustomMonValue" - -# Loopback -TRANS_LOOPBACK_FIELD = "TransceiverLoopback" -LOOPBACK_CAPABILITY = "LoopbackCapability" -MEDIA_OUTPUT_LOOPBACK = "MediaSideOutputLoopbackEnable" -MEDIA_INPUT_LOOPBACK = "MediaSideInputLoopbackEnable" -HOST_OUTPUT_LOOPBACK = "HostSideOutputLoopbackEnable" -HOST_INPUT_LOOPBACK = "HostSideLoopbackEnable" - -# Threshold -TRANS_THRESHOLD_FIELD = "TransceiverThreshold" -CASE_TEMP_HIGH_ALARM = "TempeartureHighAlarmThreshold" -CASE_TEMP_LOW_ALARM = "TempeartureLowAlarmThreshold" -CASE_TEMP_HIGH_WARN = "TempeartureHighWarningThreshold" -CASE_TEMP_LOW_WARN = "TempeartureLowWarningThreshold" -VOLTAGE_HIGH_ALARM = "Supply3V3HighAlarmThreshold" -VOLTAGE_LOW_ALARM = "Supply3V3LowAlarmThreshold" -VOLTAGE_HIGH_WARN = "Supply3V3HighWarningThreshold" -VOLTAGE_LOW_WARN = "Supply3V3LowWarningThreshold" -AUX1_HIGH_ALARM = "Aux1MonitorHighAlarmThreshold" -AUX1_LOW_ALARM = "Aux1MonitorLowAlarmThreshold" -AUX1_HIGH_WARN = "Aux1MonitorHighWarningThreshold" -AUX1_LOW_WARN = "Aux1MonitorLowWarningThreshold" -AUX2_HIGH_ALARM = "Aux2MonitorHighAlarmThreshold" -AUX2_LOW_ALARM = "Aux2MonitorLowAlarmThreshold" -AUX2_HIGH_WARN = "Aux2MonitorHighWarningThreshold" -AUX2_LOW_WARN = "Aux2MonitorLowWarningThreshold" -AUX3_HIGH_ALARM = "Aux3MonitorHighAlarmThreshold" -AUX3_LOW_ALARM = "Aux3MonitorLowAlarmThreshold" -AUX3_HIGH_WARN = "Aux3MonitorHighWarningThreshold" -AUX3_LOW_WARN = "Aux3MonitorLowWarningThreshold" -TX_POWER_HIGH_ALARM = "TxOpticalPowerHighAlarmThreshold" -TX_POWER_LOW_ALARM = "TxOpticalPowerLowAlarmThreshold" -TX_POWER_HIGH_WARN = "TxOpticalPowerHighWarningThreshold" -TX_POWER_LOW_WARN = "TxOpticalPowerLowWarningThreshold" -TX_BIAS_CURR_HIGH_ALARM = "TxBiasCurrentHighAlarmThreshold" -TX_BIAS_CURR_LOW_ALARM = "TxBiasCurrentLowAlarmThreshold" -TX_BIAS_CURR_HIGH_WARN = "TxBiasCurrentHighWarningThreshold" -TX_BIAS_CURR_LOW_WARN = "TxBiasCurrentLowWarningThreshold" -RX_POWER_HIGH_ALARM = "RxOpticalPowerHighAlarmThreshold" -RX_POWER_LOW_ALARM = "RxOpticalPowerLowAlarmThreshold" -RX_POWER_HIGH_WARN = "RxOpticalPowerHighWarningThreshold" -RX_POWER_LOW_WARN = "RxOpticalPowerLowWarningThreshold" - -# Status -TRANS_MODULE_STATUS_FIELD = "TransceiverModuleStatus" -TRANS_LANE_STATUS_FIELD = "TransceiverLaneStatus" -MODULE_STATE = "ModuleState" -MODULE_FIRMWARE_FAULT_INFO = "FirmwareFault" -MODULE_FLAG_BYTE1 = "ModuleFlagByte1" -MODULE_FLAG_BYTE2 = "ModuleFlagByte2" -MODULE_FLAG_BYTE3 = "ModuleFlagByte3" -CDB1_STATUS = "Cdb1Status" -MODULE_FAULT_CAUSE = "ModuleFaultCause" -DATA_PATH_STATE= "DataPathState" -TX_OUTPUT_STATUS = "TxOutputStatus" -RX_OUTPUT_STATUS = "RxOutputStatus" -TX_LOS_FIELD = "TxLOS" -TX_LOS_SUPPORT_FIELD = "TxLOSSupported" -TX_CDR_LOL = "TxCDRLOL" -TX_CDR_LOL_SUPPORT_FIELD = "TxCDRLOLSupported" -TX_POWER_HIGH_ALARM_FLAG = "TxPowerHighAlarmFlag" -TX_POWER_LOW_ALARM_FLAG = "TxPowerLowAlarmFlag" -TX_POWER_HIGH_WARN_FLAG = "TxPowerHighWarnFlag" -TX_POWER_LOW_WARN_FLAG = "TxPowerLowWarnFlag" -TX_BIAS_HIGH_ALARM_FLAG = "TxBiasHighAlarmFlag" -TX_BIAS_LOW_ALARM_FLAG = "TxBiasLowAlarmFlag" -TX_BIAS_HIGH_WARN_FLAG = "TxBiasHighWarnFlag" -TX_BIAS_LOW_WARN_FLAG = "TxBiasLowWarnFlag" -RX_POWER_HIGH_ALARM_FLAG = "RxPowerHighAlarmFlag" -RX_POWER_LOW_ALARM_FLAG = "RxPowerLowAlarmFlag" -RX_POWER_HIGH_WARN_FLAG = "RxPowerHighWarnFlag" -RX_POWER_LOW_WARN_FLAG = "RxPowerLowWarnFlag" - -RX_CDR_LOL = "RxCDRLOL" -RX_CDR_LOL_SUPPORT_FIELD = "RxCDRLOLSupported" -CONFIG_LANE_STATUS = "ConfigStatusLane" -DPINIT_PENDING = "DPInitPending" -TUNING_IN_PROGRESS = "TxTuningInProgress" -WAVELENGTH_UNLOCKED = "TxWavelengthUnlocked" -LASER_TUNING_DETAIL = "TxTuningDetail" - -# CONFIG -TRANS_CONFIG_FIELD = "TransceiverConfig" -MODULE_LEVEL_CONTROL = "ModuleControl" - -APPLS_ADVT_FIELD = "Applications Advertisement" -APPLS_ADVT_FIELD_PAGE01 = "Applications Advertisement Pag01" -CTRLS_ADVT_FIELD = "Supported Controls Advertisement" -FLAGS_ADVT_FIELD = "Supported Flags Advertisement" -PAGE_SUPPORT_ADVT_FIELD = "Supported Pages Advertisement" -TX_FLAGS_ADVT_FIELD = "Supported TX Flags Advertisement" -RX_FLAGS_ADVT_FIELD = "Supported RX Flags Advertisement" -LANE_MON_ADVT_FIELD = "Supported Lane Monitor Advertisement" -LANE_DATAPATH_CTRL_FIELD = "Lane Control and Data Path Control" -LANE_DATAPATH_STATUS_FIELD = "Lane Status and Data Path Status" -DATAPATH_DEINIT_FIELD = "Data Path Deinit" -LEN_MULT_FIELD = "LengthMultiplier" -MAX_POWER_FIELD = "MaxPower" -MGMT_CHAR_FIELD = "Management Characteristics" -MGMT_CHAR_MISC_FIELD = "Management Characteristics (Misc)" - -MODULE_CHAR_ADVT_FIELD = "Module Characteristics Advertising" - -STAGED_CTRL_FIELD = "Staged Control Set" -STAGED_CTRL_APPLY_DPINIT_FIELD = "Staged Control Set Apply DataPathInit" -STAGED_CTRL_APPLY_IMMEDIATE_FIELD = "Staged Control Set Apply Immediate" -STAGED_CTRL_APSEL_FIELD = "Staged Control Set ApSel" - -# C-CMIS - -# Module configuration support fields -MODULE_CONFIG_SUPPORT_FIELD = "ModuleConfigSupport" -SUPPORT_GRID = "GridSupported" -LOW_CHANNEL = "LowChannel75GHz" -HIGH_CHANNEL = "HighChannel75GHz" -MIN_PROG_OUTPUT_POWER = "MinProgOutputPower" -MAX_PROG_OUTPUT_POWER = "MaxProgOutputPower" - -## Media Lane FEC Performance Monitoring -## Media Lane Link Performance Monitoring -# PM -TRANS_PM_FIELD = "TransceiverPm" -VDM_SUPPORTED = "VdmSupported" -VDM_SUPPORTED_PAGE = "VdmSupportedPage" -VDM_CONTROL = "VdmControl" -MEDIA_LANE_FEC_PM = "Media Lane FEC Performance Monitoring" -MEDIA_LANE_LINK_PM = "Media Lane Link Performance Monitoring" -RX_BITS_PM = "rxBitsPm" -RX_BITS_SUB_INTERVAL_PM = "rxBitsSubIntPm" -RX_CORR_BITS_PM = "rxCorrBitsPm" -RX_MIN_CORR_BITS_SUB_INTERVAL_PM = "rxMinCorrBitsSubIntPm" -RX_MAX_CORR_BITS_SUB_INTERVAL_PM = "rxMaxCorrBitsSubIntPm" -RX_FRAMES_PM = "rxFramesPm" -RX_FRAMES_SUB_INTERVAL_PM = "rxFramsSubIntPm" -RX_FRAMES_UNCORR_ERR_PM = "rxFramesUncorrErrPm" -RX_MIN_FRAMES_UNCORR_ERR_SUB_INTERVAL_PM = "rxMinFramesUncorrErrSubintPm" -RX_MAX_FRAMES_UNCORR_ERR_SUB_INTERVAL_PM = "rxMaxFramesUncorrErrSubintPm" - -RX_AVG_CD_PM = "rxAvgCdPm" -RX_MIN_CD_PM = "rxMinCdPm" -RX_MAX_CD_PM = "rxMaxCdPm" -RX_AVG_DGD_PM = "rxAvgDgdPm" -RX_MIN_DGD_PM = "rxMinDgdPm" -RX_MAX_DGD_PM = "rxMaxDgdPm" -RX_AVG_SOPMD_PM = "rxAvgSopmdPm" -RX_MIN_SOPMD_PM = "rxMinSopmdPm" -RX_MAX_SOPMD_PM = "rxMaxSopmdPm" -RX_AVG_PDL_PM = "rxAvgPdlPm" -RX_MIN_PDL_PM = "rxMinPdlPm" -RX_MAX_PDL_PM = "rxMaxPdlPm" -RX_AVG_OSNR_PM = "rxAvgOsnrPm" -RX_MIN_OSNR_PM = "rxMinOsnrPm" -RX_MAX_OSNR_PM = "rxMaxOsnrPm" -RX_AVG_ESNR_PM = "rxAvgEsnrPm" -RX_MIN_ESNR_PM = "rxMinEsnrPm" -RX_MAX_ESNR_PM = "rxMaxEsnrPm" -RX_AVG_CFO_PM = "rxAvgCfoPm" -RX_MAX_CFO_PM = "rxMinCfoPm" -RX_MIN_CFO_PM = "rxMaxCfoPm" -RX_AVG_EVM_PM = "rxAvgEvmPm" -RX_MIN_EVM_PM = "rxMinEvmPm" -RX_MAX_EVM_PM = "rxMaxEvmPm" -TX_AVG_POWER_PM = "txAvgPowerPm" -TX_MIN_POWER_PM = "txMinPowerPm" -TX_MAX_POWER_PM = "txMaxPowerPm" -RX_AVG_POWER_PM = "rxAvgPowerPm" -RX_MIN_POWER_PM = "rxMinPowerPm" -RX_MAX_POWER_PM = "rxMaxPowerPm" -RX_AVG_SIG_POWER_PM = "rxAvgSigPowerPm" -RX_MIN_SIG_POWER_PM = "rxMinSigPowerPm" -RX_MAX_SIG_POWER_PM = "rxMaxSigPowerPm" -RX_AVG_SOPROC_PM = "rxAvgSigSoprocPm" -RX_MIN_SOPROC_PM = "rxMinSigSoprocPm" -RX_MAX_SOPROC_PM = "rxMaxSigSoprocPm" -RX_AVG_MER_PM = "rxAvgMerPm" -RX_MIN_MER_PM = "rxMinMerPm" -RX_MAX_MER_PM = "rxMaxMerPm" - -# CDB -TRANS_CDB_FIELD = "TransceiverCdb" -CDB_SUPPORT = "CdbSupport" -AUTO_PAGING_SUPPORT = "AutoPagingSupport" -CDB_SEQ_WRITE_LENGTH_EXT = "CdbReadWriteLengthExtension" -CDB_RPL_LENGTH = "CdbReplyLength" -CDB_RPL_CHKCODE = "CdbReplyCheckCode" -CDB_LPL = "CdbLocalPayload" -CDB_CMD = "CdbCommand" -CDB_WRITE_MSG = "CdbWriteMessage" - - diff --git a/sonic_platform_base/sonic_xcvr/fields/public/__init__.py b/sonic_platform_base/sonic_xcvr/fields/public/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py b/sonic_platform_base/sonic_xcvr/fields/public/cmis.py deleted file mode 100644 index 88806b1d5..000000000 --- a/sonic_platform_base/sonic_xcvr/fields/public/cmis.py +++ /dev/null @@ -1,13 +0,0 @@ -from ..xcvr_field import NumberRegField -from .. import consts - -class CableLenField(NumberRegField): - def __init__(self, name, offset, *fields, **kwargs): - kwargs["deps"] = [consts.LEN_MULT_FIELD] - super(CableLenField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - base_len = super(CableLenField, self).decode(raw_data, **decoded_deps) - len_mult = decoded_deps.get(consts.LEN_MULT_FIELD) - mult = 10 ** (len_mult - 1) - return base_len * mult diff --git a/sonic_platform_base/sonic_xcvr/fields/public/sff8472.py b/sonic_platform_base/sonic_xcvr/fields/public/sff8472.py deleted file mode 100644 index 5059e2ff2..000000000 --- a/sonic_platform_base/sonic_xcvr/fields/public/sff8472.py +++ /dev/null @@ -1,103 +0,0 @@ -import struct - -from ..xcvr_field import NumberRegField -from .. import consts - -class TempField(NumberRegField): - def __init__(self, name, offset, *fields, **kwargs): - kwargs["deps"] = [consts.INT_CAL_FIELD, consts.EXT_CAL_FIELD, consts.T_SLOPE_FIELD, consts.T_OFFSET_FIELD] - super(TempField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - int_cal = decoded_deps.get(consts.INT_CAL_FIELD) - ext_cal = decoded_deps.get(consts.EXT_CAL_FIELD) - measured_val = struct.unpack(self.format, raw_data)[0] - if int_cal: - return measured_val / self.scale - elif ext_cal: - t_slope = decoded_deps.get(consts.T_SLOPE_FIELD) - t_offset = decoded_deps.get(consts.T_OFFSET_FIELD) - result = t_slope * measured_val + t_offset - return result / self.scale - return float('NaN') - -class VoltageField(NumberRegField): - def __init__(self, name, offset, *fields, **kwargs): - kwargs["deps"] = [consts.INT_CAL_FIELD, consts.EXT_CAL_FIELD, consts.V_SLOPE_FIELD, consts.V_OFFSET_FIELD] - super(VoltageField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - int_cal = decoded_deps.get(consts.INT_CAL_FIELD) - ext_cal = decoded_deps.get(consts.EXT_CAL_FIELD) - measured_val = struct.unpack(self.format, raw_data)[0] - if int_cal: - return measured_val / self.scale - elif ext_cal: - v_slope = decoded_deps.get(consts.V_SLOPE_FIELD) - v_offset = decoded_deps.get(consts.V_OFFSET_FIELD) - result = v_slope * measured_val + v_offset - return result / self.scale - return float('NaN') - -class TxBiasField(NumberRegField): - def __init__(self, name, offset, *fields, **kwargs): - kwargs["deps"] = [consts.INT_CAL_FIELD, consts.EXT_CAL_FIELD, consts.TX_I_SLOPE_FIELD, consts.TX_I_OFFSET_FIELD] - super(TxBiasField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - int_cal = decoded_deps.get(consts.INT_CAL_FIELD) - ext_cal = decoded_deps.get(consts.EXT_CAL_FIELD) - measured_val = struct.unpack(self.format, raw_data)[0] - if int_cal: - return measured_val / self.scale - elif ext_cal: - tx_i_slope = decoded_deps.get(consts.TX_I_SLOPE_FIELD) - tx_i_offset = decoded_deps.get(consts.TX_I_OFFSET_FIELD) - result = tx_i_slope * measured_val + tx_i_offset - return result / self.scale - return float('NaN') - -class TxPowerField(NumberRegField): - def __init__(self, name, offset, *fields, **kwargs): - kwargs["deps"] = [consts.INT_CAL_FIELD, consts.EXT_CAL_FIELD, consts.TX_PWR_SLOPE_FIELD, consts.TX_PWR_OFFSET_FIELD] - super(TxPowerField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - int_cal = decoded_deps.get(consts.INT_CAL_FIELD) - ext_cal = decoded_deps.get(consts.EXT_CAL_FIELD) - measured_val = struct.unpack(self.format, raw_data)[0] - if int_cal: - return measured_val / self.scale - elif ext_cal: - tx_pwr_slope = decoded_deps.get(consts.TX_PWR_SLOPE_FIELD) - tx_pwr_offset = decoded_deps.get(consts.TX_PWR_OFFSET_FIELD) - result = tx_pwr_slope * measured_val + tx_pwr_offset - return result / self.scale - return float('NaN') - -class RxPowerField(NumberRegField): - def __init__(self, name, offset, *fields, **kwargs): - kwargs["deps"] = [consts.INT_CAL_FIELD, consts.EXT_CAL_FIELD, consts.RX_PWR_0_FIELD, consts.RX_PWR_1_FIELD, - consts.RX_PWR_2_FIELD, consts.RX_PWR_3_FIELD, consts.RX_PWR_4_FIELD] - super(RxPowerField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - int_cal = decoded_deps.get(consts.INT_CAL_FIELD) - ext_cal = decoded_deps.get(consts.EXT_CAL_FIELD) - measured_val = struct.unpack(self.format, raw_data)[0] - if int_cal: - return measured_val / self.scale - elif ext_cal: - rx_pwr_4 = decoded_deps.get(consts.RX_PWR_4_FIELD) - rx_pwr_3 = decoded_deps.get(consts.RX_PWR_3_FIELD) - rx_pwr_2 = decoded_deps.get(consts.RX_PWR_2_FIELD) - rx_pwr_1 = decoded_deps.get(consts.RX_PWR_1_FIELD) - rx_pwr_0 = decoded_deps.get(consts.RX_PWR_0_FIELD) - - result = rx_pwr_4 * measured_val * 1e4 + \ - rx_pwr_3 * measured_val * 1e3 + \ - rx_pwr_2 * measured_val * 1e2 + \ - rx_pwr_1 * measured_val + \ - rx_pwr_0 - return result / self.scale - return float('NaN') diff --git a/sonic_platform_base/sonic_xcvr/fields/xcvr_field.py b/sonic_platform_base/sonic_xcvr/fields/xcvr_field.py deleted file mode 100644 index 68febd72c..000000000 --- a/sonic_platform_base/sonic_xcvr/fields/xcvr_field.py +++ /dev/null @@ -1,285 +0,0 @@ -""" - xcvr_field.py - - Classes for representing types of fields found in xcvr memory maps. -""" - -import struct - -class XcvrField(object): - """ - Base class for representing fields in xcvr memory maps. - - Args: - name: string, denoting the name of the field. Must be unique for a particular XcvrMemMap. - offset: integer, the absolute offset of the field in a memory map, assuming a linear address space - ro: boolean, True if the field is read-only and False otherwise - """ - def __init__(self, name, offset, **kwargs): - self.name = name - self.offset = offset - self.ro = kwargs.get("ro", True) - self.deps = kwargs.get("deps", []) - - def get_fields(self): - """ - Return: dict containing all fields nested within this field - """ - fields = {} - if hasattr(self, "fields"): - for field in self.fields: - fields[field.name] = field - fields.update(field.get_fields()) - return fields - - def get_offset(self): - """ - Return: absolute byte offset of field in memory map - """ - return self.offset - - def get_size(self): - """ - Return: size of field in bytes (min. 1) - """ - raise NotImplementedError - - def read_before_write(self): - """ - Return: True if a field needs to be read before written to, False otherwise - """ - raise NotImplementedError - - def get_deps(self): - """ - Return: List of field names corresponding to fields that this field is dependent on for decoding - """ - return self.deps - - def decode(self, raw_data, **decoded_deps): - """ - raw_data: bytearray of length equal to size of field - decoded_deps: mapping of this field's dependencies to their decoded results - Return: decoded data (high level meaning) - """ - raise NotImplementedError - - def encode(self, val, raw_state=None): - """ - val: data with high level meaning - raw_state: bytearray denoting the current state of memory corresponding to this field - Return: bytearray of length equal to size of field - - Not implemented if not appropriate for the field (e.g. read-only) - """ - raise NotImplementedError - - -class RegBitField(XcvrField): - """ - Field denoting a single bit. Must be defined under a parent RegField - - Args: - bitpos: the bit position of this field relative to its parent's offset - """ - def __init__(self, name, bitpos, offset=None, **kwargs): - super(RegBitField, self).__init__(name, offset, **kwargs) - assert bitpos < 64 - self.bitpos = bitpos - - def get_size(self): - return 1 - - def read_before_write(self): - return True - - def decode(self, raw_data, **decoded_deps): - return bool((raw_data[0] >> self.bitpos % 8) & 1) - - def encode(self, val, raw_state=None): - assert not self.ro and raw_state is not None - curr_state = raw_state[0] - if val: - curr_state |= (1 << self.bitpos % 8) - else: - curr_state &= ~(1 << self.bitpos % 8) - return bytearray([curr_state]) - - -class RegField(XcvrField): - """ - Field denoting one or more bytes, but logically interpreted as one unit (e.g. a 4-byte integer) - """ - def __init__(self, name, offset, *fields, **kwargs): - super(RegField, self).__init__(name, offset, **kwargs) - self.fields = fields - self.size = kwargs.get("size", 1) - self.start_bitpos = self.size * 8 - 1 # max bitpos - self._update_bit_offsets() - - def _update_bit_offsets(self): - for field in self.fields: - assert 0 <= field.bitpos < self.size * 8 - field.offset = self.offset + field.bitpos // 8 - self.start_bitpos = min(field.bitpos, self.start_bitpos) - - def get_bitmask(self): - if not self.fields: - return None - mask = 0 - for field in self.fields: - mask |= 1 << field.bitpos - return mask - - def get_size(self): - return self.size - - def read_before_write(self): - return False - -class NumberRegField(RegField): - """ - Interprets byte(s) as a number - """ - def __init__(self, name, offset, *fields, **kwargs): - super(NumberRegField, self).__init__(name, offset, *fields, **kwargs) - self.scale = kwargs.get("scale") - self.format = kwargs.get("format", "B") - - def decode(self, raw_data, **decoded_deps): - decoded = struct.unpack(self.format, raw_data)[0] - mask = self.get_bitmask() - if mask is not None: - decoded &= mask - decoded >>= self.start_bitpos - if self.scale is not None: - return decoded / self.scale - return decoded - - def encode(self, val, raw_state=None): - assert not self.ro - if self.scale is not None: - return bytearray(struct.pack(self.format, int(val * self.scale))) - return bytearray(struct.pack(self.format, val)) - -class FixedNumberRegField(NumberRegField): - """ - Interprets byte(s) as a fixed-point number - """ - def __init__(self, name, offset, num_frac_bits, *fields, **kwargs): - super(FixedNumberRegField, self).__init__(name, offset, *fields, **kwargs) - self.num_frac_bits = num_frac_bits - - def decode(self, raw_data, **decoded_deps): - decoded = super(FixedNumberRegField, self).decode(raw_data, **decoded_deps) - return decoded / (1 << self.num_frac_bits) - - def encode(self, val, raw_state=None): - bin = val * (1 << self.num_frac_bits) - return super(FixedNumberRegField, self).encode(bin, raw_state) - -class StringRegField(RegField): - """ - Interprets byte(s) as a string - """ - def __init__(self, name, offset, *fields, **kwargs): - super(StringRegField, self).__init__(name, offset, *fields, **kwargs) - self.encoding = kwargs.get("encoding", "ascii") - self.format = kwargs.get("format", ">%ds" % self.size) - - def decode(self, raw_data, **decoded_deps): - return struct.unpack(self.format, raw_data)[0].decode(self.encoding, 'ignore') - -class CodeRegField(RegField): - """ - Interprets byte(s) as a code - """ - def __init__(self, name, offset, code_dict, *fields, **kwargs): - super(CodeRegField, self).__init__(name, offset, *fields, **kwargs) - self.code_dict = code_dict - self.format = kwargs.get("format", "B") - - def decode(self, raw_data, **decoded_deps): - code = struct.unpack(self.format, raw_data)[0] - mask = self.get_bitmask() - if mask is not None: - code &= mask - code >>= self.start_bitpos - return self.code_dict.get(code, "Unknown") - -class HexRegField(RegField): - """ - Interprets bytes as a series of hex pairs - """ - def __init__(self, name, offset, *fields, **kwargs): - super(HexRegField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - return '-'.join([ "%02x" % byte for byte in raw_data]) - -class RegGroupField(XcvrField): - """ - Field denoting one or more bytes, logically interpreted as one or more RegFields - (e.g. a 4-byte integer followed by a 16-byte string) or RegGroupFields. - - The offset of a RegGroupField is the offset of its first member XcvrField. - - The member fields need not be contiguous, but the first field must be the one with the smallest offset. - """ - def __init__(self, name, *fields, **kwargs): - super(RegGroupField, self).__init__(name, fields[0].get_offset(), **kwargs) - self.fields = fields - - def get_size(self): - start = self.offset - end = start - for field in self.fields: - end = max(end, field.get_offset() + field.get_size()) - return end - start - - def read_before_write(self): - return False - - def decode(self, raw_data, **decoded_deps): - """ - Return: a dict mapping member field names to their decoded results - """ - result = {} - start = self.offset - for field in self.fields: - offset = field.get_offset() - if not field.get_deps(): - result[field.name] = field.decode(raw_data[offset - start: offset + field.get_size() - start], - **decoded_deps) - - # Now decode any fields that have dependant fields in the same RegGroupField scope - for field in self.fields: - offset = field.get_offset() - deps = field.get_deps() - if deps: - decoded_deps.update({dep: result[dep] for dep in deps if dep in result}) - result[field.name] = field.decode(raw_data[offset - start: offset + field.get_size() - start], - **decoded_deps) - return result - -class DateField(StringRegField): - """ - Common representation of date codes in xcvr memory maps - """ - def __init__(self, name, offset, *fields, **kwargs): - super(DateField, self).__init__(name, offset, *fields, **kwargs) - - def decode(self, raw_data, **decoded_deps): - date = super(DateField, self).decode(raw_data, **decoded_deps) - year_offset = 0 - month_offset = 2 - day_offset = 4 - lot_offset = 6 - - date = "20%s-%s-%s %s" % ( - date[year_offset:month_offset], - date[month_offset:day_offset], - date[day_offset:lot_offset], - date[lot_offset:self.get_size()] - ) - return date diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/__init__.py b/sonic_platform_base/sonic_xcvr/mem_maps/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/__init__.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/c_cmis.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/c_cmis.py deleted file mode 100644 index 4dee61763..000000000 --- a/sonic_platform_base/sonic_xcvr/mem_maps/public/c_cmis.py +++ /dev/null @@ -1,81 +0,0 @@ -""" - c_cmis.py - - Implementation of XcvrMemMap for C-CMIS Rev 1.1 -""" - -from ...fields.xcvr_field import ( - NumberRegField, - RegGroupField -) -from ...fields import consts -from .cmis import CmisMemMap - -class CCmisMemMap(CmisMemMap): - def __init__(self, codes): - super(CCmisMemMap, self).__init__(codes) - - self.MODULE_CONFIG_SUPPORT = RegGroupField(consts.MODULE_CONFIG_SUPPORT_FIELD, - NumberRegField(consts.SUPPORT_GRID, self.getaddr(0x4, 128)), - NumberRegField(consts.LOW_CHANNEL, self.getaddr(0x4, 158), format=">h", size=2), - NumberRegField(consts.HIGH_CHANNEL, self.getaddr(0x4, 160), format=">h", size=2), - NumberRegField(consts.MIN_PROG_OUTPUT_POWER, self.getaddr(0x4, 198), format=">h", size=2, scale = 100.0), - NumberRegField(consts.MAX_PROG_OUTPUT_POWER, self.getaddr(0x4, 200), format=">h", size=2, scale = 100.0) - ) - - self.MEDIA_LANE_FEC_PM = RegGroupField(consts.MEDIA_LANE_FEC_PM, - NumberRegField(consts.RX_BITS_PM, self.getaddr(0x34, 128), format=">Q", size=8), - NumberRegField(consts.RX_BITS_SUB_INTERVAL_PM, self.getaddr(0x34, 136), format=">Q", size=8), - NumberRegField(consts.RX_CORR_BITS_PM, self.getaddr(0x34, 144), format=">Q", size=8), - NumberRegField(consts.RX_MIN_CORR_BITS_SUB_INTERVAL_PM, self.getaddr(0x34, 152), format=">Q", size=8), - NumberRegField(consts.RX_MAX_CORR_BITS_SUB_INTERVAL_PM, self.getaddr(0x34, 160), format=">Q", size=8), - NumberRegField(consts.RX_FRAMES_PM, self.getaddr(0x34, 168), format=">I", size=4), - NumberRegField(consts.RX_FRAMES_SUB_INTERVAL_PM, self.getaddr(0x34, 172), format=">I", size=4), - NumberRegField(consts.RX_FRAMES_UNCORR_ERR_PM, self.getaddr(0x34, 176), format=">I", size=4), - NumberRegField(consts.RX_MIN_FRAMES_UNCORR_ERR_SUB_INTERVAL_PM, self.getaddr(0x34, 180), format=">I", size=4), - NumberRegField(consts.RX_MAX_FRAMES_UNCORR_ERR_SUB_INTERVAL_PM, self.getaddr(0x34, 184), format=">I", size=4), - ) - - # MEDIA_LANE_LINK_PM block corresponds to all the coherent PMs in C-CMIS spec reported in Page 35h. - self.MEDIA_LANE_LINK_PM = RegGroupField(consts.MEDIA_LANE_LINK_PM, - NumberRegField(consts.RX_AVG_CD_PM, self.getaddr(0x35, 128), format=">i", size=4), - NumberRegField(consts.RX_MIN_CD_PM, self.getaddr(0x35, 132), format=">i", size=4), - NumberRegField(consts.RX_MAX_CD_PM, self.getaddr(0x35, 136), format=">i", size=4), - NumberRegField(consts.RX_AVG_DGD_PM, self.getaddr(0x35, 140), format=">H", size=2, scale=100.0), - NumberRegField(consts.RX_MIN_DGD_PM, self.getaddr(0x35, 142), format=">H", size=2, scale=100.0), - NumberRegField(consts.RX_MAX_DGD_PM, self.getaddr(0x35, 144), format=">H", size=2, scale=100.0), - NumberRegField(consts.RX_AVG_SOPMD_PM, self.getaddr(0x35, 146), format=">H", size=2, scale=100.0), - NumberRegField(consts.RX_MIN_SOPMD_PM, self.getaddr(0x35, 148), format=">H", size=2, scale=100.0), - NumberRegField(consts.RX_MAX_SOPMD_PM, self.getaddr(0x35, 150), format=">H", size=2, scale=100.0), - NumberRegField(consts.RX_AVG_PDL_PM, self.getaddr(0x35, 152), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MIN_PDL_PM, self.getaddr(0x35, 154), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MAX_PDL_PM, self.getaddr(0x35, 156), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_AVG_OSNR_PM, self.getaddr(0x35, 158), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MIN_OSNR_PM, self.getaddr(0x35, 160), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MAX_OSNR_PM, self.getaddr(0x35, 162), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_AVG_ESNR_PM, self.getaddr(0x35, 164), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MIN_ESNR_PM, self.getaddr(0x35, 166), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MAX_ESNR_PM, self.getaddr(0x35, 168), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_AVG_CFO_PM, self.getaddr(0x35, 170), format=">h", size=2), - NumberRegField(consts.RX_MIN_CFO_PM, self.getaddr(0x35, 172), format=">h", size=2), - NumberRegField(consts.RX_MAX_CFO_PM, self.getaddr(0x35, 174), format=">h", size=2), - NumberRegField(consts.RX_AVG_EVM_PM, self.getaddr(0x35, 176), format=">H", size=2, scale=655.35), - NumberRegField(consts.RX_MIN_EVM_PM, self.getaddr(0x35, 178), format=">H", size=2, scale=655.35), - NumberRegField(consts.RX_MAX_EVM_PM, self.getaddr(0x35, 180), format=">H", size=2, scale=655.35), - NumberRegField(consts.TX_AVG_POWER_PM, self.getaddr(0x35,182), format=">h", size=2, scale=100.0), - NumberRegField(consts.TX_MIN_POWER_PM, self.getaddr(0x35,184), format=">h", size=2, scale=100.0), - NumberRegField(consts.TX_MAX_POWER_PM, self.getaddr(0x35,186), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_AVG_POWER_PM, self.getaddr(0x35,188), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_MIN_POWER_PM, self.getaddr(0x35,190), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_MAX_POWER_PM, self.getaddr(0x35,192), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_AVG_SIG_POWER_PM, self.getaddr(0x35,194), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_MIN_SIG_POWER_PM, self.getaddr(0x35,196), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_MAX_SIG_POWER_PM, self.getaddr(0x35,198), format=">h", size=2, scale=100.0), - NumberRegField(consts.RX_AVG_SOPROC_PM, self.getaddr(0x35,200), format=">H", size=2), - NumberRegField(consts.RX_MIN_SOPROC_PM, self.getaddr(0x35,202), format=">H", size=2), - NumberRegField(consts.RX_MAX_SOPROC_PM, self.getaddr(0x35,204), format=">H", size=2), - NumberRegField(consts.RX_AVG_MER_PM, self.getaddr(0x35,206), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MIN_MER_PM, self.getaddr(0x35,208), format=">H", size=2, scale=10.0), - NumberRegField(consts.RX_MAX_MER_PM, self.getaddr(0x35,210), format=">H", size=2, scale=10.0), - # TODO: add others PMs... - ) diff --git a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py b/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py deleted file mode 100644 index 3a2359c11..000000000 --- a/sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py +++ /dev/null @@ -1,455 +0,0 @@ -""" - cmis.py - - Implementation of XcvrMemMap for CMIS Rev 5.0 -""" - -from ..xcvr_mem_map import XcvrMemMap -from ...fields.xcvr_field import ( - CodeRegField, - DateField, - HexRegField, - NumberRegField, - RegBitField, - RegGroupField, - StringRegField, -) -from ...fields import consts -from ...fields.public.cmis import CableLenField - -class CmisMemMap(XcvrMemMap): - def __init__(self, codes): - super(CmisMemMap, self).__init__(codes) - - self.MGMT_CHARACTERISTICS = RegGroupField(consts.MGMT_CHAR_FIELD, - NumberRegField(consts.MGMT_CHAR_MISC_FIELD, self.getaddr(0x0, 2), - RegBitField(consts.FLAT_MEM_FIELD, 7) - ) - ) - - # Should contain ONLY Lower page fields - self.ADMIN_INFO = RegGroupField(consts.ADMIN_INFO_FIELD, - CodeRegField(consts.ID_FIELD, self.getaddr(0x0, 0), self.codes.XCVR_IDENTIFIERS), - CodeRegField(consts.ID_ABBRV_FIELD, self.getaddr(0x0, 128), self.codes.XCVR_IDENTIFIER_ABBRV), - StringRegField(consts.VENDOR_NAME_FIELD, self.getaddr(0x0, 129), size=16), - HexRegField(consts.VENDOR_OUI_FIELD, self.getaddr(0x0, 145), size=3), - StringRegField(consts.VENDOR_PART_NO_FIELD, self.getaddr(0x0, 148), size=16), - StringRegField(consts.VENDOR_REV_FIELD, self.getaddr(0x0, 164), size=2), - StringRegField(consts.VENDOR_SERIAL_NO_FIELD, self.getaddr(0x0, 166), size=16), - DateField(consts.VENDOR_DATE_FIELD, self.getaddr(0x0, 182), size=8), - RegGroupField(consts.EXT_ID_FIELD, - CodeRegField(consts.POWER_CLASS_FIELD, self.getaddr(0x0, 200), self.codes.POWER_CLASSES, - *(RegBitField("%s_%d" % (consts.POWER_CLASS_FIELD, bit), bit) for bit in range(5, 8)) - ), - NumberRegField(consts.MAX_POWER_FIELD, self.getaddr(0x0, 201), scale=4.0), - ), - NumberRegField(consts.LEN_MULT_FIELD, self.getaddr(0x0, 202), - *(RegBitField("%s_%d" % (consts.LEN_MULT_FIELD, bit), bit) for bit in range (6, 8)) - ), - CableLenField(consts.LENGTH_ASSEMBLY_FIELD, self.getaddr(0x0, 202), - *(RegBitField("%s_%d" % (consts.LENGTH_ASSEMBLY_FIELD, bit), bit) for bit in range(0, 6)) - ), - - CodeRegField(consts.CONNECTOR_FIELD, self.getaddr(0x0, 203), self.codes.CONNECTORS), - - RegGroupField(consts.APPLS_ADVT_FIELD, - *(CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, app), self.getaddr(0x0, 86 + 4 * (app - 1)), - self.codes.HOST_ELECTRICAL_INTERFACE) for app in range(1, 9)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, app), self.getaddr(0x0, 87 + 4 * (app- 1)), - self.codes.NM_850_MEDIA_INTERFACE) for app in range(1, 9)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, app), self.getaddr(0x0, 87 + 4 * (app - 1)), - self.codes.SM_MEDIA_INTERFACE) for app in range(1, 9)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, app), self.getaddr(0x0, 87 + 4 * (app - 1)), - self.codes.PASSIVE_COPPER_MEDIA_INTERFACE) for app in range(1, 9)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, app), self.getaddr(0x0, 87 + 4 * (app - 1)), - self.codes.ACTIVE_CABLE_MEDIA_INTERFACE) for app in range(1, 9)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, app), self.getaddr(0x0, 87 + 4 * (app - 1)), - self.codes.BASE_T_MEDIA_INTERFACE) for app in range(1, 9)), - - *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, lane), self.getaddr(0x0, 88 + 4 * (lane - 1)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) - ) for lane in range(1, 9)), - - *(NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, lane), self.getaddr(0x0, 88 + 4 * (lane - 1)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) - ) for lane in range(1, 9)), - - *(NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, lane), self.getaddr(0x0, 89 + 4 * (lane - 1)), - format="B", size=1) for lane in range(1, 9)), - ), - - CodeRegField(consts.HOST_ELECTRICAL_INTERFACE, self.getaddr(0x0, 86), self.codes.HOST_ELECTRICAL_INTERFACE), - CodeRegField(consts.MEDIA_TYPE_FIELD, self.getaddr(0x0, 85), self.codes.MODULE_MEDIA_TYPE), - CodeRegField(consts.MODULE_MEDIA_INTERFACE_850NM, self.getaddr(0x0, 87), self.codes.NM_850_MEDIA_INTERFACE), - CodeRegField(consts.MODULE_MEDIA_INTERFACE_SM, self.getaddr(0x0, 87), self.codes.SM_MEDIA_INTERFACE), - CodeRegField(consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, self.getaddr(0x0, 87), self.codes.PASSIVE_COPPER_MEDIA_INTERFACE), - CodeRegField(consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, self.getaddr(0x0, 87), self.codes.ACTIVE_CABLE_MEDIA_INTERFACE), - CodeRegField(consts.MODULE_MEDIA_INTERFACE_BASE_T, self.getaddr(0x0, 87), self.codes.BASE_T_MEDIA_INTERFACE), - NumberRegField(consts.MEDIA_LANE_COUNT, self.getaddr(0x0, 88), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) - ), - NumberRegField(consts.HOST_LANE_COUNT, self.getaddr(0x0, 88), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) - ), - NumberRegField(consts.HOST_LANE_ASSIGNMENT_OPTION, self.getaddr(0x0, 89), format="B", size=1), - CodeRegField(consts.MEDIA_INTERFACE_TECH, self.getaddr(0x0, 212), self.codes.MEDIA_INTERFACE_TECH), - NumberRegField(consts.CMIS_MAJOR_REVISION, self.getaddr(0x0, 1), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) - ), - NumberRegField(consts.CMIS_MINOR_REVISION, self.getaddr(0x0, 1), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) - ), - NumberRegField(consts.ACTIVE_FW_MAJOR_REV, self.getaddr(0x0, 39), format="B", size=1), - NumberRegField(consts.ACTIVE_FW_MINOR_REV, self.getaddr(0x0, 40), format="B", size=1), - ) - - # Should contain ONLY upper page fields - self.ADVERTISING = RegGroupField(consts.ADVERTISING_FIELD, - NumberRegField(consts.INACTIVE_FW_MAJOR_REV, self.getaddr(0x1, 128), format="B", size=1), - NumberRegField(consts.INACTIVE_FW_MINOR_REV, self.getaddr(0x1, 129), format="B", size=1), - NumberRegField(consts.HW_MAJOR_REV, self.getaddr(0x1, 130), size=1), - NumberRegField(consts.HW_MINOR_REV, self.getaddr(0x1, 131), size=1), - CodeRegField(consts.DP_PATH_INIT_DURATION, self.getaddr(0x1, 144), self.codes.DP_PATH_TIMINGS, - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) - ), - CodeRegField(consts.DP_PATH_DEINIT_DURATION, self.getaddr(0x1, 144), self.codes.DP_PATH_TIMINGS, - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) - ), - NumberRegField(consts.MEDIA_LANE_ASSIGNMENT_OPTION, self.getaddr(0x1, 176), format="B", size=1), - - RegGroupField(consts.ACTIVE_APSEL_CODE, - *(NumberRegField("%s%d" % (consts.ACTIVE_APSEL_HOSTLANE, lane) , self.getaddr(0x11, offset), - *(RegBitField("Bit%d" % bit, bit) for bit in range(4, 7))) - for lane, offset in zip(range(1, 9), range(206, 214))) - ), - - RegGroupField(consts.APPLS_ADVT_FIELD_PAGE01, - *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x1, 176 + (app - 1)), - format="B", size=1) for app in range(1, 16)), - - *(CodeRegField("%s_%d" % (consts.HOST_ELECTRICAL_INTERFACE, app), self.getaddr(0x1, 223 + 4 * (app - 9)), - self.codes.HOST_ELECTRICAL_INTERFACE) for app in range(9, 16)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_850NM, app), self.getaddr(0x1, 224 + 4 * (app - 9)), - self.codes.NM_850_MEDIA_INTERFACE) for app in range(9, 16)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_SM, app), self.getaddr(0x1, 224 + 4 * (app - 9)), - self.codes.SM_MEDIA_INTERFACE) for app in range(9, 16)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_PASSIVE_COPPER, app), self.getaddr(0x1, 224 + 4 * (app - 9)), - self.codes.PASSIVE_COPPER_MEDIA_INTERFACE) for app in range(9, 16)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_ACTIVE_CABLE, app), self.getaddr(0x1, 224 + 4 * (app - 9)), - self.codes.ACTIVE_CABLE_MEDIA_INTERFACE) for app in range(9, 16)), - - *(CodeRegField("%s_%d" % (consts.MODULE_MEDIA_INTERFACE_BASE_T, app), self.getaddr(0x1, 224 + 4 * (app - 9)), - self.codes.BASE_T_MEDIA_INTERFACE) for app in range(9, 16)), - - *(NumberRegField("%s_%d" % (consts.MEDIA_LANE_COUNT, lane), self.getaddr(0x1, 225 + 4 * (lane - 9)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (0, 4)) - ) for lane in range(9, 16)), - - *(NumberRegField("%s_%d" % (consts.HOST_LANE_COUNT, lane), self.getaddr(0x1, 225 + 4 * (lane - 9)), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)) - ) for lane in range(9, 16)), - - *(NumberRegField("%s_%d" % (consts.HOST_LANE_ASSIGNMENT_OPTION, app), self.getaddr(0x1, 226 + 4 * (app - 9)), - format="B", size=1) for app in range(9, 16)) - ) - ) - - self.MODULE_LEVEL_MONITORS = RegGroupField(consts.MODULE_MONITORS_FIELD, - NumberRegField(consts.TEMPERATURE_FIELD, self.getaddr(0x0, 14), size=2, format=">h", scale=256.0), - NumberRegField(consts.VOLTAGE_FIELD, self.getaddr(0x0, 16), size=2, format=">H", scale=10000.0), - NumberRegField(consts.GRID_SPACING, self.getaddr(0x12, 128), - *(RegBitField("Bit%d" % (bit), bit) for bit in range (4, 8)), ro = False - ), - NumberRegField(consts.LASER_CONFIG_CHANNEL, self.getaddr(0x12, 136), format=">h", size=2, ro=False), - NumberRegField(consts.LASER_CURRENT_FREQ, self.getaddr(0x12, 168), format=">L", size=4, scale = 1000.0), - NumberRegField(consts.TX_CONFIG_POWER, self.getaddr(0x12, 200), format=">h", size=2, scale=100.0, ro=False), - NumberRegField(consts.AUX_MON_TYPE, self.getaddr(0x1, 145), size=1), - NumberRegField(consts.AUX1_MON, self.getaddr(0x0, 18), format=">h", size=2), - NumberRegField(consts.AUX2_MON, self.getaddr(0x0, 20), format=">h", size=2), - NumberRegField(consts.AUX3_MON, self.getaddr(0x0, 22), format=">h", size=2), - NumberRegField(consts.CUSTOM_MON, self.getaddr(0x0, 24), format=">H", size=2), - ) - - self.MODULE_CHAR_ADVT = RegGroupField(consts.MODULE_CHAR_ADVT_FIELD, - NumberRegField(consts.PAGE_SUPPORT_ADVT_FIELD, self.getaddr(0x1, 142), - RegBitField(consts.VDM_SUPPORTED, 6), - ), - NumberRegField(consts.CTRLS_ADVT_FIELD, self.getaddr(0x1, 155), - RegBitField(consts.TX_DISABLE_SUPPORT_FIELD, 1), - size=2, format=" seconds. - If the watchdog is currently armed, calling this function will - simply reset the timer to the provided value. If the underlying - hardware does not support the value provided in , this - method should arm the watchdog with the *next greater* available - value. - - Returns: - An integer specifying the *actual* number of seconds the watchdog - was armed with. On failure returns -1. - """ - raise NotImplementedError - - def disarm(self): - """ - Disarm the hardware watchdog - - Returns: - A boolean, True if watchdog is disarmed successfully, False if not - """ - raise NotImplementedError - - def is_armed(self): - """ - Retrieves the armed state of the hardware watchdog. - - Returns: - A boolean, True if watchdog is armed, False if not - """ - raise NotImplementedError - - def get_remaining_time(self): - """ - If the watchdog is armed, retrieve the number of seconds remaining on - the watchdog timer - - Returns: - An integer specifying the number of seconds remaining on thei - watchdog timer. If the watchdog is not armed, returns -1. - """ - raise NotImplementedError diff --git a/sonic_psu/__init__.py b/sonic_psu/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_psu/psu_base.py b/sonic_psu/psu_base.py deleted file mode 100644 index 4ac699944..000000000 --- a/sonic_psu/psu_base.py +++ /dev/null @@ -1,120 +0,0 @@ -# -# psu_base.py -# -# Abstract base class for implementing platform-specific -# PSU control functionality for SONiC -# - -try: - import abc -except ImportError as e: - raise ImportError (str(e) + " - required module not found") - -class PsuBase(object): - __metaclass__ = abc.ABCMeta - - @abc.abstractmethod - def get_num_psus(self): - """ - Retrieves the number of PSUs supported on the device - - :return: An integer, the number of PSUs supported on the device - """ - return 0 - - @abc.abstractmethod - def get_psu_status(self, index): - """ - Retrieves the operational status of power supply unit (PSU) defined - by index 1-based - - :param index: An integer, 1-based index of the PSU of which to query status - :return: Boolean, - - True if PSU is operating properly: PSU is inserted and powered in the device - - False if PSU is faulty: PSU is inserted in the device but not powered - """ - return False - - @abc.abstractmethod - def get_psu_presence(self, index): - """ - Retrieves the presence status of power supply unit (PSU) defined - by 1-based index - - :param index: An integer, 1-based index of the PSU of which to query status - :return: Boolean, True if PSU is plugged, False if not - """ - return False - - def get_model(self, idx): - """ - Retrieves the model number/name of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query model number - :return: String, denoting model number/name - """ - return "" - - def get_mfr_id(self, idx): - """ - Retrieves the manufacturing id of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query mfr id - :return: String, denoting manufacturing id - """ - return "" - - def get_serial(self, idx): - """ - Retrieves the serial number of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query serial number - :return: String, denoting serial number of the PSU unit - """ - return "" - - def get_direction(self, idx): - """ - Retrieves the airflow direction of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query airflow direction - :return: String, denoting the airflow direction - """ - return "" - - def get_output_voltage(self, idx): - """ - Retrieves the ouput volatage in milli volts of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query o/p volatge - :return: A float, value of o/p voltage in Volts if PSU is good, else zero - """ - return 0.0 - - def get_output_current(self, idx): - """ - Retrieves the output current in milli amperes of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query o/p current - :return: A float, value of o/p current in Amps if PSU is good, else zero - """ - return 0.0 - - def get_output_power(self, idx): - """ - Retrieves the output power in micro watts of a power supply unit (PSU) defined - by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query o/p power - :return: A float, value of o/p power in Watts if PSU is good, else zero - """ - return 0.0 - - def get_fan_rpm(self, idx, fan_idx): - """ - Retrieves the speed of fan, in rpm, denoted by 1-based of a power - supply unit (PSU) defined by 1-based index - :param idx: An integer, 1-based index of the PSU of which to query fan speed - :param fan_idx: An integer, 1-based index of the PSU-fan of which to query speed - :return: An integer, value of PSU-fan speed in rpm if PSU-fan is good, else zero - """ - return 0 diff --git a/sonic_sfp b/sonic_sfp deleted file mode 120000 index fd9b3493d..000000000 --- a/sonic_sfp +++ /dev/null @@ -1 +0,0 @@ -./sonic_platform_base/sonic_sfp/ \ No newline at end of file diff --git a/sonic_thermal/__init__.py b/sonic_thermal/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_thermal/thermal_base.py b/sonic_thermal/thermal_base.py deleted file mode 100644 index c2fd86391..000000000 --- a/sonic_thermal/thermal_base.py +++ /dev/null @@ -1,89 +0,0 @@ -# -# thermal_base.py -# -# Base class for implementing platform-specific -# Thermal functionality for SONiC - -try: - import abc -except ImportError as e: - raise ImportError (str(e) + " - required module not found") - -class ThermalBase(object): - __metaclass__ = abc.ABCMeta - - def get_num_thermals(self): - """ - Retrieves the number of thermal sensors supported on the device - - :return: An integer, the number of thermal sensors supported on the device - """ - return 0 - - def get_name(self, index): - """ - Retrieves the human-readable name of a thermal sensor by 1-based index - - Returns: - :param index: An integer, 1-based index of the thermal sensor of which to query status - :return: String, - A string representing the name of the thermal sensor. - """ - return "" - - def get_temperature(self, index): - """ - Retrieves current temperature reading from thermal sensor by 1-based index - - :param index: An integer, 1-based index of the thermal sensor of which to query status - :return: Float, - A float number of current temperature in Celsius up to nearest thousandth - of one degree Celsius, e.g. 30.125 - """ - return 0.0 - - def get_low_threshold(self, index): - """ - Retrieves the low threshold temperature of thermal sensor by 1-based index - Actions should be taken if the temperature becomes lower than the low threshold. - - :param index: An integer, 1-based index of the thermal sensor of which to query status - :return: A float number, the low threshold temperature of thermal in Celsius - up to nearest thousandth of one degree Celsius, e.g. 30.125 - """ - return 0.0 - - def get_low_critical_threshold(self, index): - """ - Retrieves the low critical threshold temperature of thermal by 1-based index - Actions should be taken immediately if the temperature becomes lower than the low critical - threshold otherwise the device will be damaged. - - :param index: An integer, 1-based index of the thermal sensor of which to query status - :return: A float number, the low critical threshold temperature of thermal in Celsius - up to nearest thousandth of one degree Celsius, e.g. 30.125 - """ - return 0.0 - - def get_high_threshold(self, index): - """ - Retrieves the high threshold temperature of thermal by 1-based index - Actions should be taken if the temperature becomes higher than the threshold. - - :param index: An integer, 1-based index of the thermal sensor of which to query status - :return: A float number, the high threshold temperature of thermal in Celsius - up to nearest thousandth of one degree Celsius, e.g. 30.125 - """ - return 0.0 - - def get_high_critical_threshold(self, index): - """ - Retrieves the high critical threshold temperature of thermal by 1-based index - Actions should be taken immediately if the temperature becomes higher than the high critical - threshold otherwise the device will be damaged. - - :param index: An integer, 1-based index of the thermal sensor of which to query status - :return: A float number, the high critical threshold temperature of thermal in Celsius - up to nearest thousandth of one degree Celsius, e.g. 30.125 - """ - return 0.0 diff --git a/sonic_y_cable/__init__.py b/sonic_y_cable/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_y_cable/broadcom/__init__.py b/sonic_y_cable/broadcom/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_y_cable/broadcom/y_cable_broadcom.py b/sonic_y_cable/broadcom/y_cable_broadcom.py deleted file mode 100644 index 43a2d0edd..000000000 --- a/sonic_y_cable/broadcom/y_cable_broadcom.py +++ /dev/null @@ -1,9315 +0,0 @@ -# -# y_cable_broadcom.py -# -# definitions for implementing Y cable access and configurations -# API's for Y cable functionality in SONiC -# -#from y_cable_base import YCableBase -from sonic_y_cable.y_cable_base import YCableBase - -try: - import time - import struct - import array - import math - import os - import re - import string - import threading - import shelve - from ctypes import c_int16 - from datetime import datetime - from contextlib import contextmanager - #import chassis - - import platform - #from chassis import chassis - import sonic_platform.platform - #from sonic_py_common import logger -except ImportError as e: - print("{}".format(e)) - # When build python3 xcvrd, it tries to do basic check which will import this file. However, - # not all platform supports python3 API now, so it could cause an issue when importing - # sonic_platform.platform. We skip the ImportError here. This is safe because: - # 1. If any python package is not available, there will be exception when use it - # 2. Vendors know their platform API version, they are responsible to use correct python - # version when importing this file. - # pass - -# strut definitions used in fw related functions - -class func_name_args(): - def __init__(self, length, name, desc): - self.arg_len = length - self.func = name - self.description = desc - -class cable_image_version_s(object): - - def __init__(self): - self.image_version_minor = 0 - self.image_version_major = 0 - - -class cable_image_info_s(object): - - def __init__(self): - self.image_fw_version = cable_image_version_s() - self.image_api_version = cable_image_version_s() - self.image_crc32 = 0 - self.image_ptr = array.array('H', []) - self.image_size = 0 - - -class cable_bank_info_s(object): - - def __init__(self): - self.image_fw_version = cable_image_version_s() - self.image_api_version = cable_image_version_s() - self.image_crc32 = 0 - - -class cable_status_info_s(): - - def __init__(self): - self.current_bank = 0 - self.next_bank = 0 - self.bank1_info = cable_bank_info_s() - self.bank2_info = cable_bank_info_s() - - -class cable_upgrade_info_s(object): - - def __init__(self): - self.image_info = cable_image_info_s() - self.status_info = cable_status_info_s() - self.destination = 0 - self.bank = 0 - - -class cable_upgrade_head_s(): - - def __init__(self): - self.compression = 0 - self.compressed_size = 0 - self.compressed_crc32 = 0 - self.add_size = 0 - self.add_crc32 = 0 - self.header_crc32 = 0 - self.cable_up_info = cable_upgrade_info_s() - - -class cmd_handle_s(object): - - def __init__(self): - self.cmd_wr = 0 - self.read_info = 0 - self.cmd_rd = 0 - self.info_len = 0 - self.data_read = bytearray(30) - - -class valid_port_option_table_s: - - def __init__(self, speed, fec_tor, fec_nic, anlt_tor, anlt_nic, mode): - self.speed = speed - self.fec_tor = fec_tor - self.fec_nic = fec_nic - self.anlt_tor = anlt_tor - self.anlt_nic = anlt_nic - self.mode = mode - - -class context_state_frame_s(object): - def __init__(self): - self.r0 = 0 - self.r1 = 0 - self.r2 = 0 - self.r3 = 0 - self.r12 = 0 - self.lr = 0 - self.return_address = 0 - self.xpsr = 0 - - -class ram2_exp_hdr_s(object): - def __init__(self): - self.crash = 0 - self.crash_len = 0 - self.cfsr_reg = 0 - self.ufsr_reg = 0 - self.bfsr_reg = 0 - self.mmfsr_reg = 0 - self.val = context_state_frame_s() - self.exp_sp_depth = 0 - - -class ram2_exp_s(object): - def __init__(self): - self.hdr_val = ram2_exp_hdr_s() - self.exp_stack = array.array('I', []) - - - -class cable_mcu_event_log_s(object): - - def __init__(self): - self.event_type = None - self.timestamp = 0 - self.run_no = 0 - self.event_source = 0 - -class cable_phy_chip_event_log_s(object): - - def __init__(self): - self.in_fault = None - self.out_fault = None - self.timestamp = 0 - self.run_no = 0 - - -class pcsfec_dump_status_short_s(object): - - def __init__(self): - self.fec_type = 0 - self.func_mode = 0 - self.pcs_sts = pcsrx_status_short_s() # PCS Rx status for port based on fec_type/direction/func_mode - self.fec_sts = fecrx_status_short_s() # FEC Rx status for port based on fec_type/direction/func_mode - self.no_clr_on_rd = 0 - -class fecrx_status_short_s(object): - - def __init__(self): - self.am_lolock_sticky = 0 - self.dgbox_clsn_sticky = 0 - self.hi_ser_sticky = 0 - self.xdec_err_sticky = 0 - self.fec_link_stat = 0 - self.fec_link_stat_sticky = 0 - self.tot_frame_rev_cnt = 0 - self.tot_frame_corr_cnt = 0 - self.tot_frame_uncorr_cnt = 0 - self.tot_symbols_corr_cnt = 0 - self.tot_bits_corr_cnt = [] - self.tot_frames_err_cnt = [] - - -class pcsrx_status_short_s(object): - - def __init__(self): - self.pcs_status_phylane = [] - self.pcs_dskw_align_stat = 0 - self.pcs_dskw_align_loss_sticky = 0 - self.pcs_hiber_stat = 0 - self.pcs_hiber_sticky = 0 - self.pcs_ber_cnt = 0 - self.pcs_link_stat = 0 - self.pcs_link_stat_sticky = 0 - -class pcsrx_status_phylane_short_s(object): - - def __init__(self): - self.pcs_block_lock_stat = 0 - self.pcs_block_lolock_sticky = 0 - self.pcs_am_lock_stat = 0 - self.pcs_am_lolock_sticky = 0 - self.pcs_dskw_error_sticky = 0 - self.pcs_bip_err_cnt = [] - - -ENABLE_DBG_PRINT = False - - -def enable_debug_print(flag): - global ENABLE_DBG_PRINT - ENABLE_DBG_PRINT = flag - - -def debug_print(log_msg): - if ENABLE_DBG_PRINT: - curr_timestamp = datetime.utcnow() - cur_tstr = curr_timestamp.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] - print("({}) {} : {}".format(threading.currentThread().getName(), cur_tstr, log_msg)) - return None - -# -# Lock for port access for thread safe -# - - -class PortLock(object): - def __init__(self, port_nbr): - self.port_nbr = port_nbr - self.lock = threading.RLock() - - # def __del__(self): - # print("PortLock {} destroyed".format(self.port_nbr)) - - def __enter__(self): - self.lock.acquire() - debug_print("(with) acquired lock for port {}".format(self.port_nbr)) - - def __exit__(self, exc_type, exc_value, traceback): - self.lock.release() - debug_print("(with) released lock for port {}".format(self.port_nbr)) - - @contextmanager - def acquire_timeout(self, timeout): - result = self.lock.acquire(timeout=timeout) - debug_print("(with timeout) acquired lock for port {}".format(self.port_nbr)) - yield result - if result: - self.lock.release() - debug_print("(with timeout) released lock for port {}".format(self.port_nbr)) - - def get_port_nbr(self): - return self.port_nbr - - def acquire(self): - self.lock.acquire() - debug_print("explicitly acquired lock for port {}".format(self.port_nbr)) - - def release(self): - self.lock.release() - debug_print("explicitly released lock for port {}".format(self.port_nbr)) - -# -# BCM Y Cable implementation derived from y_cable_base -# - - -class YCable(YCableBase): - - - CAPI_FEC_TYPE_PCS = 0 - FEC_TOT_FRAMES_ERR_NUM_SHORT = 8 - port_func_mode_description = [ - "", - "MILLENIO_CAPI_MODE_400", - "MILLENIO_CAPI_MODE_200", - "MILLENIO_CAPI_MODE_100", - "MILLENIO_CAPI_MODE_50G", - "MILLENIO_CAPI_MODE_40G", - "MILLENIO_CAPI_MODE_25G", - "MILLENIO_CAPI_MODE_10G", - "MILLENIO_CAPI_MODE_1G "] - - port_fec_type_description = [ - "MILLENIO_CAPI_FEC_TYPE_PCS", - "MILLENIO_CAPI_FEC_TYPE_FC_FEC", - "MILLENIO_CAPI_FEC_TYPE_RS528", - "MILLENIO_CAPI_FEC_TYPE_RS544", - "INVALID_FEC", - "MILLENIO_CAPI_FEC_TYPE_NA"] - - - CAPI_MODE_NONE = 0 #**< No suitable func mode */ - CAPI_MODE_100G = 3 #**< 100G mode */ - CAPI_MODE_50G = 4 #**< 50G mode */ - - WARMBOOT = 0 - COLDBOOT = 1 - - # definitions of the modes to be run for loopback mode - # on the port/cable - LOOPBACK_MODE_NEAR_END = 1 - - # definitions of PRBS run modes - PRBS_DIRECTION_BOTH = 0 - PRBS_DIRECTION_GENERATOR = 1 - PRBS_DIRECTION_CHECKER = 2 - - BCM_API_VERSION = "2.0" - CONSOLE_PRINT = False - - # Log levels - LOG_INFO = 1 - LOG_WARN = 2 - LOG_DEBUG = 3 - LOG_ERROR = 4 - - CABLE_MODE_100G_FEC = 0 - CABLE_MODE_100G_PCS = 1 - CABLE_MODE_50G_FEC = 2 - CABLE_MODE_50G_PCS = 3 - - PORT_SPEED_50 = 0 - PORT_SPEED_100 = 1 - - FEC_MODE_NONE = 0 - FEC_MODE_RS = 1 - PORT_FEC_FC = 2 - - ANLT_DISABLED = 1 - ANLT_ENABLED = 2 - ANLT_DONT_CARE = 3 - #ANLT_DONT_CARE = True - - CABLE_MODE_50G = 50000 - CABLE_MODE_100G = 100000 - - PORT_LOCK_TIMEOUT = 30 # in seconds - - # Rollback states - PERFORM_ROLLBACK = 1 - ALREADY_ROLLED_BACK = 2 - CANNOT_ROLLBACK = 3 - - # Activate states - PERFORM_ACTIVATE = 1 - ALREADY_ACTIVATED = 2 - CANNOT_ACTIVATE = 3 - - # Register absolute addresses - QSFP28_LP_3_TX_RX_LOSS = 0x00000003 - QSFP28_LP_5_TX_RX_CDR_LOL = 0x00000005 - QSFP28_LP_6_TEMP_WARN = 0x00000006 - QSFP28_LOS_LOL_SEC = 0x0000004A - QSFP28_LINK_DOWN = 0x0000004B - QSFP28_LINK_FAULT = 0x0000004C - QSFP28_MESC_FAULT = 0x0000004D - QSFP28_INSERT_ERR_FAULT = 0x0000004F - QSFP28_BIP_CW_ERR_FAULT = 0x00000050 - QSFP28_LP_22_TEMP_MSB = 0x00000016 - QSFP_SQL_STATUS = 0x0000004E - QSFP_LP_31_VENDOR = 0x0000004F # CHANGED to 79 -- Not used. Check! - QSFP_LINK_FAULT_MASK = 0x00007F61 - QSFP_MESC_MASK = 0x00007F62 - QSFP28_LP_100_TX_RX_LOS_MASK = 0x00000064 - QSFP28_LP_102_TX_RX_CDR_LOL_MASK = 0x00000066 - QSFP28_LOS_LOL_SEC_MASK = 0x00007F63 - QSFP28_UP_DOWN_MASK = 0x00007F64 - QSFP28_BIP_UNCORR_MASK = 0x00007F65 - QSFP28_UP0_148_VENDOR_NAME_0 = 0x00000094 - QSFP28_UP0_168_PN_1 = 0x000000a8 - QSFP28_UP0_168_SN_1 = 0x000000c4 - QSFP28_UP0_DATE_CODE = 0x000000d4 - QSFP28_UP0_224_SPECIFIC_1_RSV = 0x000000e0 - QSFP_BRCM_CABLE_CMD = 0x00000013 - QSFP_BRCM_CABLE_CTRL_CMD_STS = 0x00000014 - QSFP_VEN_FE_130_BRCM_DATA_LENGHT_LSB = 0x00007f82 - QSFP28_VENFD_129_DIE_TEMP_MSB = 0x00007f01 - QSFP28_VENFD_130_DIE_VOLTAGE_LSB = 0x00007f02 - QSFP28_VENFD_184_NIC_TORB_TORA_RESET = 0x00007f38 - QSFP28_VENFD_216_LINK_STATUS = 0x00007f58 - QSFP28_RESET_SELF_OFFSET = 0x0000005D - - # temperature and voltage register offsets - QSFP28_VENFD_128_DIE_TEMP_LSB = 0x00007f00 - QSFP28_VENFD_131_DIE_VOLTAGE_MSB = 0x00007f03 - QSFP28_VENFD_134_TORA_TEMP_MSB = 0x00007f06 - QSFP28_VENFD_135_TORA_TEMP_LSB = 0x00007f07 - QSFP28_VENFD_138_TORB_TEMP_MSB = 0x00007f0a - QSFP28_VENFD_139_TORB_TEMP_LSB = 0x00007f0b - QSFP28_VENFD_142_NIC_TEMP_MSB = 0x00007f0e - QSFP28_VENFD_143_NIC_TEMP_LSB = 0x00007f0f - - QSFP28_LP_QSFP28_LP_2_STATUS_CR = 0x00000002 - QSFP_BRCM_FW_UPGRADE_COMP_SET = 0x00000094 - - # User defined - CMD_REQ_PARAM_START_OFFSET = 0x7F87 - CMD_RSP_PARAM_START_OFFSET = 0x7FB8 - - MAX_REQ_PARAM_LEN = 0x30 - MAX_RSP_PARAM_LEN = 0x77 - - # command IDs - CABLE_CMD_ID_PRBS_SET = 0x01 - CABLE_CMD_ID_PRBS_CHK = 0x03 - CABLE_CMD_ID_SET_LOOPBACK = 0x04 - CABLE_CMD_ID_GET_LOOPBACK = 0x05 - CABLE_CMD_ID_SET_TXFIR = 0x06 - CABLE_CMD_ID_GET_TXFIR = 0x07 - CABLE_CMD_ID_SET_ANLT = 0x08 - CABLE_CMD_ID_GET_ANLT = 0x09 - CABLE_CMD_ID_GET_ANLT_RESTART = 0x0A - CABLE_CMD_ID_GET_ANLT_GET_STATUS = 0x0B - CABLE_CMD_ID_SET_POLARITY = 0x0C - CABLE_CMD_ID_GET_POLARITY = 0x0D - CABLE_CMD_ID_SET_MODE = 0x0E - CABLE_CMD_ID_GET_MODE = 0x0F - CABLE_CMD_ID_GET_SQUELCH = 0x10 - CABLE_CMD_ID_SET_SQUELCH = 0x11 - CABLE_CMD_ID_GET_HMUX_CONFIG = 0x12 - CABLE_CMD_ID_SET_HMUX_CONFIG = 0x13 - CABLE_CMD_ID_GET_HMUX_CONTEXT = 0x14 - CABLE_CMD_ID_SET_HMUX_CONTEXT = 0x15 - CABLE_CMD_ID_GET_HMUX_STATS = 0x16 - CABLE_CMD_ID_READ_REG = 0x17 - CABLE_CMD_ID_WRITE_REG = 0x18 - CABLE_CMD_ID_ENABLE_PHY_CHIP = 0x19 - CABLE_CMD_ID_DISABLE_PHY_CHIP = 0x1A - CABLE_CMD_ID_DUMP_PAGE = 0x1B - CABLE_CMD_ID_GET_EYE_MARGIN = 0x1F - CABLE_CMD_ID_GET_SNR = 0x20 - CABLE_CMD_ID_SET_HMUX_CONTEXT_PRI = 0x21 - CABLE_CMD_ID_SET_HMUX_CONTEXT_SEC = 0x22 - CABLE_CMD_ID_GET_TOT_MAN_SWT_CNT = 0x23 - CABLE_CMD_ID_GET_TOT_MAN_SWT_CNT_CLR = 0x24 - CABLE_CMD_ID_GET_TO_TORA_MAN_SWT_CNT = 0x25 - CABLE_CMD_ID_GET_TO_TORA_MAN_SWT_CNT_CLR = 0x26 - CABLE_CMD_ID_GET_TO_TORB_MAN_SWT_CNT = 0x27 - CABLE_CMD_ID_GET_TO_TORB_MAN_SWT_CNT_CLR = 0x28 - CABLE_CMD_ID_GET_FM_TORA_MAN_SWT_CNT = 0x29 - CABLE_CMD_ID_GET_FM_TORA_MAN_SWT_CNT_CLR = 0x2A - CABLE_CMD_ID_GET_FM_TORB_MAN_SWT_CNT = 0x2B - CABLE_CMD_ID_GET_FM_TORB_MAN_SWT_CNT_CLR = 0x2C - CABLE_CMD_ID_GET_TOT_AUT_SWT_CNT = 0x2D - CABLE_CMD_ID_GET_TOT_AUT_SWT_CNT_CLR = 0x2E - CABLE_CMD_ID_GET_TO_TORA_AUT_SWT_CNT = 0x2F - CABLE_CMD_ID_GET_TO_TORA_AUT_SWT_CNT_CLR = 0x30 - CABLE_CMD_ID_GET_TO_TORB_AUT_SWT_CNT = 0x31 - CABLE_CMD_ID_GET_TO_TORB_AUT_SWT_CNT_CLR = 0x32 - CABLE_CMD_ID_READ_MCU_RAM = 0x33 - CABLE_CMD_ID_CLEAR_CRASH = 0x34 - CABLE_CMD_GET_PHY_CHIP_EVENT_LOG = 0x35 - CABLE_CMD_GET_MCU_EVENT_LOG = 0x36 - CABLE_CMD_SET_PHY_CHIP_DEBUG_MODE = 0x37 - CABLE_CMD_GET_PHY_CHIP_DEBUG_MODE = 0x38 - CABLE_CMD_GET_PCSFEC_STATS = 0x39 - CABLE_CMD_ENABLE_WATCHDOG = 0x40 - CABLE_CMD_DISABLE_WATCHDOG = 0x41 - - - # Download commands - FW_CMD_START = 1 - FW_CMD_TRANSFER = 2 - FW_CMD_COMPLETE = 3 - FW_CMD_SWAP = 4 - FW_CMD_ABORT = 5 - FW_CMD_INFO = 6 - FW_CMD_RESET = 7 - - FW_UP_SUCCESS = 1 - FW_UP_IN_PROGRESS = 2 - - FW_CMD_WARM_BOOT = 13 - FW_CMD_BOOT_STATUS = 14 - FW_CMD_BL_WR_UNPR = 15 - FW_CMD_BL_WR_PR = 16 - - # destination values - TOR_MCU = 0x01 - TOR_MCU_SELF = 0x01 - NIC_MCU = 0x02 - MUX_CHIP = 0x03 - TOR_MCU_PEER = 0x04 - - # FW image address - MCU_FW_IMG_INFO_ADDR = 0x3E7F0 - MCU_FW_IMG_SIZE = 0x3E800 - MUX_FW_IMG_INFO_ADDR = 0x3FFE0 - MUX_FW_IMG_SIZE = 0x40000 - FW_IMG_INFO_SIZE = 12 - FW_UP_PACKET_SIZE = 128 - - QSFP_BRCM_FW_UPGRADE_DATA_PAGE_1 = 0x81 - QSFP_BRCM_FW_UPGRADE_DATA_PAGE_2 = 0x82 - QSFP_BRCM_FW_UPGRADE_DATA_START = 0x80 - QSFP_BRCM_DIAGNOSTIC_PAGE = 0x04 - QSFP_BRCM_DIAGNOSTIC_STATUS = 0x81 - - QSFP_BRCM_FW_UPGRADE_PACKET_SIZE = 0x92 - QSFP_BRCM_FW_UPGRADE_CURRENT_BANK = 0x80 - - QSFP_BRCM_FW_UPGRADE_CTRL_CMD = 0x80 - QSFP_BRCM_FW_UPGRADE_CMD_STS = 0x81 - QSFP_BRCM_FW_UPGRADE_CTRL_STS = 0x81 - - QSFP_BRCM_FW_UPGRADE_PAGE = 0x80 - QSFP_BRCM_FW_UPGRADE_HEADER_0_7 = 0x82 - QSFP_BRCM_FW_UPGRADE_HEADER_24_31 = 0x85 - QSFP_BRCM_FW_UPGRADE_BOOT_STATUS = 0x9A - - # Bootloader - QSFP_BRCM_FW_UPGRADE_BL_SUPPORT_0_7 = 0xAD - - # The Qsfp page for broadcom firmware version support - QSFP_BRCM_FW_VERSION_PAGE = 0x83 - QSFP_BRCM_FW_VERSION_CTRL_CMD = 0x80 - QSFP_BRCM_FW_VERSION_CMD_STS = 0x81 - QSFP_BRCM_FW_VERSION_HEADER_24_31 = 0x85 - QSFP_BRCM_FW_VERSION_CURRENT_BANK = 0x86 - - - # muxchip return codes - RR_ERROR = -1 # -255 # Error Category - RR_ERROR_SYSTEM_UNAVAILABLE = -250 # System Unavailable Error - RR_SUCCESS = 0 # Success - - # PRBS polynomials - CABLE_PRBS7 = 0 # PRBS poly 7 - CABLE_PRBS9 = 1 # PRBS poly 9 - CABLE_PRBS11 = 2 # PRBS poly 11 - CABLE_PRBS15 = 3 # PRBS poly 15 - CABLE_PRBS23 = 4 # PRBS poly 23 - CABLE_PRBS31 = 5 # PRBS poly 31 - CABLE_PRBS58 = 6 # PRBS poly 58 - CABLE_PRBS49 = 7 # PRBS poly 49 - CABLE_PRBS13 = 8 # PRBS poly 13 - - # Loopback modes - CABLE_NIC_GLOOPBACK_MODE = 0 # Global NIC loopback mode, line/NIC side deep or G-Loop - CABLE_NIC_RLOOPBACK_MODE = 1 # Remote NIC loopback mode, line/NIC side R-LOOP - CABLE_TOR_GLOOPBACK_MODE = 2 # Global TOR loopback mode, TOR side deep or G-Loop - CABLE_TOR_RLOOPBACK_MODE = 3 # Remote TOR loopback mode, side R-LOOP - - # core ip's - CORE_IP_ALL = 0 # Core IP ALL - CORE_IP_LW = 2 # Core IP Line Wrapper - CORE_IP_CLIENT = 3 # Core IP SerDes - CORE_IP_NIC = 1 - CORE_IP_TOR = 2 - CORE_IP_CENTRAL = 3 - - # Error codes returned from y_cable functions - ERROR_PLATFORM_NOT_LOADED = -1 # -1 - ERROR_CMD_STS_CHECK_FAILED = -1 # -2 - ERROR_WRITE_EEPROM_FAILED = -1 # -3 - ERROR_CMD_PROCESSING_FAILED = -1 # -4 - ERROR_MCU_NOT_RELEASED = -1 # -5 - ERROR_MCU_BUSY = -1 # -6 - ERROR_INVALID_PRBS_MODE = -1 # -8 - ERROR_INVALID_TARGET = -1 # -9 - ERROR_INVALID_DIRECTION = -1 # -10 - ERROR_INVALID_POLARITY = -1 # -11 - ERROR_CMD_EXEC_FAILED = -1 # -12 - ERROR_PORT_LOCK_TIMEOUT = -1 # -13 - ERROR_INVALID_INPUT = -1 # -14 - ERROR_WR_EEPROM_FAILED = -1 - - ERROR_FW_GET_STATUS_FAILED = -1 # -15 - ERROR_NO_MATCHING_FW = -1 # -16 - ERROR_RESET_FAILED = -1 # -17 - ERROR_TOGGLE_FAILED = -1 # -18 - # ERROR_FW_ACTIVATE_FAILURE = -1 #-19 - # ERROR_FW_ROLLBACK_FAILURE = -1 #-20 - ERROR_GET_FEC_MODE_FAILED = -1 # -21 - ERROR_READ_SIDE_FAILED = -1 # -22 - - WARNING_FW_ALREADY_ACTIVE = -50 - WARNING_FW_ALREADY_ROLLEDBACK = -51 - - EEPROM_READ_DATA_INVALID = -1 # -100 - EEPROM_ERROR = -1 # -101 - API_FAIL = -1 # -102 - - ERROR_RW_NIC_FAILED = -1 # -30 #Unable to communicate with NIC MCU - ERROR_RW_TOR_FAILED = -1 # -31 #Unable to communicate with TOR MCU - ERROR_GET_VERSION_FAILED = -1 # -32 #Unable to get firmware version from MCU - ERROR_FLASH_SIZE_INVALID = -1 # -33 #Firmware image size is greater than flash bank size - ERROR_FLASH_ERASE_FAILED = -1 # -34 #Flash erase failed - ERROR_FLASH_WRITE_FAILED = -1 # -35 #Flash write failed - ERROR_FLASH_READ_FAILED = -1 # -36 #Flash read failed - ERROR_CRC32_FAILED = -1 # -37 #Flash CRC validation failed - ERROR_CMD_TIMEOUT = -1 # -38 #No response after command sent - ERROR_SYSTEM_BUSY = -1 # -39 #System is busy - - # debug_dump commands - CMD_REG_DUMP = "reg_dump" - CMD_INTR_STATUS = "intr_status" - - NIC_NO_SIG_DETECT_LANE0 = 0x1 - NIC_NO_SIG_DETECT_LANE1 = 0x2 - NIC_NO_SIG_DETECT_LANE2 = 0x4 - NIC_NO_SIG_DETECT_LANE3 = 0x8 - TORA_NO_SIG_DETECT_LANE0 = 0x10 - TORA_NO_SIG_DETECT_LANE1 = 0x20 - TORA_NO_SIG_DETECT_LANE2 = 0x40 - TORA_NO_SIG_DETECT_LANE3 = 0x80 - - NIC_CDR_LOCK_LOSS_LANE0 = 0x1 - NIC_CDR_LOCK_LOSS_LANE1 = 0x2 - NIC_CDR_LOCK_LOSS_LANE2 = 0x4 - NIC_CDR_LOCK_LOSS_LANE3 = 0x8 - TORA_CDR_LOCK_LOSS_LANE0 = 0x10 - TORA_CDR_LOCK_LOSS_LANE1 = 0x20 - TORA_CDR_LOCK_LOSS_LANE2 = 0x40 - TORA_CDR_LOCK_LOSS_LANE3 = 0x80 - - TORB_CDR_LOCK_LOSS_LANE0 = 0x1 - TORB_CDR_LOCK_LOSS_LANE1 = 0x2 - TORB_CDR_LOCK_LOSS_LANE2 = 0x4 - TORB_CDR_LOCK_LOSS_LANE3 = 0x8 - TORB_NO_SIG_DETECT_LANE0 = 0x10 - TORB_NO_SIG_DETECT_LANE1 = 0x20 - TORB_NO_SIG_DETECT_LANE2 = 0x40 - TORB_NO_SIG_DETECT_LANE3 = 0x80 - - PHY_CHIP_WATCHDOG = 0x1 - PHY_CHIP_MEM_SINGLE_BIT_ERROR = 0x2 - PHY_CHIP_MEM_DUAL_BIT_ERROR = 0x4 - TORA_CRASH = 0x8 - TORB_CRASH = 0x10 - NIC_CRASH = 0x20 - AVS_FAILURE = 0x40 - MUX_DIRECTION_CHANGE = 0x80 - - TORA_SOUTHBOUND_FECPCS_LINK_DOWN = 0x1 - TORB_SOUTHBOUND_FECPCS_LINK_DOWN = 0x2 - ACTIVE_SOUTHBOUND_TOR_LINK_FAULT = 0x4 - TORA_NORTHBOUND_LINK_FAULT = 0x8 - TORB_NORTHBOUND_LINK_FAULT = 0x10 - TORA_BIP_UNCORRECTABLE = 0x20 - TORB_BIP_UNCORRECTABLE = 0x40 - - LEN_OF_SET_CURSOR_VALUES = 7 - - def __init__(self, port, logger1): - - self.port = port - self.platform_chassis = None - self.debug_dump_list = {} - self.sfp = None - self.lock = PortLock(port) - self.fp_lock = PortLock(port) - self.dl_lock = PortLock(port) - self.ev_lock = PortLock(port) - - # add functions for CLI execution - self.init_cli_functions() - self.logger = logger1 - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED - super(YCable, self).__init__(port, logger1) - try: - #self.platform_chassis = chassis() - self.platform_chassis = sonic_platform.platform.Platform().get_chassis() - self.sfp = self.platform_chassis.get_sfp(self.port) - - logger1.log_info("chassis loaded {}".format(self.platform_chassis)) - except Exception as e: - logger1.log_warning("Failed to load chassis due to {}".format(repr(e))) - - def init_cli_functions(self): - self.debug_dump_list["reg_dump"] = func_name_args(0, "reg_dump", "It will dump all registers with meaningful values, Function has no arguments") - self.debug_dump_list["intr_status"] = func_name_args(0, "cable_get_intr_status", "It will read cable interrupt status, Function has no arguments") - - ## TXFIR cmds - self.debug_dump_list["set_target_cursor_values"] = func_name_args(3, "set_target_cursor_values", "Function sets the target cursor values, ARG_1. lane_mask, ARG_2. cursor_values_list, ARG_3.target") - self.debug_dump_list["get_target_cursor_values"] = func_name_args(2, "get_target_cursor_values", "Function reads the cable target cursor values, ARG_1. lane_mask, ARG_2.target") - - ## LINK ACTIVE - self.debug_dump_list["is_link_active"] = func_name_args(1, "is_link_active", "Function checks if NIC, TOR_A and TOR_B of the Y cable's link is active, ARG_1. target") - - ## TOGGLE - self.debug_dump_list["toggle_mux_to_tora"] = func_name_args(0, "toggle_mux_to_tor_a", "does a hard switch toggle of the Y cable's MUX regardless of link state to TOR A on the port this is called for, Function has no arguments") - self.debug_dump_list["toggle_mux_to_torb"] = func_name_args(0, "toggle_mux_to_tor_b", "does a hard switch toggle of the Y cable's MUX regardless of link state to TOR B on the port this is called for, Function has no arguments") - - self.debug_dump_list["get_active_linked_tor_side"] = func_name_args(0, "get_active_linked_tor_side", "checks which side of the Y cable is actively linked and sending traffic and returns either TOR A or TOR B, Function has no arguments") - - self.debug_dump_list["mux_direction"] = func_name_args(0, "get_mux_direction", "checks which side of the Y cable mux is currently point to and returns either TOR A or TOR B, Function has no arguments") - self.debug_dump_list["read_side"] = func_name_args(0, "get_read_side", "checks which side of the Y cable the reads are actually getting performed from, Function has no arguments") - - ## SQUELCH - self.debug_dump_list["set_squelch"] = func_name_args(4, "cable_set_squelch", "checks which side of the Y cable the reads are actually getting performed from, Function has 4 arguments 1.target, 2.lane_map, 3.enable, 4.direction") - self.debug_dump_list["get_squelch"] = func_name_args(0, "cable_get_squelch", "specifically returns the Rx squelch and Tx squelch status on TOR and NIC, Function has no arguments") - - ## PRBS - self.debug_dump_list["enable_prbs"] = func_name_args(3, "enable_prbs_mode", "configures and enables the PRBS mode/type depending upon the mode_value the user provides, Function has 3 arguments 1.target, 2.mode_value, 3.lane_mask, 4.direction=PRBS_DIRECTION_BOTH") - self.debug_dump_list["disable_prbs"] = func_name_args(1, "disable_prbs_mode", "configures and disables the PRBS mode/type depending upon the mode_value the user provides, Function has 1 arguments 1.target, 2.direction=PRBS_DIRECTION_BOTH") - self.debug_dump_list["check_prbs"] = func_name_args(3, "cable_check_prbs", "specifically provides PRBS lock status and error count for the given prbs_type, lane_mask and target side, Function has 1 arguments 1.target, 2.mode_value, 3.lane_mask") - - ## MODE - self.debug_dump_list["set_mode"] = func_name_args(1, "cable_set_mode", "specifically set the cable mode on the port user provides, Function has 1 argument 1.cable_mode") - self.debug_dump_list["get_mode"] = func_name_args(0, "cable_get_mode", "specifically set the cable mode on the port user provides, Function has no arguments") - self.debug_dump_list["set_fec_mode"] = func_name_args(1, "set_fec_mode", "specifically set the cable mode on the port user provides, Function has 1 arguments 1. fec_mode") - self.debug_dump_list["get_fec_mode"] = func_name_args(0, "get_fec_mode", "specifically get the cable mode on the port user provides, Function has no arguments") - - ## SWITCHING MODE - self.debug_dump_list["get_switching_mode"] = func_name_args(0, "get_switching_mode", "returns which type of switching mode the cable is set to auto/manual, Function has no arguments") - self.debug_dump_list["set_switching_mode"] = func_name_args(1, "set_switching_mode", "enables the auto switching or manual switching feature on the Y-Cable, Function has 1 arguments 1.mode") - - ## LOOPBACK - self.debug_dump_list["enable_loopback"] = func_name_args(3, "enable_loopback_mode", "configures and enables the Loopback mode on the port user provides, Function has 3 arguments 1.target 2.lane_map 3.mode ") - self.debug_dump_list["disable_loopback"] = func_name_args(1, "disable_loopback_mode", "disables the Loopback mode on the port user provides, Function has 1 argument 1.target") - self.debug_dump_list["get_loopback"] = func_name_args(1, "get_loopback_mode", "returns the Loopback mode on the port which it has been configured, Function has 1 argument 1.target") - - ## ANLT - self.debug_dump_list["set_anlt"] = func_name_args(2, "set_anlt", "enables/disables the cable auto-negotiation + link training (AN/LT), Function has 2 arguments 1.enable 2.target") - self.debug_dump_list["get_anlt"] = func_name_args(1, "get_anlt", "enables/disables the cable auto-negotiation + link training (AN/LT), Function has 2 arguments 1.target") - self.debug_dump_list["get_anlt_stats"] = func_name_args(1, "get_anlt_stats", "returns auto-negotiation + link training (AN/LT) mode statistics, Function has 1 arguments 1.target") - self.debug_dump_list["restart_anlt"] = func_name_args(1, "restart_anlt", "restarts auto-negotiation + link training (AN/LT) mode, Function has 1 arguments 1.target") - - ## SWITCH COUNT - self.debug_dump_list["switch_count_total"] = func_name_args(2, "get_switch_count_total", "returns the total switch count to change the Active TOR which has been done manually/automatic by the user, Function has 3 arguments 1.switch_count_type 2.clear_on_read") - self.debug_dump_list["switch_count_tor_a"] = func_name_args(1, "get_switch_count_tor_a", "returns the switch count to change the Active TOR which has been done manually by the user initiated from ToR A, Function has 1 arguments 1.clear_on_read") - self.debug_dump_list["switch_count_tor_b"] = func_name_args(1, "get_switch_count_tor_b", "returns the switch count to change the Active TOR which has been done manually by the user initiated from ToR A, Function has 1 arguments 1.clear_on_read") - self.debug_dump_list["switch_count_target"] = func_name_args(3, "get_switch_count_target", "returns the total number of times the Active TOR has been done manually/automaticlly toggled towards a target, Function has 3 arguments 1.switch_count_type, 2.target, 3.clear_on_read") - - ## LOCAL VLOLATAGE and TEMP - self.debug_dump_list["local_voltage"] = func_name_args(0, "get_local_voltage", "returns local ToR voltage of the physical port for which this API is called, Function has no arguments") - self.debug_dump_list["local_temperature"] = func_name_args(0, "get_local_temperature", "returns local ToR temperature of the physical port for which this API is called, Function has no arguments") - self.debug_dump_list["nic_temperature"] = func_name_args(0, "get_nic_temperature", "returns nic temperature of the physical port for which this API is called, Function has no arguments") - - ## Read / Write Register - self.debug_dump_list["read_register"] = func_name_args(2, "rd_reg_ex", "specifically used to read the register values, Function has 2 arguments 1. reg_addr, 2. lane_map ") - self.debug_dump_list["write_register"] = func_name_args(3, "wr_reg_ex", "specifically used to write the register values, Function has 3 arguments 1. reg_addr, 2. reg_value, 3. lane_map ") - - ## reset - self.debug_dump_list["reset_nic"] = func_name_args(1, "reset", "resets the MCU to which this API is called for, Function has 1 arguments 1. target ") - self.debug_dump_list["reset_tora"] = func_name_args(1, "reset", "resets the MCU to which this API is called for, Function has 1 arguments 1. target ") - self.debug_dump_list["reset_torb"] = func_name_args(1, "reset", "resets the MCU to which this API is called for, Function has 1 arguments 1. target ") - - ## ALIVE STATUS - self.debug_dump_list["alive_status"] = func_name_args(0, "get_alive_status", "checks if cable is connected to all the ports and is healthy, Function has no arguments ") - - ## EYE_HEIGHTS - self.debug_dump_list["eye_heights"] = func_name_args(1, "get_eye_heights", "returns the EYE height value for a specfic port, Function has 1 argument 1. target ") - self.debug_dump_list["internal_eye_heights"] = func_name_args(1, "internal_get_eye_heights", "returns the EYE height value for a specfic port, Functionn has 1 argument 1.target") - - self.debug_dump_list["get_snr"] = func_name_args(0, "cable_get_snr", "returns the SNR value, Function has no arguments ") - self.debug_dump_list["ber_info"] = func_name_args(1, "get_ber_info", "returns the BER (Bit error rate) value for a specfic port, Function has 1 arguments 1. target ") - self.debug_dump_list["get_speed"] = func_name_args(0, "get_speed", "gets the mode of the cable for corresponding lane configuration, Function has no arguments ") - - ## AUTOSWITCH HYSTERESIS - self.debug_dump_list["set_hysteresis_timer"] = func_name_args(1, "set_autoswitch_hysteresis_timer", "sets the hysteresis timer of the cable. the time in auto-switch mode which the mux has to wait after toggling it once, before again toggling the mux to a different ToR, Function has 1 arguments 1. timer ") - self.debug_dump_list["get_hysteresis_timer"] = func_name_args(0, "get_autoswitch_hysteresis_timer", "gets the hysteresis timer of the cable, Function has no arguments ") - - ## SET/GET INTR STATUS - self.debug_dump_list["set_intr_mask"] = func_name_args(1, "cable_set_intr_mask", "sets the Lane interupt mask,Chip interupt mask and Port interupt mask on torA, torB and NIC. Function has 1 arguments 1. intr_mask") - self.debug_dump_list["get_intr_mask"] = func_name_args(0, "cable_get_intr_mask", "gets the Lane interupt mask,Chip interupt mask and Port interupt mask on torA, torB and NIC. Function has no arguments ") - - ## intr active status - self.debug_dump_list["intr_active_status"] = func_name_args(0, "cable_check_intr_active_status", "gets the active interupt mask, Functionn has no arguments ") - - self.debug_dump_list["create_port"] = func_name_args(5, "create_port", "sets the mode of the cable/port for corresponding lane/fec etc. configuration as specified, Functionn has 5 arguments 1.speed, 2.fec_mode_tor=FEC_MODE_NONE, 3.fec_mode_nic=FEC_MODE_NONE, 4.anlt_tor=False, 5.anlt_nic=False ") - - ## SET / GET DEBUG MODE - self.debug_dump_list["set_debug"] = func_name_args(1, "set_debug_mode", "enables/disables a debug mode that the port is now, Functionn has 1 arguments 1.debug_mode ") - self.debug_dump_list["get_debug"] = func_name_args(0, "get_debug_mode", "enables/disables a debug mode that the port is now, Functionn has no arguments") - self.debug_dump_list["event_log"] = func_name_args(0, "get_event_log", "returns the event log of the cable, Functionn has no arguments") - - ## PHY CHIP - self.debug_dump_list["enadis_phy_chip_idle_loop"] = func_name_args(1, "cable_set_enadis_phy_chip_idle_loop", "cable_set_enadis_phy_chip_idle_loop, Functionn has 1 argument 1.disable") - - ## WATCHDOG - self.debug_dump_list["watchdog_self"] = func_name_args(1, "enable_disable_watchdog_tor", "enable or disable the watchdog tor self, Functionn has 1 argument 1.disable") - self.debug_dump_list["watchdog_peer"] = func_name_args(1, "enable_disable_watchdog_peer_tor", "enable or disable the watchdog tor peer, Functionn has 1 argument 1.disable") - self.debug_dump_list["watchdog_nic"] = func_name_args(1, "cable_enable_disable_watchdog_nic", "enable or disable the watchdog nic, Functionn has 1 argument 1.disable") - - self.debug_dump_list["util_print_ctx_debug"] = func_name_args(0, "util_print_ctx_debug", "print, Functionn has no argument") - - ## CRASH DUMP - self.debug_dump_list["nic_mcu_dump"] = func_name_args(0, "cable_print_nic_mcu_dump", "gets the nic crash, Functionn has no argument") - self.debug_dump_list["clear_nic_mcu_dump"] = func_name_args(0, "cable_clear_nic_mcu_dump", "clears the nic crash, Functionn has no argument") - self.debug_dump_list["tor_mcu_dump"] = func_name_args(0, "cable_print_tor_mcu_dump", "gets the tor crash, Functionn has no argument") - self.debug_dump_list["clear_tor_mcu_dump"] = func_name_args(0, "cable_clear_tor_mcu_dump", "clears the tor crash, Functionn has no argument") - - -############################################################################################# -### Broadcom internal/debug/utility functions ### -############################################################################################# - - def enable_all_log(self, enable): - if enable: - self.CONSOLE_PRINT = True - if self.logger is not None: - self.logger.set_min_log_priority(9) - print("Logging enabled...") - else: - self.CONSOLE_PRINT = False - if self.logger is not None: - self.logger.set_min_log_priority(7) - print("Logging disabled...") - - def __get_pid_str(self): - pid_str = "[{},{}] BCM_YCABLE Port-{} : ".format(os.getpid(), threading.currentThread().getName(), self.port) - return pid_str - - def log_timestamp(self, last_timestamp, log_msg): - curr_timestamp = datetime.utcnow() - cur_tstr = curr_timestamp.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] - difftime = curr_timestamp - last_timestamp - - tstr = "({}s {}ms)".format(difftime.seconds, difftime.microseconds//1000) - ret_str = cur_tstr + tstr - self.log(self.LOG_DEBUG, "{} : {}".format(ret_str, log_msg)) - - return curr_timestamp - - def log(self, level, msg, also_print_to_console=False): - - msg = self.__get_pid_str() + msg - also_print_to_console = True if self.CONSOLE_PRINT else also_print_to_console - - if level == self.LOG_INFO: - self.logger.log_info(msg) - elif level == self.LOG_WARN: - self.logger.log_warning(msg) - elif level == self.LOG_DEBUG: - self.logger.log_debug(msg) - elif level == self.LOG_ERROR: - self.logger.log_error(msg) - - if self.CONSOLE_PRINT or also_print_to_console: - curr_timestamp = datetime.utcnow() - cur_tstr = curr_timestamp.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] - msg = cur_tstr + " " + msg - print(msg) - - def log_start(self, msg): - self.log(self.LOG_DEBUG, msg + " Start") - - def log_end(self, msg): - self.log(self.LOG_DEBUG, msg + " Exit") - - def __util_convert_to_phyinfo_details(self, target, lane_map): - """ - - This util API is internally used to simplify the calculation of core_ip, lane_mask - - """ - - if target == self.TARGET_NIC or target == self.EYE_PRBS_LOOPBACK_TARGET_NIC: - core_ip = self.CORE_IP_NIC - else: - core_ip = self.CORE_IP_TOR - - read_side = self.get_read_side() - is_torA = False - - if read_side == 1: - is_torA = True - elif read_side == 0 and target == self.EYE_PRBS_LOOPBACK_TARGET_LOCAL: - core_ip = self.CORE_IP_NIC - - if (target == self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - target = read_side - - # if check is on TOR-B, make is_torA False - if (target == self.TARGET_TOR_B or target == self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and read_side == self.TARGET_TOR_A: - is_torA = False - # if check is on TOR-A and read side is TOR-B, make is_torA False - elif (((target == self.TARGET_TOR_A or target == self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and read_side == self.TARGET_TOR_B) or - ((target == self.TARGET_TOR_A or target == self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and read_side == self.TARGET_NIC)): - is_torA = True - - #lane_mask = lane_map - - if core_ip == self.CORE_IP_NIC: - lane_mask = lane_map - else: - if is_torA is False: - lane_mask = ((lane_map << 4) & 0xF0) | ((lane_map >> 4) & 0x0F) - else: - lane_mask = lane_map - - if core_ip == self.CORE_IP_TOR: - core_ip = self.CORE_IP_CLIENT - elif core_ip == self.CORE_IP_NIC: - core_ip = self.CORE_IP_LW - else: - core_ip = self.CORE_IP_ALL - - return core_ip, lane_mask - - def __util_convert_to_loopback_phyinfo(self, target, lane_map, lb_mode): - """ - - This util API is internally used to simplify the calculation of core_ip, lane_mask - - """ - - if target == self.TARGET_NIC or target == self.EYE_PRBS_LOOPBACK_TARGET_NIC: - core_ip = self.CORE_IP_NIC - else: - core_ip = self.CORE_IP_TOR - - read_side = self.get_read_side() - is_torA = False - - if read_side == self.TARGET_TOR_A: - is_torA = True - elif read_side == 0 and target == self.EYE_PRBS_LOOPBACK_TARGET_LOCAL: - core_ip = self.CORE_IP_NIC - - if (target == self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - target = read_side - - # if target is TOR-B, but read_side is TOR-A, make is_torA False - if (target == self.TARGET_TOR_B or target == self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and read_side == self.TARGET_TOR_A: - is_torA = False - # if target is TOR-A but read_side is TOR-B, make is_torA True - elif (((target == self.TARGET_TOR_A or target == self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and read_side == self.TARGET_TOR_B) or - ((target == self.TARGET_TOR_A or target == self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and read_side == self.TARGET_NIC)): - is_torA = True - - #lane_mask = lane_map - - if core_ip == self.CORE_IP_NIC: - lane_mask = lane_map - if lb_mode == self.LOOPBACK_MODE_FAR_END: - mode = self.CABLE_NIC_GLOOPBACK_MODE - elif lb_mode == self.LOOPBACK_MODE_NEAR_END: - mode = self.CABLE_NIC_RLOOPBACK_MODE - else: - self.log(self.LOG_ERROR, "Incorrect mode value") - return self.ERROR_INVALID_INPUT - - else: - if is_torA is False: - lane_mask = ((lane_map << 4) & 0xF0) | ((lane_map >> 4) & 0x0F) - if lb_mode == self.LOOPBACK_MODE_FAR_END: - mode = self.CABLE_TOR_GLOOPBACK_MODE - elif lb_mode == self.LOOPBACK_MODE_NEAR_END: - mode = self.CABLE_TOR_RLOOPBACK_MODE - else: - self.log(self.LOG_ERROR, "Incorrect mode value") - return self.ERROR_INVALID_INPUT - else: - lane_mask = lane_map - if lb_mode == self.LOOPBACK_MODE_FAR_END: - mode = self.CABLE_TOR_GLOOPBACK_MODE - elif lb_mode == self.LOOPBACK_MODE_NEAR_END: - mode = self.CABLE_TOR_RLOOPBACK_MODE - else: - self.log(self.LOG_ERROR, "Incorrect mode value") - return self.ERROR_INVALID_INPUT - - if core_ip == self.CORE_IP_TOR: - core_ip = self.CORE_IP_CLIENT - elif core_ip == self.CORE_IP_NIC: - core_ip = self.CORE_IP_LW - else: - core_ip = self.CORE_IP_ALL - - return core_ip, lane_mask, mode - - def __cable_cmd_execute(self, command_id, cmd_hdr, cmd_req_body): - """ - Internal function, sends command request to MCU and returns the response from MCU - - Args: - command_id: - Command ID - cmd_hdr - command header containing details of the command - cmd_req_body - command request payload, to be sent to MCU - - Returns: - an integer, 0 if transaction is successful - , -N for failure - byte array, cmd_rsp_body containing command response - """ - - start_ts = datetime.utcnow() - ts = datetime.utcnow() - curr_offset = None - cmd_rsp_body = None - ret_val = 0 - - if self.platform_chassis is not None: - - debug_print("Trying for the lock") - with self.lock.acquire_timeout(self.PORT_LOCK_TIMEOUT) as result: - if result: - ts = self.log_timestamp(ts, "lock acquired") - # read cable command and status offsets - curr_offset = self.QSFP_BRCM_CABLE_CMD - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 2) - if result is None: - self.log(self.LOG_ERROR, "read eeprom failed") - return self.EEPROM_ERROR, None - - cmd_req = result[0] - cmd_sts = result[1] - ts = self.log_timestamp(ts, "read cmd/sts done") - - # if command request and status both are 1, - # write 0 to cmd req and - # wait for status to go 0 - if ((cmd_req & 0x01) == 1) and ((cmd_sts & 0x01) == 1): - cmd_req = 0 - curr_offset = self.QSFP_BRCM_CABLE_CMD - buffer1 = bytearray([cmd_req]) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer1) - if result is False: - return self.ERROR_WR_EEPROM_FAILED, None - - # poll command status for 100ms - start = time.monotonic_ns() - ms_elapsed = 0 - while (ms_elapsed < 100): - sta = 0 - curr_offset = self.QSFP_BRCM_CABLE_CTRL_CMD_STS - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - return self.EEPROM_ERROR, None - sta = result[0] - - if (sta & 0x01) == 0x0: - break - ms_elapsed = (time.monotonic_ns()//1000000) - (start//1000000) - else: - self.log(self.LOG_ERROR, "CMD_REQ/STS both are stuck at 1") - return self.ERROR_CMD_STS_CHECK_FAILED, None - ts = self.log_timestamp(ts, "resetting cmd to 0 done (error logic)") - self.log(self.LOG_DEBUG, "Currently processing COMMAND ID is {}".format(command_id)) - # check if any command is currently being executed - if ((cmd_req & 0x01) == 0) and ((cmd_sts & 0x01) == 0): - # - # Combine the write of the cable command header - # - write the request parameter len - # - write the response parameter len - # - write the BH lane mask (Client) - # - write the LW lane mask (Line) - # - write the core ip value - # - - # skip sending cmd_hdr for SET_HMUX_CONTEXT_PRI and SET_HMUX_CONTEXT_SEC - if ((command_id < self.CABLE_CMD_ID_SET_HMUX_CONTEXT_PRI) or - (command_id >= self.CABLE_CMD_ID_READ_MCU_RAM)): - curr_offset = self.QSFP_VEN_FE_130_BRCM_DATA_LENGHT_LSB - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 5, cmd_hdr) - if result is False: - self.log(self.LOG_ERROR, "write_eeprom() failed") - return self.ERROR_WRITE_EEPROM_FAILED, None - ts = self.log_timestamp(ts, "writing of cmd_hdr 5 bytes done") - else: - curr_offset = self.QSFP_VEN_FE_130_BRCM_DATA_LENGHT_LSB + 1 - cmd_rsp_len = cmd_hdr[1] - buffer1 = bytearray([cmd_rsp_len]) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer1) - if result is False: - self.log(self.LOG_ERROR, "write_eeprom() failed") - return self.ERROR_WRITE_EEPROM_FAILED, None - ts = self.log_timestamp(ts, "writing of cmd_hdr (only rsp_len) 1 byte done") - - # write request data - wr_len = cmd_hdr[0] - if wr_len > 0: - curr_offset = self.CMD_REQ_PARAM_START_OFFSET - result = self.platform_chassis.get_sfp( - self.port).write_eeprom(curr_offset, wr_len, cmd_req_body) - if result is False: - return self.ERROR_WR_EEPROM_FAILED, None - ts = self.log_timestamp(ts, "write request data done - bytes {}".format(wr_len)) - - # write the command request byte now - cmd_req = 1 - cmd_req = (cmd_req | (command_id << 1)) - curr_offset = self.QSFP_BRCM_CABLE_CMD - buffer1 = bytearray([cmd_req]) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer1) - if result is False: - return self.ERROR_WR_EEPROM_FAILED, None - rd = False - ts = self.log_timestamp(ts, "write command request to 1 done") - - error = 0 - start = time.monotonic_ns() - ms_elapsed = 0 - while (ms_elapsed < 500): - sta = 0 - curr_offset = self.QSFP_BRCM_CABLE_CTRL_CMD_STS - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - return self.EEPROM_ERROR, None - sta = result[0] - - if (sta & 0x7F) == 0x11: - rd = True - break - - if (sta & 0x7F) == 0x31: - #rd = True - error = 1 - self.log(self.LOG_ERROR, "ERROR: NIC command failed") - break - - ms_elapsed = (time.monotonic_ns()//1000000) - (start//1000000) - else: - self.log(self.LOG_ERROR, "CMD_STS never read as 0x11 or 0x31. reg_value: {}".format(hex(sta))) - ret_val = self.ERROR_CMD_PROCESSING_FAILED - ts = self.log_timestamp(ts, "polling for status done") - - # read response data - if rd is True: - rd_len = cmd_hdr[1] - if rd_len > 0: - curr_offset = self.CMD_RSP_PARAM_START_OFFSET - cmd_rsp_body = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, rd_len) - if cmd_rsp_body is None: - return self.EEPROM_ERROR, None - ts = self.log_timestamp(ts, "read cmd response bytes {} done".format(rd_len)) - - # set the command request to idle state - cmd_req = 0 - curr_offset = self.QSFP_BRCM_CABLE_CMD - buffer1 = bytearray([cmd_req]) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer1) - if result is False: - self.log(self.LOG_ERROR, "write eeprom failed for CMD_req") - return self.ERROR_WRITE_EEPROM_FAILED, None - ts = self.log_timestamp(ts, "write command request to 0 done") - - # wait for MCU response to be pulled down - start = time.monotonic_ns() - ms_elapsed = 0 - while (ms_elapsed < 2000): - sta = 0 - curr_offset = self.QSFP_BRCM_CABLE_CTRL_CMD_STS - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - return self.EEPROM_ERROR, None - sta = result[0] - - if (sta & 0x01) == 0x0: - break - ms_elapsed = (time.monotonic_ns()//1000000) - (start//1000000) - else: - ret_val = self.ERROR_MCU_NOT_RELEASED - self.log_timestamp(ts, "poll for MCU response to be puled down - done") - - if error: - return -1, None - - else: - ret_val = self.ERROR_MCU_BUSY - else: - self.log(self.LOG_ERROR, "Port lock timed-out!") - return self.ERROR_PORT_LOCK_TIMEOUT, None - - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check if link is Active on TOR B side") - return self.ERROR_PLATFORM_NOT_LOADED, None - - self.log_timestamp(start_ts, "__cable_cmd_execute() completed") - return ret_val, cmd_rsp_body - - def __validate_read_data(self, result, size, message): - ''' - This API specifically used to validate the register read value - ''' - - if result is not None: - if isinstance(result, bytearray): - if len(result) != size: - LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a size {} not equal to {} for port {}" - self.log(self.LOG_ERROR, LOG_MESSAGE_TEMPLATE.format(message, len(result), size, self.port)) - return self.EEPROM_READ_DATA_INVALID - else: - LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned an instance value of type {} which is not a bytearray for port {}" - self.log(self.LOG_ERROR, LOG_MESSAGE_TEMPLATE.format(message, type(result), self.port)) - return self.EEPROM_READ_DATA_INVALID - else: - LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a None value for port {} which is not expected" - self.log(self.LOG_ERROR, LOG_MESSAGE_TEMPLATE.format(message, self.port)) - return self.EEPROM_READ_DATA_INVALID - - -############################################################################## -# -# Public APIs -# -############################################################################## - - def get_api_version(self): - """ - Returns Broadcom y_cable api version - """ - return self.BCM_API_VERSION - - def get_part_number(self): - """ - This API specifically returns the part number of the Y cable for a specfic port. - - Args: - None - - Returns: - a string, with part number - """ - - if self.sfp is not None: - curr_offset = self.QSFP28_UP0_168_PN_1 - part_result = self.sfp.read_eeprom(curr_offset, 15) - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to get vendor name and pn_number") - return self.ERROR_PLATFORM_NOT_LOADED - - if self.__validate_read_data(part_result, 15, "get part_number") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - part_number = str(part_result.decode()) - self.log(self.LOG_DEBUG, "Part number = {}".format(part_number)) - - return part_number - - def get_serial_number(self): - """ - This API specifically returns the serial number of the Y cable for a specfic port. - - Args: - None - - Returns: - a string, with part number - """ - - if self.sfp is not None: - curr_offset = self.QSFP28_UP0_168_SN_1 - sn_result = self.sfp.read_eeprom(curr_offset, 15) - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to get vendor name and sn_number") - return self.ERROR_PLATFORM_NOT_LOADED - - if self.__validate_read_data(sn_result, 15, "get serial_number") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - sn_number = str(sn_result.decode()) - self.log(self.LOG_DEBUG, "Serial number = {}".format(sn_number)) - - return sn_number - - def get_date_code(self): - """ - This API specifically returns the date code of the Y cable for a specfic port. - - Args: - None - - Returns: - a string, with part number - """ - - if self.sfp is not None: - curr_offset = self.QSFP28_UP0_DATE_CODE - dcode_result = self.sfp.read_eeprom(curr_offset, 7) - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to date code") - return self.ERROR_PLATFORM_NOT_LOADED - - if self.__validate_read_data(dcode_result, 7, "get date_code") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - dt_code = str(dcode_result.decode()) - self.log(self.LOG_DEBUG, "Date Code = {}".format(dt_code)) - - return dt_code - - def get_vendor(self): - """ - This API returns the vendor name of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - None - Returns: - a string, with vendor name - """ - - if self.platform_chassis is not None: - curr_offset = self.QSFP28_UP0_148_VENDOR_NAME_0 - vendor_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 15) - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to get vendor name ") - return self.ERROR_PLATFORM_NOT_LOADED - - if self.__validate_read_data(vendor_result, 15, "Vendor_name") == -1: - return self.EEPROM_ERROR - - vendor_name = str(vendor_result.decode()) - self.log(self.LOG_DEBUG, "vendor name = {}".format(vendor_name)) - - return vendor_name - - def get_read_side(self): - """ - This API checks which side of the Y cable the reads are actually getting performed - from, either TOR A or TOR B or NIC and returns the value. - The port on which this API is called for can be referred using self.port. - - Args: - None - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if reading the Y cable from TOR A side. - TARGET_TOR_B, if reading the Y cable from TOR B side. - TARGET_NIC, if reading the Y cable from NIC side. - TARGET_UNKNOWN, if reading the Y cable API fails. - """ - - #start_ts = datetime.utcnow() - #ts = self.log_timestamp(start_ts, " get_read_side() start") - - if self.platform_chassis is not None: - curr_offset = self.QSFP28_UP0_224_SPECIFIC_1_RSV - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check read side") - return self.ERROR_PLATFORM_NOT_LOADED - - if self.__validate_read_data(result, 1, "read side") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - read_side = struct.unpack(" NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if the link is active - , False if the link is not active - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - if self.platform_chassis is not None: - curr_offset = self.QSFP28_VENFD_216_LINK_STATUS - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check link is active for TOR A side") - return self.ERROR_PLATFORM_NOT_LOADED - - if self.__validate_read_data(result, 1, "link is active for TOR A side") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - regval_read = struct.unpack(" manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched - """ - - if switch_count_type == self.SWITCH_COUNT_AUTO: - cmd_id = self.CABLE_CMD_ID_GET_TOT_AUT_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_TOT_AUT_SWT_CNT - elif switch_count_type == self.SWITCH_COUNT_MANUAL: - cmd_id = self.CABLE_CMD_ID_GET_TOT_MAN_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_TOT_MAN_SWT_CNT - else: - self.log(self.LOG_ERROR, "Invalid switch_count_type {}".format(switch_count_type)) - return self.ERROR_INVALID_INPUT - - count_value = self.util_get_switch_count(cmd_id) - self.log(self.LOG_INFO, "get_switch_count_total value = {} ".format(count_value)) - - return count_value - - def get_switch_count_tor_a(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR A - This is essentially all the successful switches initiated from ToR A. Toggles which were - initiated to toggle from ToR A and did not succed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR A - """ - - cmd_id = self.CABLE_CMD_ID_GET_FM_TORA_MAN_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_FM_TORA_MAN_SWT_CNT - - count_value = self.util_get_switch_count(cmd_id) - self.log(self.LOG_INFO, "get_switch_count_tor_a value = {} ".format(count_value)) - - return count_value - - def get_switch_count_tor_b(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR B - This is essentially all the successful switches initiated from ToR B. Toggles which were - initiated to toggle from ToR B and did not succed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR B - """ - - cmd_id = self.CABLE_CMD_ID_GET_FM_TORB_MAN_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_FM_TORB_MAN_SWT_CNT - - count_value = self.util_get_switch_count(cmd_id) - self.log(self.LOG_INFO, "get_switch_count_tor_b value = {} ".format(count_value)) - - return count_value - - def get_switch_count_target(self, switch_count_type, target, clear_on_read=False): - """ - This API returns the total number of times the Active TOR has - been done manually/automaticlly toggled towards a target. - For example, TARGET_TOR_A as target would imply - how many times the mux has been toggled towards TOR A. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times manually the Y-cable has been switched - """ - - if (target == self.TARGET_TOR_A): - if switch_count_type == self.SWITCH_COUNT_AUTO: - cmd_id = self.CABLE_CMD_ID_GET_TO_TORA_AUT_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_TO_TORA_AUT_SWT_CNT - elif switch_count_type == self.SWITCH_COUNT_MANUAL: - cmd_id = self.CABLE_CMD_ID_GET_TO_TORA_MAN_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_TO_TORA_MAN_SWT_CNT - else: - self.log(self.LOG_ERROR, "Invalid switch_count_type {}".format(switch_count_type)) - return self.ERROR_INVALID_INPUT - - elif (target == self.TARGET_TOR_B): - if switch_count_type == self.SWITCH_COUNT_AUTO: - cmd_id = self.CABLE_CMD_ID_GET_TO_TORB_AUT_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_TO_TORB_AUT_SWT_CNT - elif switch_count_type == self.SWITCH_COUNT_MANUAL: - cmd_id = self.CABLE_CMD_ID_GET_TO_TORB_MAN_SWT_CNT_CLR if ( - clear_on_read) else self.CABLE_CMD_ID_GET_TO_TORB_MAN_SWT_CNT - else: - self.log(self.LOG_ERROR, "Invalid switch_count_type {}".format(switch_count_type)) - return self.ERROR_INVALID_INPUT - - else: - self.log(self.LOG_ERROR, "Invalid target") - return self.ERROR_INVALID_TARGET - - count_value = self.util_get_switch_count(cmd_id) - self.log(self.LOG_INFO, "get_switch_count_target {} count_value = {} ".format( - ("TOR_A" if target == self.TARGET_TOR_A else "TOR_B"), count_value)) - - return count_value - - def __util_read_eeprom(self, curr_offset, rd_len, message): - """ - This API is internally used for read and validate - """ - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, rd_len) - - if self.__validate_read_data(result, rd_len, message) == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - return result - - def __handle_ver_error(self, upgrade_info, error): - - self.log(self.LOG_ERROR, "ERROR : {} Sending abort".format(error)) - - self.__cable_fw_ver_mcu_abort(upgrade_info) - time.sleep(0.001) - - def __handle_ver_cmd(self, upgrade_info, cmd_handle): - - ret_val = self.RR_ERROR - dat = bytearray(100) - req_status = False - info_stat = 0 - dat[0] = 0x00 - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) - if result is False: - return self.ERROR_WRITE_EEPROM_FAILED - - # Send destination - dat[0] = upgrade_info.destination - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_HEADER_24_31) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Send cmd request - dat[0] = (cmd_handle.cmd_wr << 1) | 1 - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Delay reading status as this can block during swap. - time.sleep(0.1) - - - for _ in range(0, 100): - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CMD_STS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__handle_ver_cmd read eeprom failed") - return self.EEPROM_ERROR - if status[0] & 0x01: - if (((status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2)) or ((status[0] & 0xFC) == (self.FW_UP_IN_PROGRESS << 2))): - if((status[0] & 0xFC) == (self.FW_UP_IN_PROGRESS << 2)): - info_stat = 1 - - if cmd_handle.read_info == 1: - curr_offset = (self.QSFP_BRCM_FW_VERSION_PAGE*128) + cmd_handle.cmd_rd - cmd_handle.data_read = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, cmd_handle.info_len) - if cmd_handle.data_read is None: - self.log(self.LOG_ERROR, "__cmd_handle read eeprom failed") - return self.EEPROM_ERROR - req_status = True - break - else: - self.log(self.LOG_ERROR, "CMD {} failed".format(cmd_handle.cmd_wr)) - self.__handle_ver_error(upgrade_info, status[0]) - return ret_val - time.sleep(0.001) - - if req_status: - req_status = False - # set the command request to idle state - self.log(self.LOG_DEBUG, "set the command request to idle state ") - dat[0] = 0x00 - curr_offset = (self.QSFP_BRCM_FW_VERSION_PAGE*128 + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Delay reading status as this can block during swap. - time.sleep(0.001) - - - # wait for mcu response to be pulled down - self.log(self.LOG_DEBUG, "wait for mcu response to be pulled down ") - for _ in range(100): - curr_offset = (self.QSFP_BRCM_FW_VERSION_PAGE*128 + self.QSFP_BRCM_FW_VERSION_CMD_STS) - status = self.__util_read_eeprom(curr_offset, 1, "__handle_cmd") - if status is None: - self.log(self.LOG_ERROR, "__handle_cmd: read_eeprom failed") - return self.EEPROM_ERROR - - if (status[0] & 0x01) == 0: - req_status = True - break - - time.sleep(0.001) - - if not req_status: - # Timeout, no response to pull down - self.log(self.LOG_ERROR, "Timeout waiting pull down") - self.__handle_ver_error(upgrade_info, 1) - return ret_val - elif info_stat == 1: - self.log(self.LOG_ERROR, "System Unavailable") - ret_val = self.RR_ERROR_SYSTEM_UNAVAILABLE - return ret_val - else: - ret_val = self.RR_SUCCESS - return ret_val - else: - # Timeout, no response to pull down - self.log(self.LOG_ERROR, "ERROR: Timeout waiting for cmd {} status in __handle_ver_cmd()".format(cmd_handle.cmd_wr)) - self.__handle_ver_error(upgrade_info, 1) - return self.RR_ERROR - - - def __cable_fw_ver_mcu_abort(self, upgrade_info): - """ - Internal API used to abort the execution of FW related function in case of error - - Args: - upgrade_info : MCU details - """ - ret_val = self.RR_ERROR - dat = bytearray(30) - status = 0 - req_status = False - - - read_side = self.get_read_side() - - if read_side == 0x02: - self.log(self.LOG_DEBUG, "Current side: TOR B") - elif read_side == 0x01: - self.log(self.LOG_DEBUG, "Current side TOR A") - elif read_side == 0x04: - self.log(self.LOG_DEBUG, "Current side NIC") - else: - self.log(self.LOG_ERROR, "Current side UNKNOWN") - return self.ERROR_READ_SIDE_FAILED - - # Make sure TOR to NIC MCU communication is alive - self.log(self.LOG_DEBUG, "Make sure TOR to NIC MCU communication is alive ") - if (upgrade_info.destination == self.NIC_MCU) and ((read_side == 0x02) or (read_side == 0x01)): - # Since we are running from TOR side, make sure no flush is on going - for _ in range(3000): - curr_offset = ((self.QSFP_BRCM_DIAGNOSTIC_PAGE * 128) + self.QSFP_BRCM_DIAGNOSTIC_STATUS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__cable_fw_ver_mcu_abort read eeprom failed") - return self.EEPROM_ERROR - - if status[0] == 0: - break - - time.sleep(0.001) - - if status[0]: - self.log(self.LOG_ERROR, "Unable to communicate with NIC MCU") - return self.ERROR_RW_NIC_FAILED - - # Make sure to clear command first else can have unforseen consequences - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Send destination - dat[0] = upgrade_info.destination - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_HEADER_24_31) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Send Abort request - dat[0] = (self.FW_CMD_ABORT << 1) | 1 - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - time.sleep(0.3) - - # Check response status - for _ in range(100): - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CMD_STS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - return self.EEPROM_ERROR - - if (status[0] & 0x01) == 0: - req_status = True - ret_val = self.RR_SUCCESS - - # Set the command request to idle state - dat[0] = 0x00 - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - break - time.sleep(0.001) - - if not req_status: - # Pull down anyway - dat[0] = 0x00 - curr_offset = ((self.QSFP_BRCM_FW_VERSION_PAGE*128) + self.QSFP_BRCM_FW_VERSION_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - return ret_val - - def __handle_error_abort(self, upgrade_info, error): - """ - Internal API used to abort in case of error in FW related functions - """ - self.log(self.LOG_ERROR, "ERROR : {}, Sending abort".format(error)) - self.__cable_fw_mcu_abort(upgrade_info) - time.sleep(0.001) - - def __handle_error(self, error): - """ - Internal API to handle error in FW related APIs - """ - dat = bytearray(30) - status = 0 - - self.log(self.LOG_ERROR, "ERROR : {} FAILED".format(error)) - - if self.platform_chassis is not None: - - # set the command request to idle state - dat[0] = 0x00 - curr_offset = (self.QSFP_BRCM_FW_UPGRADE_PAGE * 128) + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) - if result is False: - return self.ERROR_WRITE_EEPROM_FAILED - - # wait for mcu response to be pulled down - for _ in range(30): - curr_offset = (self.QSFP_BRCM_FW_UPGRADE_PAGE * 128) + self.QSFP_BRCM_FW_UPGRADE_CMD_STS - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__handle_error read eeprom failed") - return self.EEPROM_ERROR - - if (status[0] & 0x01) == 0: - return - time.sleep(0.001) - - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to handle_error") - return self.ERROR_PLATFORM_NOT_LOADED - - def __cable_fw_mcu_abort(self, upgrade_info): - """ - Internal API used to abort the execution of FW related function in case of error - - Args: - upgrade_info : MCU details - """ - ret_val = self.RR_ERROR - dat = bytearray(30) - status = 0 - req_status = False - - read_side = self.get_read_side() - - if read_side == 0x02: - self.log(self.LOG_DEBUG, "Current side: TOR B") - elif read_side == 0x01: - self.log(self.LOG_DEBUG, "Current side TOR A") - elif read_side == 0x04: - self.log(self.LOG_DEBUG, "Current side NIC") - else: - self.log(self.LOG_ERROR, "Current side UNKNOWN") - return self.ERROR_READ_SIDE_FAILED - - # Make sure TOR to NIC MCU communication is alive - self.log(self.LOG_DEBUG, "Make sure TOR to NIC MCU communication is alive ") - if (upgrade_info.destination == self.NIC_MCU) and ((read_side == 0x02) or (read_side == 0x01)): - # Since we are running from TOR side, make sure no flush is on going - for _ in range(3000): - curr_offset = ((self.QSFP_BRCM_DIAGNOSTIC_PAGE * 128) + self.QSFP_BRCM_DIAGNOSTIC_STATUS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__cable_fw_mcu_abort read eeprom failed") - return self.EEPROM_ERROR - - if status[0] == 0: - break - - time.sleep(0.001) - - if status[0]: - self.log(self.LOG_ERROR, "Unable to communicate with NIC MCU") - return self.ERROR_RW_NIC_FAILED - - # Make sure to clear command first else can have unforseen consequences - curr_offset = (self.QSFP_BRCM_FW_UPGRADE_PAGE*128) - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Send destination - dat[0] = upgrade_info.destination - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset + self.QSFP_BRCM_FW_UPGRADE_HEADER_24_31, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Send Abort request - dat[0] = (self.FW_CMD_ABORT << 1) | 1 - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - time.sleep(0.3) - - # Check response status - for _ in range(100): - status = self.platform_chassis.get_sfp(self.port).read_eeprom( - curr_offset + self.QSFP_BRCM_FW_UPGRADE_CMD_STS, 1) - if status is None: - return self.EEPROM_ERROR - - if (status[0] & 0x01) == 0: - req_status = True - ret_val = self.RR_SUCCESS - - # Set the command request to idle state - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - break - time.sleep(0.001) - - if not req_status: - # Pull down anyway - dat[0] = 0x00 - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - if not req_status: - self.log(self.LOG_ERROR, "Abort timeout. No response from MCU") - self.__handle_error(17) - return self.ERROR_CMD_TIMEOUT - - return ret_val - - def cable_fw_get_status(self, upgrade_info, crc_check_version=False): - """ - This function used internally to get the status information of existing firmware. - The status information has the following details, - 1. current bank - 2. bank1 firmware image version minor - 3. bank1 firmware image version major - 4. bank1 API image version minor - 5. bank1 API image version major - 6. bank1 image crc32 - 7. bank2 firmware image version minor - 8. bank2 firmware image version major - 9. bank2 API image version minor - 10. bank2 API image version major - 11. bank2 image crc32 - - upgrade_info: - an object of type cable_upgrade_type_s, must have upgrade_info.destination - set to MUX_CHIP or NIC_MCU or TOR_MCU - - Returns: - RR_SUCCESS : Success - RR_ERROR : Failed - ERROR_RW_NIC_FAILED : Unable to communicate with nic MCU - EEPROM_READ_DATA_INVALID : Read invalid data - RR_ERROR_SYSTEM_UNAVAILABLE : System unavaiable - ERROR_PLATFORM_NOT_LOADED : Platform not loaded - ERROR_PORT_LOCK_TIMEOUT : Port lock timeout - - """ - ret_val = self.RR_ERROR - cmd_handle = cmd_handle_s() - - # check argument type - if (upgrade_info is None): - self.log(self.LOG_ERROR, "ERROR : Argument type error in function [cable_fw_get_status] arg1 type [cable_upgrade_info_s] given {} arg2 type [bool] given {}".format(type(upgrade_info), type(crc_check_version))) - return self.ERROR_INVALID_INPUT - - if self.platform_chassis is not None: - # SEE which MCU it is: Assuming constant pages have been set for each MCU - - curr_offset = (0*128) + 0x6A - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - return self.EEPROM_ERROR - - if (status[0] == 1) and (crc_check_version == False): - - if(self.__pre_ver_cmd_check(upgrade_info) == self.RR_SUCCESS): - - cmd_handle.cmd_wr = self.FW_CMD_INFO - cmd_handle.read_info = 1 - cmd_handle.info_len = 26 - - if (status[0] == 1) and (crc_check_version == False): - # CMD version supported - self.log(self.LOG_DEBUG, "CMD version supported. calling handle_ver_cmd()") - cmd_handle.cmd_rd = self.QSFP_BRCM_FW_VERSION_CURRENT_BANK - ret_val = self.__handle_ver_cmd(upgrade_info, cmd_handle) - - if((ret_val != self.RR_SUCCESS) and (ret_val != self.RR_ERROR_SYSTEM_UNAVAILABLE)): - # Try with older version - self.log(self.LOG_DEBUG, "CMD version not supported. calling handle_cmd()") - cmd_handle.cmd_rd = self.QSFP_BRCM_FW_UPGRADE_CURRENT_BANK - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - else: - self.log(self.LOG_ERROR, "MCU not in the right state") - return ret_val - else: - if(self.__pre_cmd_check(upgrade_info) == self.RR_SUCCESS): - cmd_handle.cmd_wr = self.FW_CMD_INFO - cmd_handle.read_info = 1 - cmd_handle.info_len = 26 - - # CMD version not supported. CRC check performed in the FW - self.log(self.LOG_DEBUG, "CMD version not supported. calling handle_cmd()") - cmd_handle.cmd_rd = self.QSFP_BRCM_FW_UPGRADE_CURRENT_BANK - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - - else: - self.log(self.LOG_ERROR, "MCU not in the right state") - return ret_val - - # Current bank - upgrade_info.status_info.current_bank = cmd_handle.data_read[0] - upgrade_info.status_info.next_bank = cmd_handle.data_read[25] - - # Bank 1 minor fw version - upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor = ( - cmd_handle.data_read[2] << 8) | cmd_handle.data_read[1] - - # Bank 1 major fw version - upgrade_info.status_info.bank1_info.image_fw_version.image_version_major = ( - cmd_handle.data_read[4] << 8) | cmd_handle.data_read[3] - - # Bank 1 minor API version - upgrade_info.status_info.bank1_info.image_api_version.image_version_minor = ( - cmd_handle.data_read[6] << 8) | cmd_handle.data_read[5] - - # Bank 1 major API version - upgrade_info.status_info.bank1_info.image_api_version.image_version_major = ( - cmd_handle.data_read[8] << 8) | cmd_handle.data_read[7] - - # Bank 1 CRC32 - upgrade_info.status_info.bank1_info.image_crc32 = (cmd_handle.data_read[12] << 24) | ( - cmd_handle.data_read[11] << 16) | (cmd_handle.data_read[10] << 8) | cmd_handle.data_read[9] - # Bank 2 minor fw version - upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor = ( - cmd_handle.data_read[14] << 8) | cmd_handle.data_read[13] - - # Bank 2 major fw version - upgrade_info.status_info.bank2_info.image_fw_version.image_version_major = ( - cmd_handle.data_read[16] << 8) | cmd_handle.data_read[15] - - # Bank 2 minor API version - upgrade_info.status_info.bank2_info.image_api_version.image_version_minor = ( - cmd_handle.data_read[18] << 8) | cmd_handle.data_read[17] - - # Bank 2 major API version - upgrade_info.status_info.bank2_info.image_api_version.image_version_major = ( - cmd_handle.data_read[20] << 8) | cmd_handle.data_read[19] - - # Bank2 CRC32 - upgrade_info.status_info.bank2_info.image_crc32 = (cmd_handle.data_read[24] << 24) | ( - cmd_handle.data_read[23] << 16) | (cmd_handle.data_read[22] << 8) | cmd_handle.data_read[21] - - return ret_val - - def cable_fw_toggle_bcomp(self, upgrade_info): - """ - This API is internally used by activate firmware. Used to activate old FW only. - - Args: - upgrade_info: MCU details - """ - - ret_val = self.RR_ERROR - cmd_handle = cmd_handle_s() - - # check argument type - if(upgrade_info is None): - self.log(self.LOG_ERROR, "ERROR : Argument type error in function [cable_fw_toggle_bcomp] arg type [cable_upgrade_info_s] given {}".format(type(upgrade_info))) - return self.ERROR_INVALID_INPUT - - if self.platform_chassis is not None: - - if(self.__pre_cmd_check(upgrade_info) == self.RR_SUCCESS): - cmd_handle.cmd_wr = self.FW_CMD_SWAP - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - if (ret_val != self.RR_SUCCESS): - return ret_val - - # Do reset - time.sleep(0.3) - - ret_val = self.__cable_fw_mcu_reset(upgrade_info) - if(ret_val != self.RR_SUCCESS): - self.log(self.LOG_ERROR, "cable_fw_mcu_reset failed. ret_val {}".format(ret_val)) - return self.ERROR_RESET_FAILED - - time.sleep(0.3) - ret_val = self.RR_SUCCESS - - else: - self.log(self.LOG_ERROR, "MCU not in the right state") - - return ret_val - - def cable_fw_bank_toggle(self, upgrade_info): - ''' - This API is internally used by activate firmware - - Args: - upgrade_info: MCU details - ''' - ret_val = self.RR_ERROR - status = 0 - cmd_handle = cmd_handle_s() - - # check argument type - if(upgrade_info is None): - self.log(self.LOG_ERROR, "ERROR : Argument type error in function [cable_fw_bank_toggle] arg type [cable_upgrade_info_s] given {}".format(type(upgrade_info))) - return self.ERROR_INVALID_INPUT - - if self.platform_chassis is not None: - - if(self.__pre_cmd_check(upgrade_info) == self.RR_SUCCESS): - cmd_handle.cmd_wr = self.FW_CMD_SWAP - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - if (ret_val != self.RR_SUCCESS): - return ret_val - - # Do reset - time.sleep(0.3) - - ret_val = self.__cable_fw_mcu_reset(upgrade_info) - if(ret_val != self.RR_SUCCESS): - self.log(self.LOG_ERROR, "cable_fw_mcu_reset failed. ret_val {}".format(ret_val)) - return self.ERROR_RESET_FAILED - - time.sleep(0.3) - - cmd_handle.cmd_wr = self.FW_CMD_BOOT_STATUS - cmd_handle.read_info = 1 - cmd_handle.cmd_rd = self.QSFP_BRCM_FW_UPGRADE_BOOT_STATUS - cmd_handle.info_len = 1 - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - if(ret_val != self.RR_SUCCESS): - self.log(self.LOG_ERROR, "handle_cmd failed. ret_val {}".format(ret_val)) - return ret_val - - if upgrade_info.destination == self.NIC_MCU: - if cmd_handle.data_read[0] == 0: - # Reset went through. Check mux chip status - for _ in range(0, 3000): - curr_offset = ((self.QSFP_BRCM_DIAGNOSTIC_PAGE*128) + self.QSFP_BRCM_DIAGNOSTIC_STATUS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 2) - if status is None: - return self.EEPROM_ERROR - if status[0] == 0: - break - time.sleep(0.001) - - if status[0]: - self.log(self.LOG_ERROR, "Unable to communicate with MUX chip") - return self.RR_ERROR - - ret_val = self.RR_SUCCESS - return ret_val - - elif cmd_handle.data_read[0] == 1: - # RESET ERROR - self.log(self.LOG_ERROR, "COLD BOOT reset succeeded but MUX chip failed") - ret_val = self.RR_ERROR - return ret_val - else: - # RESET ERROR - self.log(self.LOG_ERROR, "COLD BOOT reset failed") - ret_val = self.RR_ERROR - return ret_val - else: - if cmd_handle.data_read[0] == 0: - ret_val = self.RR_SUCCESS - return ret_val - else: - # RESET ERROR - self.log(self.LOG_ERROR, "COLD BOOT reset failed") - ret_val = self.RR_ERROR - return ret_val - else: - self.log(self.LOG_ERROR, "MCU not in the right state") - - return ret_val - - def __cable_fw_warm_boot(self, upgrade_info): - - ret_val = self.RR_ERROR - status = 0 - cmd_handle = cmd_handle_s() - - if self.__pre_cmd_check(upgrade_info) == self.RR_SUCCESS: - cmd_handle.cmd_wr = self.FW_CMD_WARM_BOOT - - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - if ret_val != self.RR_SUCCESS: - return ret_val - time.sleep(2) - - cmd_handle.cmd_wr = self.FW_CMD_BOOT_STATUS - cmd_handle.read_info = 1 - cmd_handle.cmd_rd = self.QSFP_BRCM_FW_UPGRADE_BOOT_STATUS - cmd_handle.info_len = 1 - ret_val = self.__handle_cmd(upgrade_info, cmd_handle) - if(ret_val != self.RR_SUCCESS): - return ret_val - - if cmd_handle.data_read[0] == 0: - # Reset went through. Check mux chip status - for _ in range(0, 3000): - curr_offset = ((self.QSFP_BRCM_DIAGNOSTIC_PAGE*128) + self.QSFP_BRCM_DIAGNOSTIC_STATUS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__cmd_handle read eeprom failed") - return self.EEPROM_ERROR - - if status[0] == 0: - break - time.sleep(0.001) - - if status[0]: - self.log(self.LOG_ERROR, "Unable to communicate with MUX chip") - return self.RR_ERROR - - ret_val = self.RR_SUCCESS - return ret_val - - elif cmd_handle.data_read[0] == 1: - # RESET ERROR - self.log(self.LOG_ERROR, "WARM BOOT reset succeeded but MUX chip failed") - ret_val = self.RR_ERROR - return ret_val - else: - # RESET ERROR - self.log(self.LOG_ERROR, "WARM BOOT reset failed") - ret_val = self.RR_ERROR - return ret_val - else: - self.log(self.LOG_ERROR, "MCU not in the right state") - - return ret_val - - def __handle_cmd(self, upgrade_info, cmd_handle): - - ret_val = self.RR_ERROR - req_status = False - dat = bytearray(100) - info_stat = 0 - status = 0 - QSFP_PAGE_OFFSET = self.QSFP_BRCM_FW_UPGRADE_PAGE * 128 - - dat[0] = 0x00 - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) - if result is False: - return self.ERROR_WRITE_EEPROM_FAILED - - # Send destination - dat[0] = upgrade_info.destination - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_HEADER_24_31) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) - if result is False: - return self.ERROR_WRITE_EEPROM_FAILED - - # Send command request - dat[0] = (cmd_handle.cmd_wr << 1) | 1 - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) - if result is False: - return self.ERROR_WRITE_EEPROM_FAILED - - # Delay reading status as this can block during swap - time.sleep(0.1) - # time.sleep(1) - - # First check if any errors - for _ in range(0, 100): - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_CMD_STS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__cmd_handle read eeprom failed") - return self.EEPROM_ERROR - if status[0] & 0x01: - if (((status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2)) or ((status[0] & 0xFC) == (self.FW_UP_IN_PROGRESS << 2))): - if((status[0] & 0xFC) == (self.FW_UP_IN_PROGRESS << 2)): - info_stat = 1 - - if cmd_handle.read_info == 1: - curr_offset = (self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_1*128) + cmd_handle.cmd_rd - cmd_handle.data_read = self.platform_chassis.get_sfp( - self.port).read_eeprom(curr_offset, cmd_handle.info_len) - if cmd_handle.data_read is None: - self.log(self.LOG_ERROR, "__cmd_handle read eeprom failed") - return self.EEPROM_ERROR - req_status = True - break - else: - self.log(self.LOG_ERROR, "CMD {} failed".format(cmd_handle.cmd_wr)) - self.__handle_error_abort(upgrade_info, status[0]) - return ret_val - time.sleep(0.001) - - if req_status: - req_status = False - # set the command request to idle state - self.log(self.LOG_DEBUG, "set the command request to idle state ") - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - time.sleep(0.3) - - # wait for mcu response to be pulled down - self.log(self.LOG_DEBUG, "wait for mcu response to be pulled down ") - for _ in range(100): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "__handle_cmd") - if status is None: - self.log(self.LOG_ERROR, "__handle_cmd: read_eeprom failed") - return self.EEPROM_ERROR - - if (status[0] & 0x01) == 0: - req_status = True - break - - time.sleep(0.001) - - if not req_status: - # Timeout, no response to pull down - self.log(self.LOG_ERROR, "Timeout waiting pull down") - self.__handle_error_abort(upgrade_info, 1) - return ret_val - - elif info_stat == 1: - self.log(self.LOG_ERROR, "System unavailable") - ret_val = self.RR_ERROR_SYSTEM_UNAVAILABLE - return ret_val - else: - ret_val = self.RR_SUCCESS - return ret_val - else: - # Timeout, no response to pull down - self.log(self.LOG_ERROR, "Timeout waiting for cmd {} status".format(cmd_handle.cmd_wr)) - self.__handle_error_abort(upgrade_info, 1) - return ret_val - - def parse_image(self, upgrade_head, destination, fwfile): - - File_seek = 0 - image_compressed = 0 - image_offset = 0 - fw_up_buff = array.array('I', []) - - if (os.path.isfile(fwfile) != True): - self.log(self.LOG_ERROR, "ERROR : Fwfile {} is not present".format(fwfile)) - return self.RR_ERROR - - self.log(self.LOG_DEBUG, "parse_image for destination {} fwfile {}".format(destination, fwfile)) - for i in range(self.MUX_FW_IMG_SIZE): - fw_up_buff.append(0) - - file1 = open(fwfile, 'rb') - if file1 is None: - self.log(self.LOG_ERROR, "File {} failed to open".format(fwfile)) - return self.RR_ERROR - - if (destination == self.TOR_MCU_SELF) or (destination == self.TOR_MCU_PEER): - # Check TOR current bank to find which TOR image to download - self.log(self.LOG_DEBUG, "Check TOR current bank to find which TOR image to download") - upgrade_head.cable_up_info.destination = destination - if (self.cable_fw_get_status(upgrade_head.cable_up_info, True) != self.RR_SUCCESS): - file1.close() - return self.RR_ERROR - if upgrade_head.cable_up_info.status_info.current_bank == 1: - # Select TOR bank 2 image - # First read TOR bank 1 image header to find header location of TOR bank2 image header - self.log(self.LOG_INFO, "First read TOR bank 1 image header to find header location of TOR bank2 image header") - file1.seek(image_offset + 0x10) - image_compressed = struct.unpack('I', file1.read(4))[0] - if image_compressed: - # Read compressed image size - File_seek = struct.unpack('I', file1.read(4))[0] - file1.seek(image_offset) - else: - # Read image size - file1.seek(image_offset) - File_seek = struct.unpack('I', file1.read(4))[0] - # Next set TOR bank2 image header location - File_seek += (image_offset + 0x28) - else: - File_seek = image_offset - # Parse TOR image now - self.log(self.LOG_INFO, "Parse TOR image now") - file1.seek(File_seek) - upgrade_head.cable_up_info.image_info.image_size = struct.unpack('I', file1.read(4))[0] - - fw_version_array = array.array('I', []) - for i in range(self.FW_IMG_INFO_SIZE): - if i < 4: - byte_val = file1.read(2) - fw_version_array.append(0) - fw_version_array[i] = struct.unpack('H', byte_val)[0] - else: - byte_val = file1.read(4) - fw_version_array.append(0) - fw_version_array[i] = struct.unpack('I', byte_val)[0] - break - - upgrade_head.compression = struct.unpack('I', file1.read(4))[0] - upgrade_head.compressed_size = struct.unpack('I', file1.read(4))[0] - upgrade_head.compressed_crc32 = struct.unpack('I', file1.read(4))[0] - upgrade_head.add_size = struct.unpack('I', file1.read(4))[0] - upgrade_head.add_crc32 = struct.unpack('I', file1.read(4))[0] - upgrade_head.header_crc32 = struct.unpack('I', file1.read(4))[0] - - for i in range(upgrade_head.cable_up_info.image_info.image_size): - byte_val = file1.read(4) - if len(byte_val) == 4: - fw_up_buff[i] = struct.unpack('I', byte_val)[0] - - upgrade_head.cable_up_info.image_info.image_fw_version.image_version_major = fw_version_array[1] - upgrade_head.cable_up_info.image_info.image_fw_version.image_version_minor = fw_version_array[0] - upgrade_head.cable_up_info.image_info.image_api_version.image_version_minor = fw_version_array[2] - upgrade_head.cable_up_info.image_info.image_api_version.image_version_major = fw_version_array[3] - upgrade_head.cable_up_info.image_info.image_crc32 = fw_version_array[4] - upgrade_head.cable_up_info.image_info.image_ptr = fw_up_buff - - if destination == self.TOR_MCU_SELF: - upgrade_head.cable_up_info.destination = self.TOR_MCU_SELF - else: - upgrade_head.cable_up_info.destination = self.TOR_MCU_PEER - - elif destination == self.NIC_MCU: - # Parse NIC image - self.log(self.LOG_INFO, "Parse NIC image") - # Seek to location of NIC bank1 image - file1.seek(0x10) - image_compressed = struct.unpack('I', file1.read(4))[0] - if image_compressed: - # Read compressed image size - image_offset = struct.unpack('I', file1.read(4))[0] - file1.seek(0) - else: - # Read image size - file1.seek(0) - image_offset = struct.unpack('I', file1.read(4))[0] - - image_offset += 0x28 - # Seek to TOR bank2 image - file1.seek(image_offset) - # Read TOR bank 2 image header to find header location of NIC bank1 image header - file1.seek((image_offset + 0x10)) - image_compressed = struct.unpack('I', file1.read(4))[0] - if image_compressed: - # Read compressed image size - File_seek = struct.unpack('I', file1.read(4))[0] - file1.seek(image_offset) - else: - # Read image size - file1.seek(image_offset) - File_seek = struct.unpack('I', file1.read(4))[0] - - # Seek to NIC bank1 image - File_seek += (image_offset + 0x28) - file1.seek(File_seek) - image_offset = File_seek - - # Check NIC current bank to find which NIC image to download - upgrade_head.cable_up_info.destination = destination - if (self.cable_fw_get_status(upgrade_head.cable_up_info, True) != self.RR_SUCCESS): - file1.close() - return self.RR_ERROR - - if upgrade_head.cable_up_info.status_info.current_bank == 1: - # Select NIC bank 2 image - # First read NIC bank 1 image header to find header location of NIC bank2 image header - file1.seek((image_offset + 0x10)) - image_compressed = struct.unpack('I', file1.read(4))[0] - - if image_compressed: - # Read compressed image size - File_seek = struct.unpack('I', file1.read(4))[0] - file1.seek(image_offset) - else: - # Read image size - file1.seek(image_offset) - File_seek = struct.unpack('I', file1.read(4))[0] - - # Next set NIC bank2 image header location - File_seek += (image_offset + 0x28) - else: - File_seek = image_offset - - file1.seek(File_seek) - upgrade_head.cable_up_info.image_info.image_size = struct.unpack('I', file1.read(4))[0] - - fw_version_array = array.array('I', []) - for i in range(self.FW_IMG_INFO_SIZE): - if i < 4: - byte_val = file1.read(2) - fw_version_array.append(0) - fw_version_array[i] = struct.unpack('H', byte_val)[0] - else: - byte_val = file1.read(4) - fw_version_array.append(0) - fw_version_array[i] = struct.unpack('I', byte_val)[0] - break - - upgrade_head.compression = struct.unpack('I', file1.read(4))[0] - upgrade_head.compressed_size = struct.unpack('I', file1.read(4))[0] - upgrade_head.compressed_crc32 = struct.unpack('I', file1.read(4))[0] - upgrade_head.add_size = struct.unpack('I', file1.read(4))[0] - upgrade_head.add_crc32 = struct.unpack('I', file1.read(4))[0] - upgrade_head.header_crc32 = struct.unpack('I', file1.read(4))[0] - - upgrade_head.cable_up_info.destination = self.NIC_MCU - - for i in range(upgrade_head.cable_up_info.image_info.image_size): - byte_val = file1.read(4) - if len(byte_val) == 4: - fw_up_buff[i] = struct.unpack('I', byte_val)[0] - - upgrade_head.cable_up_info.image_info.image_fw_version.image_version_major = fw_version_array[1] - upgrade_head.cable_up_info.image_info.image_fw_version.image_version_minor = fw_version_array[0] - upgrade_head.cable_up_info.image_info.image_api_version.image_version_minor = fw_version_array[2] - upgrade_head.cable_up_info.image_info.image_api_version.image_version_major = fw_version_array[3] - upgrade_head.cable_up_info.image_info.image_crc32 = fw_version_array[4] - upgrade_head.cable_up_info.image_info.image_ptr = fw_up_buff - upgrade_head.cable_up_info.destination = self.NIC_MCU - - elif destination == self.MUX_CHIP: - # Parse MUX CHIP image - # Seek to location of NIC bank1 image - file1.seek(0x10) - image_compressed = struct.unpack('I', file1.read(4))[0] - if image_compressed: - # Read compressed image size - image_offset = struct.unpack('I', file1.read(4))[0] - file1.seek(0) - else: - # Read image size - file1.seek(0) - image_offset = struct.unpack('I', file1.read(4))[0] - - image_offset += 0x28 - # Seek to TOR bank2 image - file1.seek(image_offset) - - # Read TOR bank 2 image header to find header location of NIC bank1 image header - file1.seek(image_offset + 0x10) - image_compressed = struct.unpack('I', file1.read(4))[0] - - if image_compressed: - # Read compressed image size - File_seek = struct.unpack('I', file1.read(4))[0] - file1.seek(image_offset) - else: - # Read image size - file1.seek(image_offset) - File_seek = struct.unpack('I', file1.read(4))[0] - - # Seek to NIC bank1 image - File_seek += (image_offset + 0x28) - file1.seek(File_seek) - image_offset = File_seek - - # Read NIC bank 1 image header to find header location of N - file1.seek(image_offset + 0x10) - image_compressed = struct.unpack('I', file1.read(4))[0] - if image_compressed: - # Read compressed image size - File_seek = struct.unpack('I', file1.read(4))[0] - file1.seek(image_offset) - else: - # Read image size - file1.seek(image_offset) - File_seek = struct.unpack('I', file1.read(4))[0] - - # Next set NIC bank2 image header location - File_seek += (image_offset + 0x28) - image_offset = File_seek - - file1.seek(File_seek + 0x10) - image_compressed = struct.unpack('I', file1.read(4))[0] - - if image_compressed: - # Read compressed image size - File_seek = struct.unpack('I', file1.read(4))[0] - file1.seek(image_offset) - else: - # Read image size - file1.seek(image_offset) - File_seek = struct.unpack('I', file1.read(4))[0] - - File_seek += (image_offset + 0x28) - file1.seek(File_seek) - #image_offset = File_seek - - upgrade_head.cable_up_info.image_info.image_size = struct.unpack('I', file1.read(4))[0] - - fw_version_array = array.array('I', []) - for i in range(self.FW_IMG_INFO_SIZE): - if i < 4: - byte_val = file1.read(2) - fw_version_array.append(0) - fw_version_array[i] = struct.unpack('H', byte_val)[0] - else: - byte_val = file1.read(4) - fw_version_array.append(0) - fw_version_array[i] = struct.unpack('I', byte_val)[0] - break - - upgrade_head.compression = struct.unpack('I', file1.read(4))[0] - upgrade_head.compressed_size = struct.unpack('I', file1.read(4))[0] - upgrade_head.compressed_crc32 = struct.unpack('I', file1.read(4))[0] - upgrade_head.add_size = struct.unpack('I', file1.read(4))[0] - upgrade_head.add_crc32 = struct.unpack('I', file1.read(4))[0] - upgrade_head.header_crc32 = struct.unpack('I', file1.read(4))[0] - - upgrade_head.cable_up_info.destination = self.MUX_CHIP - - for i in range(upgrade_head.cable_up_info.image_info.image_size): - byte_val = file1.read(4) - if len(byte_val) == 4: - fw_up_buff[i] = struct.unpack('I', byte_val)[0] - - upgrade_head.cable_up_info.image_info.image_fw_version.image_version_major = fw_version_array[1] - upgrade_head.cable_up_info.image_info.image_fw_version.image_version_minor = fw_version_array[0] - upgrade_head.cable_up_info.image_info.image_api_version.image_version_minor = fw_version_array[2] - upgrade_head.cable_up_info.image_info.image_api_version.image_version_major = fw_version_array[3] - upgrade_head.cable_up_info.image_info.image_crc32 = fw_version_array[4] - upgrade_head.cable_up_info.image_info.image_ptr = fw_up_buff - - else: - file1.close() - return self.RR_ERROR - - file1.close() - return self.RR_SUCCESS - - def __cable_fw_mcu_reset(self, upgrade_info): - - ret_val = self.RR_ERROR - dat = bytearray(30) - status = 0 - req_status = False - - if (self.__pre_cmd_check(upgrade_info) == self.RR_SUCCESS): - # If TOR MCU, reset self - if(upgrade_info.destination == self.TOR_MCU_SELF): - curr_offset = ((0x00*128) + 0x5D) - dat = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if dat is None: - return self.EEPROM_ERROR - dat[0] |= 0x80 - curr_offset = ((0x00*128) + 0x5D) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - time.sleep(1) - - # Check response status - for _ in range(0, 2000): - curr_offset = ((0x00*128) + 0x5D) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - return self.EEPROM_ERROR - - if (status[0] & 0x80) == 0: - ret_val = self.RR_SUCCESS - return ret_val - time.sleep(0.001) - - elif((upgrade_info.destination == self.TOR_MCU_PEER) or (upgrade_info.destination == self.NIC_MCU)): - if(upgrade_info.destination == self.TOR_MCU_PEER): - read_side = self.get_read_side() - if (read_side == self.TARGET_UNKNOWN): - self.log(self.LOG_ERROR, "ERROR: get_read_side Failed!") - return None - dat[0] = 0x02 if read_side == 0x01 else 0x01 - else: - dat[0] = 0x04 - curr_offset = ((0xFD*128) + 0xB8) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - if(upgrade_info.destination == self.NIC_MCU): - # MUST WAIT FOR mux CHIP TO BOOT - time.sleep(7.5) - - # Check response status - for _ in range(0, 2000): - curr_offset = ((0xFD*128) + 0xB8) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - return self.EEPROM_ERROR - - if ((status[0] & 0x01) == 0): - ret_val = self.RR_SUCCESS - return ret_val - time.sleep(0.001) - - # Should not be here unless no response - if not req_status: - # ERROR - return ret_val - - else: - self.log(self.LOG_ERROR, "MCU not in the right state") - - return ret_val - - def __pre_ver_cmd_check(self, upgrade_info): - - dat = bytearray(30) - QSFP_PAGE_OFFSET = self.QSFP_BRCM_FW_VERSION_PAGE * 128 - - read_side = self.get_read_side() - if read_side == self.TARGET_UNKNOWN: - self.log(self.LOG_ERROR, "ERROR: get_read_side Failed!") - return self.RR_ERROR - - #ts = datetime.utcnow() - # Make sure TOR to NIC MCU communication is alive - if upgrade_info.destination == self.NIC_MCU and ((read_side == 0x02) or (read_side == 0x01)): - # Since we are running from TOR side, make sure no flush is on going - for _ in range(0, 3000): - curr_offset = ((self.QSFP_BRCM_DIAGNOSTIC_PAGE*128) + self.QSFP_BRCM_DIAGNOSTIC_STATUS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__pre_cmd_check read eeprom failed") - return self.EEPROM_ERROR - if status[0] == 0: - break - time.sleep(0.001) - - if status[0]: - self.log(self.LOG_ERROR, "Unable to communicate with NIC MCU") - return self.ERROR_RW_NIC_FAILED - #ts = self.log_timestamp(ts,"TOR to NIC MCU communication is alive") - - # read cable command and status offsets - self.log(self.LOG_DEBUG, "read cable command and status offsets") - result = self.__util_read_eeprom((QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_VERSION_CTRL_CMD), 2, "pre_cmd_check") - if result is None: - return self.EEPROM_ERROR - if result != self.EEPROM_READ_DATA_INVALID: - dat[0] = result[0] - dat[1] = result[1] - - if ((dat[0] & 0x01) != 0) or ((dat[1] & 0x01) != 0): - self.log(self.LOG_DEBUG, "MCU not in the right state. Sending abort") - ret_val = self.__cable_fw_ver_mcu_abort(upgrade_info) - if ret_val != self.RR_SUCCESS: - self.log(self.LOG_ERROR, "MCU abort failed") - return ret_val - - time.sleep(0.001) - result = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_VERSION_CTRL_CMD), 2, "pre_cmd_check") - if result is None: - return self.EEPROM_ERROR - - result = self.__util_read_eeprom((QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_VERSION_CTRL_CMD), 2, "pre_cmd_check") - if result is None: - return self.EEPROM_ERROR - if result != self.EEPROM_READ_DATA_INVALID: - dat[0] = result[0] - dat[1] = result[1] - if ((dat[0] & 0x01) == 0) and ((dat[1] & 0x01) == 0): - ret_val = self.RR_SUCCESS - else: - ret_val = self.RR_ERROR - - return ret_val - - def __pre_cmd_check(self, upgrade_info): - - dat = bytearray(30) - QSFP_PAGE_OFFSET = self.QSFP_BRCM_FW_UPGRADE_PAGE * 128 - - read_side = self.get_read_side() - if read_side == self.TARGET_UNKNOWN: - self.log(self.LOG_ERROR, "ERROR: get_read_side Failed!") - return self.RR_ERROR - - #ts = datetime.utcnow() - # Make sure TOR to NIC MCU communication is alive - if upgrade_info.destination == self.NIC_MCU and ((read_side == 0x02) or (read_side == 0x01)): - # Since we are running from TOR side, make sure no flush is on going - for _ in range(0, 3000): - curr_offset = ((self.QSFP_BRCM_DIAGNOSTIC_PAGE*128) + self.QSFP_BRCM_DIAGNOSTIC_STATUS) - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "__pre_cmd_check read eeprom failed") - return self.EEPROM_ERROR - if status[0] == 0: - break - time.sleep(0.001) - - if status[0]: - self.log(self.LOG_ERROR, "Unable to communicate with NIC MCU") - return self.ERROR_RW_NIC_FAILED - #ts = self.log_timestamp(ts,"TOR to NIC MCU communication is alive") - - # read cable command and status offsets - self.log(self.LOG_DEBUG, "read cable command and status offsets") - result = self.__util_read_eeprom((QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD), 2, "pre_cmd_check") - if result is None: - return self.EEPROM_ERROR - if result != self.EEPROM_READ_DATA_INVALID: - dat[0] = result[0] - dat[1] = result[1] - - if ((dat[0] & 0x01) != 0) or ((dat[1] & 0x01) != 0): - self.log(self.LOG_DEBUG, "MCU not in the right state. Sending abort") - ret_val = self.__cable_fw_mcu_abort(upgrade_info) - if ret_val != self.RR_SUCCESS: - self.log(self.LOG_ERROR, "MCU abort failed") - return ret_val - - time.sleep(0.001) - result = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD), 2, "pre_cmd_check") - if result is None: - return self.EEPROM_ERROR - - result = self.__util_read_eeprom((QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD), 2, "pre_cmd_check") - if result is None: - return self.EEPROM_ERROR - if result != self.EEPROM_READ_DATA_INVALID: - dat[0] = result[0] - dat[1] = result[1] - if ((dat[0] & 0x01) == 0) and ((dat[1] & 0x01) == 0): - ret_val = self.RR_SUCCESS - else: - ret_val = self.RR_ERROR - - return ret_val - - def __cable_fw_upgrade(self, upgrade_head): - """ - This function used internally to upgrade the firmware of TOR, NIC and MUX - physical_port: - an Integer, the actual physical port connected to a Y cable - - upgrade_info: - an object of type cable_upgrade_info_s, The destination, versions - and image_buffer must be set - - Returns - RR_SUCCESS Success - RR_ERROR Failures - ERROR_RW_NIC_FAILED Unable to comminicate NIC MCU - ERROR_INVALID_TARGET Wrong destination - ERROR_CMD_TIMEOUT Command Time out - """ - ret_val = self.RR_ERROR - dat = bytearray(128) - status = 0 - req_status = False - i = 0 - tmp_cnt = 0 - tmp_print = 0 - QSFP_PAGE_OFFSET = self.QSFP_BRCM_FW_UPGRADE_PAGE * 128 - start_tstamp = datetime.utcnow() - - if(self.__pre_cmd_check(upgrade_head.cable_up_info) == self.RR_SUCCESS): - # START CMD ============================================ - # Debug prints - self.log(self.LOG_DEBUG, "Starting firmware upgrade to {}".format("TOR MCU SELF" - if upgrade_head.cable_up_info.destination == self.TOR_MCU_SELF - else "TOR MCU PEER" if upgrade_head.cable_up_info.destination == self.TOR_MCU_PEER - else "NIC MCU" if upgrade_head.cable_up_info.destination == self.NIC_MCU else "MUX_CHIP")) - - self.log(self.LOG_DEBUG, "FW Version minor: {}".format( - hex(upgrade_head.cable_up_info.image_info.image_fw_version.image_version_minor))) - self.log(self.LOG_DEBUG, "FW Version major: {}".format( - hex(upgrade_head.cable_up_info.image_info.image_fw_version.image_version_major))) - if (upgrade_head.cable_up_info.destination == self.TOR_MCU_SELF or upgrade_head.cable_up_info.destination == self.TOR_MCU_PEER): - self.log(self.LOG_DEBUG, "API version minor: {}".format( - hex(upgrade_head.cable_up_info.image_info.image_api_version.image_version_minor))) - self.log(self.LOG_DEBUG, "API version major: {}".format( - hex(upgrade_head.cable_up_info.image_info.image_api_version.image_version_major))) - self.log(self.LOG_DEBUG, "CRC32 : {}".format(hex(upgrade_head.cable_up_info.image_info.image_crc32))) - self.log(self.LOG_DEBUG, "Image size : {}".format(hex(upgrade_head.cable_up_info.image_info.image_size))) - - ts = datetime.utcnow() - # Send image header - self.log(self.LOG_INFO, "send image header") - dat[0] = upgrade_head.cable_up_info.image_info.image_size & 0xff - dat[1] = (upgrade_head.cable_up_info.image_info.image_size >> 8) & 0xFF - dat[2] = (upgrade_head.cable_up_info.image_info.image_size >> 16) & 0xFF - dat[3] = upgrade_head.cable_up_info.destination - dat[4] = upgrade_head.cable_up_info.image_info.image_fw_version.image_version_minor & 0xFF - dat[5] = (upgrade_head.cable_up_info.image_info.image_fw_version.image_version_minor >> 8) & 0xFF - dat[6] = upgrade_head.cable_up_info.image_info.image_fw_version.image_version_major & 0xFF - dat[7] = (upgrade_head.cable_up_info.image_info.image_fw_version.image_version_major >> 8) & 0xFF - dat[8] = upgrade_head.cable_up_info.image_info.image_api_version.image_version_minor & 0xFF - dat[9] = (upgrade_head.cable_up_info.image_info.image_api_version.image_version_minor >> 8) & 0xFF - dat[10] = upgrade_head.cable_up_info.image_info.image_api_version.image_version_major & 0xFF - dat[11] = (upgrade_head.cable_up_info.image_info.image_api_version.image_version_major >> 8) & 0xFF - dat[12] = upgrade_head.cable_up_info.image_info.image_crc32 & 0xFF - dat[13] = (upgrade_head.cable_up_info.image_info.image_crc32 >> 8) & 0xFF - dat[14] = (upgrade_head.cable_up_info.image_info.image_crc32 >> 16) & 0xFF - dat[15] = (upgrade_head.cable_up_info.image_info.image_crc32 >> 24) & 0xFF - dat[16] = self.FW_UP_PACKET_SIZE - dat[17] = self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_1 - - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_HEADER_0_7, 18, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - ts = self.log_timestamp(ts, "Image header sent") - - # Write compression header - dat[0] = (upgrade_head.compression & 0xFF) - dat[1] = (upgrade_head.compressed_size & 0xFF) - dat[2] = ((upgrade_head.compressed_size >> 8) & 0xFF) - dat[3] = ((upgrade_head.compressed_size >> 16) & 0xFF) - dat[4] = ((upgrade_head.compressed_size >> 24) & 0xFF) - dat[5] = (upgrade_head.compressed_crc32 & 0xFF) - dat[6] = ((upgrade_head.compressed_crc32 >> 8) & 0xFF) - dat[7] = ((upgrade_head.compressed_crc32 >> 16) & 0xFF) - dat[8] = ((upgrade_head.compressed_crc32 >> 24) & 0xFF) - dat[9] = (upgrade_head.add_size & 0xFF) - dat[10] = ((upgrade_head.add_size >> 8) & 0xFF) - dat[11] = ((upgrade_head.add_size >> 16) & 0xFF) - dat[12] = ((upgrade_head.add_size >> 24) & 0xFF) - dat[13] = (upgrade_head.add_crc32 & 0xFF) - dat[14] = ((upgrade_head.add_crc32 >> 8) & 0xFF) - dat[15] = ((upgrade_head.add_crc32 >> 16) & 0xFF) - dat[16] = ((upgrade_head.add_crc32 >> 24) & 0xFF) - - # Header CRC - dat[17] = (upgrade_head.header_crc32 & 0xFF) - dat[18] = ((upgrade_head.header_crc32 >> 8) & 0xFF) - dat[19] = ((upgrade_head.header_crc32 >> 16) & 0xFF) - dat[20] = ((upgrade_head.header_crc32 >> 24) & 0xFF) - - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_COMP_SET) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 21, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - ## Bootloader support - dat[0] = (((upgrade_head.compression & 0xFF00) >> 8) & 0xFF) - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + self.QSFP_BRCM_FW_UPGRADE_BL_SUPPORT_0_7) - - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - ts = self.log_timestamp(ts, "compression header sent") - - # Send request firmware upgrad to START - self.log(self.LOG_INFO, "START ERASING") - - dat[0] = (self.FW_CMD_START << 1) | 1 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - time.sleep(3.5) - ts = self.log_timestamp(ts, "Erase command sent") - - # Check response status - self.log(self.LOG_DEBUG, "check MCU ready status") - for i in range(3000): - status = self.__util_read_eeprom( - (self.QSFP_BRCM_FW_UPGRADE_PAGE * 128 + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if status[0] & 0x01: - if (status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2): - self.log(self.LOG_DEBUG, "MCU is Ready") - req_status = True - break - else: - if (status[0] & 0xFC) == (self.FW_UP_IN_PROGRESS << 2): - ret_val = self.RR_ERROR_SYSTEM_UNAVAILABLE - self.log(self.LOG_WARN, "System Unavailable/busy...") - #self.__handle_error_abort(upgrade_head.cable_up_info, 1) - return ret_val - - time.sleep(0.001) - - ts = self.log_timestamp(ts, "MCU ready check done") - - # if MCU is ready - if req_status: - req_status = False - # set the command request to idle state - self.log(self.LOG_DEBUG, "set the command request to idle state ") - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # wait for mcu response to be pulled down - self.log(self.LOG_DEBUG, "wait for mcu response to be pulled down ") - for _ in range(100): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self. QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if (status[0] & 0x01) == 0: - req_status = True - break - - time.sleep(0.001) - - if not req_status: - self.log(self.LOG_ERROR, "Timeout ") - self.__handle_error_abort(upgrade_head.cable_up_info, 2) - return ret_val - ts = self.log_timestamp(ts, "MCU response pulled down") - - else: - self.log(self.LOG_ERROR, "ERROR MCU is not ready ") - self.__handle_error_abort(upgrade_head.cable_up_info, 17) - return ret_val - - # if MCU response pulled down - if req_status: - # TRANSFER command - self.log(self.LOG_INFO, "FW image transfer start ") - tmp_image_ptr = upgrade_head.cable_up_info.image_info.image_ptr - remain_page_size = 0 - image_to_page_size = 0 - count = 0 - page_loc = self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_1 - if((upgrade_head.compression & 0xFF)): - tmp_image_size = upgrade_head.compressed_size - else: - tmp_image_size = upgrade_head.cable_up_info.image_info.image_size - - remain_page_size = tmp_image_size % self.FW_UP_PACKET_SIZE - image_to_page_size = tmp_image_size - remain_page_size - - # MCU is now ready for firmware upgrade, Start the loop to transfre the data - self.log(self.LOG_DEBUG, "MCU is now ready for firmware upgrade, Start the loop to transfer the data") - dat[0] = self.FW_UP_PACKET_SIZE - dat[1] = page_loc - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_PACKET_SIZE, 2, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - self.log(self.LOG_DEBUG, "Writing packet to page_loc {} fw_up_packet_size : {}".format( - page_loc, self.FW_UP_PACKET_SIZE)) - - for i in range(0, self.FW_UP_PACKET_SIZE, 4): - dat[0 + i] = tmp_image_ptr[count] & 0xFF - dat[1 + i] = (tmp_image_ptr[count] >> 8) & 0xFF - dat[2 + i] = (tmp_image_ptr[count] >> 16) & 0xFF - dat[3 + i] = (tmp_image_ptr[count] >> 24) & 0xFF - count += 1 - - if self.platform_chassis.get_sfp(self.port).write_eeprom((page_loc*128) + self.QSFP_BRCM_FW_UPGRADE_DATA_START, self.FW_UP_PACKET_SIZE, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - ts = self.log_timestamp(ts, "First packet written") - - self.log(self.LOG_INFO, "TRANSFERING remaining packets..") - - dat[0] = (self.FW_CMD_TRANSFER << 1) | 1 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # prepare and send remaining packets - for _ in range(self.FW_UP_PACKET_SIZE, image_to_page_size, self.FW_UP_PACKET_SIZE): - req_status = False - - # Toggle data page_loc - page_loc = self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_1 if( - page_loc == self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_2) else self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_2 - - # prepare packet data - for i in range(0, self.FW_UP_PACKET_SIZE, 4): - dat[0 + i] = tmp_image_ptr[count] & 0xFF - dat[1 + i] = (tmp_image_ptr[count] >> 8) & 0xFF - dat[2 + i] = (tmp_image_ptr[count] >> 16) & 0xFF - dat[3 + i] = (tmp_image_ptr[count] >> 24) & 0xFF - count += 1 - - # write packet - if self.platform_chassis.get_sfp(self.port).write_eeprom((page_loc*128) + self.QSFP_BRCM_FW_UPGRADE_DATA_START, self.FW_UP_PACKET_SIZE, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Check response status for previous packet - for i in range(500): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if status[0] & 0x01: - if(status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2): - req_status = True - tmp_cnt += self.FW_UP_PACKET_SIZE - if tmp_cnt >= (tmp_image_size / 100): - tmp_cnt = 0 - tmp_print += 1 - #_logger.log_info(" {}%".format(tmp_print),CONSOLE_PRINT) - print(" {}% (tmp_cnt {})".format(tmp_print, tmp_cnt)) - break - else: - # ERROR - self.log(self.LOG_ERROR, "ERROR: TRANSFER error {}".format((status[0] & 0xFC) >> 2)) - self.__handle_error_abort(upgrade_head.cable_up_info, 3) - return ret_val - - time.sleep(0.001) - - # if previous packet sent successfully - if req_status: - req_status = False - - # Set the command request to idle state - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # wait for mcu response to be pulled down - for i in range(1000): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if(status[0] & 0x01) == 0: - # Previous packet is OK - # Set MCU write the next packet - dat[0] = self.FW_UP_PACKET_SIZE - dat[1] = page_loc - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_PACKET_SIZE, 2, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - dat[0] = (self.FW_CMD_TRANSFER << 1) | 1 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - req_status = True - break - time.sleep(0.001) - - if not req_status: - # Time out how to handle - self.log(self.LOG_ERROR, "cable_fw_upgrade : handle erro abort1") - self.__handle_error_abort(upgrade_head.cable_up_info, 4) - return ret_val - - else: - # Check if error status or timeout - if not req_status: - self.log(self.LOG_ERROR, "ERROR: TRANSFER timed out") - - self.__handle_error_abort(upgrade_head.cable_up_info, 5) - return ret_val - ts = self.log_timestamp(ts, "All packets written... Check response for last page") - - # Transfer remaining bytes if less than a page - if remain_page_size: - req_status = False - - # Toggle data page_loc - page_loc = self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_1 if( - page_loc == self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_2) else self.QSFP_BRCM_FW_UPGRADE_DATA_PAGE_2 - j = 0 - for i in range(remain_page_size): - dat[i] = ((tmp_image_ptr[count] >> (8 * j)) & 0xFF) - j += 1 - if j >= 4: - count += 1 - j = 0 - # write packet - if self.platform_chassis.get_sfp(self.port).write_eeprom(((page_loc*128) + self.QSFP_BRCM_FW_UPGRADE_DATA_START), remain_page_size, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Check response status for previous packet - for i in range(500): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if status[0] & 0x01: - if(status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2): - req_status = True - tmp_cnt += self.FW_UP_PACKET_SIZE - if tmp_cnt >= (upgrade_head.cable_up_info.image_info.image_size / 100): - tmp_cnt = 0 - tmp_print += 1 - #_logger.log_info(" {}%".format(tmp_print),CONSOLE_PRINT) - print(" {}% (tmp_cnt: {})".format(tmp_print, tmp_cnt)) - break - else: - # ERROR - self.log(self.LOG_ERROR, "ERROR: TRANSFER error {}".format((status[0] & 0xFC) >> 2)) - self.__handle_error_abort(upgrade_head.cable_up_info, 3) - return ret_val - - time.sleep(0.001) - - # if previous packet sent successfully - if req_status: - - req_status = False - # Set the command request to idle state - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED, - - # Wait for mcu response to be pulled down - for i in range(1000): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self. QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if (status[0] & 0x01) == 0: - # Previous packet is OK - # Set MCU to write the next packet - dat[0] = remain_page_size - dat[1] = page_loc - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + - self.QSFP_BRCM_FW_UPGRADE_PACKET_SIZE) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 2, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - dat[0] = (self.FW_CMD_TRANSFER << 1) | 1 - curr_offset = ((self.QSFP_BRCM_FW_UPGRADE_PAGE*128) + - self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD) - if self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - req_status = True - break - time.sleep(0.001) - if not req_status: - self.__handle_error_abort(upgrade_head.cable_up_info, 4) - # return ret_val - return self.ERROR_CMD_TIMEOUT - else: - if not req_status: - # Timeout - self.log(self.LOG_ERROR, "Transfer timeout") - self.__handle_error_abort(upgrade_head.cable_up_info, 5) - # return ret_val - return self.ERROR_CMD_TIMEOUT - - # Check response status for last page - for i in range(100): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - - if status[0] & 0x01: - if (status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2): - req_status = True - self.log(self.LOG_DEBUG, " 100% ") - break - else: - # ERROR - self.log(self.LOG_ERROR, "ERROR: TRANSFER error{}".format((status[0] & 0xFC) >> 2)) - self.__handle_error_abort(upgrade_head.cable_up_info, 3) - return ret_val - - time.sleep(0.001) - ts = self.log_timestamp(ts, "Check response for last page done") - - if req_status: - req_status = False - - # Set the command request to idle state - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Wait for mcu response to be pulled down - for i in range(100): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self. QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if (status[0] & 0x01) == 0: - # Last packet is OK - req_status = True - break - time.sleep(0.001) - if not req_status: - # Timeout, how to handle? - self.__handle_error_abort(upgrade_head.cable_up_info, 4) - # return ret_val - return self.ERROR_CMD_TIMEOUT - ts = self.log_timestamp(ts, "Wait for mcu response to be pulled down2") - - else: - if not req_status: - self.log(self.LOG_ERROR, "ERROR: TRANSFER timed out") - self.__handle_error_abort(upgrade_head.cable_up_info, 5) - return ret_val - - # COMPLETE command - # Send firmware upgrade complete - req_status = False - self.log(self.LOG_INFO, "TRANSFER COMPLETE") - ts = self.log_timestamp(ts, "TRANSFER complete") - - dat[0] = (self.FW_CMD_COMPLETE << 1) | 1 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # Check response status - for i in range(100): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - - # Check response status - if status[0] & 0x01: - if (status[0] & 0xFC) == (self.FW_UP_SUCCESS << 2): - # MCU SUCCEEDED - req_status = True - break - else: - # ERROR - self.__handle_error_abort(upgrade_head.cable_up_info, 6) - return ret_val - time.sleep(0.001) - - ts = self.log_timestamp(ts, "MCU check response state good") - if req_status: - req_status = False - # Set the command request to idle state - dat[0] = 0x00 - if self.platform_chassis.get_sfp(self.port).write_eeprom(QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CTRL_CMD, 1, dat) is False: - return self.ERROR_WR_EEPROM_FAILED - - # wait for mcu response to be pulled down - for i in range(100): - status = self.__util_read_eeprom( - (QSFP_PAGE_OFFSET + self.QSFP_BRCM_FW_UPGRADE_CMD_STS), 1, "cable_fw_upgrade") - if status is None: - return self.EEPROM_ERROR - if (status[0] & 0x01) == 0: - # MCU is Ready - req_status = True - ret_val = self.RR_SUCCESS - break - time.sleep(0.001) - - if not req_status: - # Timeout - self.log(self.LOG_ERROR, "Timed out - MCU pull down polling") - self.__handle_error_abort(upgrade_head.cable_up_info, 7) - # return ret_val - return self.ERROR_CMD_TIMEOUT - self.log_timestamp(ts, "wait for mcu response to be pulled down3") - - else: - # ERROR - self.log(self.LOG_ERROR, "ERROR") - self.__handle_error_abort(upgrade_head.cable_up_info, 8) - return ret_val - else: - self.log(self.LOG_WARN, "MCU not in the right state") - - self.log_timestamp(start_tstamp, "FW upgrade complete") - return ret_val - - def get_firmware_version(self, target): - """ - This routine should return the active, inactive and next (committed) - firmware running on the target. Each of the version values in this context - could be a string with a major and minor number and a build value. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the firmware version on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a Dictionary: - with version_active, version_inactive and version_next keys - and their corresponding values - """ - - dat = [] - dat1 = [] - i = 0 - fw_ver_dict = {} - upgrade_info = cable_upgrade_info_s() - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - if self.platform_chassis is not None: - - read_side = self.get_read_side() - if (read_side == self.TARGET_UNKNOWN): - self.log(self.LOG_ERROR, "ERROR: get_read_side Failed!") - return None - - if (target == self.TARGET_TOR_A): - target = self.TOR_MCU_SELF if (read_side == 1) else self.TOR_MCU_PEER - elif (target == self.TARGET_TOR_B): - target = self.TOR_MCU_SELF if (read_side == 2) else self.TOR_MCU_PEER - else: - target = self.NIC_MCU - - # 1s timeout - with self.dl_lock.acquire_timeout(1) as result: - - if result: - upgrade_info.destination = target - - self.log(self.LOG_DEBUG, "read_side {} target {}".format(read_side, target)) - - ret_val = self.cable_fw_get_status(upgrade_info) - if ret_val != self.RR_ERROR: - if upgrade_info.status_info.current_bank == 1: - # Active version - dat.append(format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_major, 'X') + - "." + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor, 'X')) - # Inactive version - dat.append(format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_major, 'X') + - "." + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor, 'X')) - else: - dat.append(format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_major, 'X') + - "." + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor, 'X')) - dat.append(format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_major, 'X') + - "." + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor, 'X')) - - if upgrade_info.status_info.next_bank == 1: - dat.append(format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_major, 'X') + - "." + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor, 'X')) - else: - dat.append(format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_major, 'X') + - "." + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor, 'X')) - - else: - self.log(self.LOG_ERROR, "Error getting version for {}".format("TOR MCU SELF" if target == - self.TOR_MCU_SELF else "TOR MCU PEER" if target == self.TOR_MCU_PEER else "NIC MCU")) - # return self.RR_ERROR - return self.ERROR_GET_VERSION_FAILED - - if target == self.NIC_MCU: - upgrade_info.destination = self.MUX_CHIP - ret_val = self.cable_fw_get_status(upgrade_info) - if ret_val != self.RR_ERROR: - if upgrade_info.status_info.current_bank == 1: - # Active version - # Active version - dat1.append('.' + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_major, - 'X') + "." + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor, 'X')) - dat1.append('.' + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_major, - 'X') + "." + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor, 'X')) - # Inactive version - else: - dat1.append('.' + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_major, - 'X') + "." + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor, 'X')) - dat1.append('.' + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_major, - 'X') + "." + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor, 'X')) - if upgrade_info.status_info.next_bank == 1: - # Active version - dat1.append('.' + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_major, - 'X') + "." + format(upgrade_info.status_info.bank1_info.image_fw_version.image_version_minor, 'X')) - else: - dat1.append('.' + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_major, - 'X') + "." + format(upgrade_info.status_info.bank2_info.image_fw_version.image_version_minor, 'X')) - else: - self.log(self.LOG_ERROR, "Error getting version for MUX CHIP") - # return self.RR_ERROR - return self.ERROR_GET_VERSION_FAILED - - for i in range(0, 3): - dat[i] = dat[i] + dat1[i] - - if target == self.TOR_MCU_SELF: - fw_ver_dict["version_active"] = dat[0] - fw_ver_dict["version_inactive"] = dat[1] - fw_ver_dict["version_next"] = dat[2] - elif target == self.TOR_MCU_PEER: - fw_ver_dict["version_active"] = dat[0] - fw_ver_dict["version_inactive"] = dat[1] - fw_ver_dict["version_next"] = dat[2] - elif target == self.NIC_MCU: - fw_ver_dict["version_active"] = dat[0] - fw_ver_dict["version_inactive"] = dat[1] - fw_ver_dict["version_next"] = dat[2] - - return fw_ver_dict - - else: - self.log(self.LOG_ERROR, "DL Port lock timed-out!") - #ret_val = self.ERROR_PORT_LOCK_TIMEOUT - - return None - - def get_local_temperature(self): - """ - This API returns local ToR temperature of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - None - - Returns: - an Integer, the temperature of the local MCU - """ - read_side = self.get_read_side() - - if read_side == self.TARGET_TOR_A: - curr_offset = 0xFD * 128 + 0x86 - elif read_side == self.TARGET_TOR_B: - curr_offset = 0xFD * 128 + 0x8a - elif read_side == self.TARGET_NIC: - curr_offset = 0xFD * 128 + 0x8e - else: - self.log(self.LOG_ERROR, "get_local_temperature: unknown read_side") - return -1 - - if self.platform_chassis is not None: - #curr_offset = self.QSFP28_VENFD_129_DIE_TEMP_MSB - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - self.log(self.LOG_ERROR, "get local temperature read eeprom failed") - return self.EEPROM_ERROR - else: - temperature = result[0] - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check read side") - temperature = None - - return temperature - - def get_local_voltage(self): - """ - This API returns local ToR voltage of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - None - - Returns: - a float, the voltage of the local MCU - """ - - read_side = self.get_read_side() - - if read_side == self.TARGET_TOR_A: - curr_offset = 0xFD * 128 + 0x88 - elif read_side == self.TARGET_TOR_B: - curr_offset = 0xFD * 128 + 0x8c - elif read_side == self.TARGET_NIC: - return None - else: - self.log(self.LOG_ERROR, "get_local_voltage: unknown read_side") - return -1 - - if self.platform_chassis is not None: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 2) - if result is None: - self.log(self.LOG_ERROR, "get local temperature read eeprom failed") - return self.EEPROM_ERROR - else: - temperature = result[0] << 8 | result[1] - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check read side") - temperature = None - - return temperature - - def get_nic_voltage(self): - """ - This API returns nic voltage of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - Args: - Returns: - a float, the voltage of the NIC MCU - """ - - return None - - def get_nic_temperature(self): - """ - This API returns nic temperature of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - Args: - Returns: - an Integer, the temperature of the NIC MCU - """ - - read_side = self.get_read_side() - - if read_side == self.TARGET_TOR_A: - curr_offset = 0xFD * 128 + 0x8e - elif read_side == self.TARGET_TOR_B: - curr_offset = 0xFD * 128 + 0x8e - elif read_side == self.TARGET_NIC: - curr_offset = 0xFD * 128 + 0x81 - else: - self.log(self.LOG_ERROR, "get_nic_temperature: unknown read_side") - return -1 - - if self.platform_chassis is not None: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - self.log(self.LOG_ERROR, "get local temperature read eeprom failed") - return self.EEPROM_ERROR - else: - temperature = result[0] - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check read side") - temperature = None - - return temperature - - def internal_get_eye_heights(self, target): - """ - This API returns the EYE height value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to get the eye: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with EYE values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - if target == self.EYE_PRBS_LOOPBACK_TARGET_NIC or target == self.TARGET_NIC: - self.log(self.LOG_WARN, "Get eye heights not supported for NIC target ") - return None - elif (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and \ - (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - core_ip, lane_mask = self.__util_convert_to_phyinfo_details(target, 0X0F) - - cmd_hdr = bytearray(10) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0x40 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = 0 - #cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = self.CORE_IP_CLIENT - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_EYE_MARGIN, cmd_hdr, cmd_req_body) - - if ret_val == 0: - eye_heights = [[] for i in range(4)] - values = [] - lrud_list = [] - ind = 0 - for i in range(0, 32): - #values.append(struct.unpack("h", cmd_rsp_body[ind:ind+2])) - byte_list = [] - for j in range(0, 2): - byte_list.append(cmd_rsp_body[ind + j]) - byte_array = bytearray(byte_list) - values.append(struct.unpack("h", byte_array)[0]) - - ind += 2 - - if lane_mask == 0x0F: - j = 0 - l = 0 - for i in range(0, 4): - for k in range(0, 4): - eye_heights[j].append(values[l]) - l += 1 - j += 1 - for i in range(0, 4): - lrud_val = (format(eye_heights[i][0]) + " " + format(eye_heights[i][1]) + " " + format(eye_heights[i][2]) + " " + format(eye_heights[i][3])) - #lrud_val = eye_heights[i][2] + eye_heights[i][3] - lrud_list.append(lrud_val) - - if lane_mask == 0xF0: - j = 0 - l = 16 - for i in range(0, 4): - for k in range(0, 4): - eye_heights[j].append(values[l]) - l += 1 - j += 1 - k = 0 - for i in range(4, 8): - lrud_val = (format(eye_heights[k][0]) + " " + format(eye_heights[k][1]) + " " + format(eye_heights[k][2]) + " " + format(eye_heights[k][3])) - #lrud_val = eye_heights[k][2] + eye_heights[k][3] - lrud_list.append(lrud_val) - - k += 1 - - return lrud_list - else: - self.log(self.LOG_ERROR, "Command execute failed ret_val: {}".format(ret_val)) - return None - - def get_eye_heights(self, target): - """ - This API returns the EYE height value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to get the eye: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with EYE values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - if target == self.EYE_PRBS_LOOPBACK_TARGET_NIC or target == self.TARGET_NIC: - self.log(self.LOG_WARN, "Get eye heights not supported for NIC target ") - return None - elif (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and \ - (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - core_ip, lane_mask = self.__util_convert_to_phyinfo_details(target, 0X0F) - - cmd_hdr = bytearray(10) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0x40 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = 0 - #cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = self.CORE_IP_CLIENT - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_EYE_MARGIN, cmd_hdr, cmd_req_body) - - if ret_val == 0: - eye_heights = [[] for i in range(4)] - values = [] - lrud_list = [] - ind = 0 - for i in range(0, 32): - #values.append(struct.unpack("h", cmd_rsp_body[ind:ind+2])) - byte_list = [] - for j in range(0, 2): - byte_list.append(cmd_rsp_body[ind + j]) - byte_array = bytearray(byte_list) - values.append(struct.unpack("h", byte_array)[0]) - - ind += 2 - - if lane_mask == 0x0F: - j = 0 - l = 0 - for i in range(0, 4): - for k in range(0, 4): - eye_heights[j].append(values[l]) - l += 1 - j += 1 - for i in range(0, 4): - #lrud_val = (format(eye_heights[i][0]) + " " + format(eye_heights[i][1]) + " " + format(eye_heights[i][2]) + " " + format(eye_heights[i][3])) - lrud_val = eye_heights[i][2] + eye_heights[i][3] - lrud_list.append(lrud_val) - - if lane_mask == 0xF0: - j = 0 - l = 16 - for i in range(0, 4): - for k in range(0, 4): - eye_heights[j].append(values[l]) - l += 1 - j += 1 - k = 0 - for i in range(4, 8): - #lrud_val = (format(eye_heights[k][0]) + " " + format(eye_heights[k][1]) + " " + format(eye_heights[k][2]) + " " + format(eye_heights[k][3])) - lrud_val = eye_heights[k][2] + eye_heights[k][3] - lrud_list.append(lrud_val) - - k += 1 - - return lrud_list - else: - self.log(self.LOG_ERROR, "Command execute failed ret_val: {}".format(ret_val)) - return None - - def get_ber_info(self, target): - """ - This API returns the BER (Bit error rate) value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to get the BER: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with BER values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - if (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL and target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_A and - target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_B and target != self.EYE_PRBS_LOOPBACK_TARGET_NIC): - self.log(self.LOG_ERROR, "Invalid Traget : {}".format(target)) - return self.ERROR_INVALID_TARGET - - mode_value = 0xff - lane = 0x0f - ber_result = [] - ret_val, lock_sts, err_cnt_list = self.cable_check_prbs(target, mode_value, lane) - if ret_val != 0: - return False - - time.sleep(1) - - ret_val, lock_sts, err_cnt_list = self.cable_check_prbs(target, mode_value, lane) - if ret_val != 0: - return False - - for i in range(0, 8): - prbs_error_per_lane = err_cnt_list[i] - self.log(self.LOG_DEBUG, "prbs_error_per_lane : {}".format(hex(prbs_error_per_lane))) - ber_result.append(prbs_error_per_lane/(25.78125*(math.pow(10, 9)))) - - return ber_result - - def get_target_cursor_values(self, lane, target): - """ - This API returns the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two , main, post one, post two , post three cursor values - If any of the value is not available please return None for that filter - The port on which this API is called for can be referred using self.port. - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a list, with pre one, pre two , main, post one, post two , post three cursor values in the order - """ - - # validate lane number - if ((type(lane) is not int) or - (lane < 1 or lane > 4)): - self.log(self.LOG_ERROR, "Invalid lane = {} valid lane is 1 to 4".format(lane)) - return self.ERROR_INVALID_INPUT - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - lane -= 1 # internally lane starts from 0 - lane_mask = 1 << lane - ret_val = self.__util_convert_to_phyinfo_details(target, lane_mask) - - core_ip = ret_val[0] - lane_mask = ret_val[1] - self.log(self.LOG_DEBUG, "lane_mask = {} core_ip {} target {}".format(hex(lane_mask), core_ip, target)) - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 14 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_TXFIR, cmd_hdr, cmd_req_body) - - if ret_val == 0: - txfir = [] - ind = 0 - for _ in range(0, 7): - txfir.append(struct.unpack("h", cmd_rsp_body[ind:ind+2])[0]) - ind += 2 - - self.log(self.LOG_DEBUG, "lane {} : pre1 = {}".format(lane, txfir[0])) - self.log(self.LOG_DEBUG, "lane {} : pre2 = {}".format(lane, txfir[1])) - self.log(self.LOG_DEBUG, "lane {} : main = {}".format(lane, txfir[2])) - self.log(self.LOG_DEBUG, "lane {} : post1 = {}".format(lane, txfir[3])) - self.log(self.LOG_DEBUG, "lane {} : post2 = {}".format(lane, txfir[4])) - self.log(self.LOG_DEBUG, "lane {} : post3 = {}".format(lane, txfir[5])) - self.log(self.LOG_DEBUG, "lane {} : taps = {}".format(lane, txfir[6])) - return txfir - else: - self.log(self.LOG_ERROR, "command execution failed ret_val: {}".format(ret_val)) - - return None - - def set_target_cursor_values(self, lane, cursor_values, target): - """ - This API sets the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two , main, post one, post two etc. cursor values - The port on which this API is called for can be referred using self.port. - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - cursor_values: - a list, with pre one, pre two , main, post one, post two cursor, post three etc. values in the order - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - Returns: - a boolean, True if cursor values setting is successful - , False if cursor values setting is not successful - """ - - # check length of argument - if(self.LEN_OF_SET_CURSOR_VALUES != len(cursor_values)): - self.log(self.LOG_ERROR, "Wrong No of cursor values passed to function set_target_cursor_values") - return self.ERROR_INVALID_INPUT - - if ((type(lane) is not int) or - (lane < 1 or lane > 4)): - self.log(self.LOG_ERROR, "Invalid lane = {} valid lane is 1 to 4".format(lane)) - return self.ERROR_INVALID_INPUT - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - lane -= 1 # internally lane starts from 0 - lane_mask = 1 << lane - ret_val = self.__util_convert_to_phyinfo_details(target, lane_mask) - core_ip = ret_val[0] - lane_mask = ret_val[1] - self.log(self.LOG_DEBUG, "lane_mask = {} core_ip {} target {}".format(hex(lane_mask), core_ip, target)) - cmd_hdr = bytearray(5) - #cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - cmd_req_body1 = bytearray() - cmd_hdr[0] = 14 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - for i in range(len(cursor_values)): - cmd_req_body1 += struct.pack(" NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if the cable is target reset - , False if the cable target is not reset - """ - - status = bytearray(self.MAX_REQ_PARAM_LEN) - - if target == self.TARGET_TOR_A: - status[0] = 0x1 - elif target == self.TARGET_TOR_B: - status[0] = 0x2 - elif target == self.TARGET_NIC: - status[0] = 0x4 - else: - self.log(self.LOG_ERROR, "Invalid target") - return self.ERROR_INVALID_TARGET - - # if read side is matching target, invoke reset_self() - read_side = self.get_read_side() - if read_side == target: - return self.reset_self() - - if self.platform_chassis is not None: - - debug_print("Trying for the lock") - with self.dl_lock.acquire_timeout(self.PORT_LOCK_TIMEOUT) as result: - if result: - - curr_offset = self.QSFP28_VENFD_184_NIC_TORB_TORA_RESET - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, status) - if result is False: - self.log(self.LOG_ERROR, "write to QSFP28_VENFD_184_NIC_TORB_TORA_RESET failed.") - return False - - time.sleep(3) - - self.log(self.LOG_DEBUG, "reset value to write. rval: {} ".format(status[0])) - # for next one second, keep checking the register to see if it becomes 0 - for _ in range(30): - rval = 0 - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - return self.EEPROM_ERROR - rval = result[0] - - if (rval & status[0]) == 0x00: - ret_code = True - break - - time.sleep(0.1) # 100ms - else: - self.log(self.LOG_ERROR, "TORB_TORA_RESET never become zero. rval: {} ".format(rval)) - ret_code = False - else: - self.log(self.LOG_ERROR, "Port lock timed-out!") - return self.ERROR_PORT_LOCK_TIMEOUT - - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded, failed to check read side") - ret_code = False - - return ret_code - - def create_port(self, speed, fec_mode_tor=FEC_MODE_NONE, fec_mode_nic=FEC_MODE_NONE, anlt_tor=False, anlt_nic=False): - """ - This API sets the mode of the cable/port for corresponding lane/fec etc. configuration as specified. - The speed specifies which mode is supposed to be set 50G, 100G etc - the anlt specifies if auto-negotiation + link training (AN/LT) has to be enabled - Note that in case create_port is called multiple times, the most recent api call will take the precedence - on either of TOR side. - The port on which this API is called for can be referred using self.port. - Args: - speed: - an Integer, the value for the link speed to be configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - fec_mode_tor: - One of the following predefined constants, the actual fec mode for the tor A to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - fec_mode_nic: - One of the following predefined constants, the actual fec mode for the nic to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - anlt_tor: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on tor A - , False if auto-negotiation + link training (AN/LT) is not to be enabled on tor A - anlt_nic: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on nic - , False if auto-negotiation + link training (AN/LT) is not to be enabled on nic - Returns: - a boolean, True if the port is configured - , False if the port is not configured - """ - port_option_table = [] - ret_code = True - - port_option_table.append(valid_port_option_table_s(self.PORT_SPEED_50, self.FEC_MODE_NONE, - self.FEC_MODE_NONE, self.ANLT_DONT_CARE, self.ANLT_DONT_CARE, self.CABLE_MODE_50G_PCS)) - - port_option_table.append(valid_port_option_table_s(self.PORT_SPEED_50, self.FEC_MODE_RS, - self.FEC_MODE_RS, self.ANLT_DONT_CARE, self.ANLT_DONT_CARE, self.CABLE_MODE_50G_FEC)) - - port_option_table.append(valid_port_option_table_s(self.PORT_SPEED_100, self.FEC_MODE_NONE, - self.FEC_MODE_NONE, self.ANLT_DONT_CARE, self.ANLT_DONT_CARE, self.CABLE_MODE_100G_PCS)) - - port_option_table.append(valid_port_option_table_s(self.PORT_SPEED_100, self.FEC_MODE_RS, - self.FEC_MODE_RS, self.ANLT_DONT_CARE, self.ANLT_DONT_CARE, self.CABLE_MODE_100G_FEC)) - - matched_entry = valid_port_option_table_s - for i in range(len(port_option_table)): - if ((speed == port_option_table[i].speed) and (fec_mode_tor == port_option_table[i].fec_tor) and - (fec_mode_nic == port_option_table[i].fec_nic) and - ((0x2 if anlt_tor == True else 0x1) & port_option_table[i].anlt_tor) and - ((0x2 if anlt_nic == True else 0x1) & port_option_table[i].anlt_nic)): - matched_entry.speed = port_option_table[i].speed - matched_entry.fec_tor = port_option_table[i].fec_tor - matched_entry.fec_nic = port_option_table[i].fec_nic - matched_entry.anlt_tor = port_option_table[i].anlt_tor - matched_entry.anlt_nic = port_option_table[i].anlt_nic - matched_entry.mode = port_option_table[i].mode - break - else: - if i == (len(port_option_table) - 1): - self.log(self.LOG_ERROR, "Not supported input parameter") - return False - - # Disable ANLT irrespective, For 100G need to disable AN, mcu wouldn't do it - # Disable AN on the NIC side - if self.set_anlt(0, self.TARGET_NIC) == False: - self.log(self.LOG_ERROR, "disable AN/LT on TARGET_NIC failed") - ret_code = False - # Disable AN on the TORA side - if self.set_anlt(0, self.TARGET_TOR_A) == False: - self.log(self.LOG_ERROR, "disable AN/LT on TARGET_TOR-A failed") - ret_code = False - # Disable AN on the TORB side - if self.set_anlt(0, self.TARGET_TOR_B) == False: - self.log(self.LOG_ERROR, "disable AN/LT on TARGET_TOR-A failed") - ret_code = False - - # configure mode - if self.cable_set_mode(matched_entry.mode) == False: - self.log(self.LOG_ERROR, "set mode failed") - ret_code = False - - # configure AN/LT - if anlt_nic: - if self.set_anlt(1, self.TARGET_NIC) == False: - self.log(self.LOG_ERROR, "Enable AN/LT on TARGET_NIC failed") - ret_code = False - else: - if self.set_anlt(0, self.TARGET_NIC) == False: - self.log(self.LOG_ERROR, "Disable AN/LT on TARGET_NIC failed") - ret_code = False - - if anlt_tor: - if self.set_anlt(1, self.TARGET_TOR_A) == False: - self.log(self.LOG_ERROR, "Enable AN/LT on TARGET_TORA failed") - ret_code = False - if self.set_anlt(1, self.TARGET_TOR_B) == False: - self.log(self.LOG_ERROR, "Enable AN/LT on TARGET_TORB failed") - ret_code == False - else: - if self.set_anlt(0, self.TARGET_TOR_A) == False: - self.log(self.LOG_ERROR, "Enable AN/LT on TARGET_TORA failed") - ret_code = False - if self.set_anlt(0, self.TARGET_TOR_B) == False: - self.log(self.LOG_ERROR, "Enable AN/LT on TARGET_TORB failed") - ret_code == False - return ret_code - - def get_speed(self): - """ - This API gets the mode of the cable for corresponding lane configuration. - The port on which this API is called for can be referred using self.port. - - Args: - None - Returns: - speed: - an Integer, the value for the link speed is configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - """ - mode = self.cable_get_mode() - if mode == self.CABLE_MODE_100G_FEC or mode == self.CABLE_MODE_100G_PCS: - return self.CABLE_MODE_100G - elif mode == self.CABLE_MODE_50G_FEC or mode == self.CABLE_MODE_50G_PCS: - return self.CABLE_MODE_50G - else: - self.log(self.LOG_ERROR, "No mode configured") - return None - - def set_fec_mode(self, fec_mode, target=None): - """ - This API gets the fec mode of the cable for which it is set to. - The port on which this API is called for can be referred using self.port. - Args: - fec_mode: - One of the following predefined constants, the actual fec mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - target: - One of the following predefined constants, the actual target to set the fec mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if the fec mode is configured - , False if the fec mode is not configured - """ - - entry_to_match = valid_port_option_table_s - - mode_select = self.cable_get_mode() - if (mode_select < 0): - self.log(self.LOG_ERROR, "get_mode failed ret_code: {}".format(mode_select)) - return False - - entry_to_match.mode = mode_select - curr_fec_mode = self.FEC_MODE_NONE if ( - mode_select == self.CABLE_MODE_50G_PCS or mode_select == self.CABLE_MODE_100G_PCS) else self.FEC_MODE_RS - - if fec_mode == curr_fec_mode: - self.log(self.LOG_INFO, "Current mode already configured to {}".format( - " PCS " if fec_mode == self.FEC_MODE_NONE else "FEC")) - return True - - if fec_mode == self.FEC_MODE_NONE: - entry_to_match.fec_nic = self.FEC_MODE_NONE - entry_to_match.fec_tor = self.FEC_MODE_NONE - elif fec_mode == self.FEC_MODE_RS: - entry_to_match.fec_nic = self.FEC_MODE_RS - entry_to_match.fec_tor = self.FEC_MODE_RS - else: - self.log(self.LOG_ERROR, "Invalid Input/NotSupported mode: {}".format(fec_mode)) - return False - - entry_to_match.speed = self.PORT_SPEED_50 if ( - mode_select == self.CABLE_MODE_50G_PCS or mode_select == self.CABLE_MODE_50G_FEC) else self.PORT_SPEED_100 - - anlt_enable = self.get_anlt(self.TARGET_NIC) - entry_to_match.anlt_nic = 1 if anlt_enable == True else 0 - - anlt_enable = self.get_anlt(self.TARGET_TOR_A) - entry_to_match.anlt_tor = 1 if anlt_enable == True else 0 - - anlt_enable = self.get_anlt(self.TARGET_TOR_B) - entry_to_match.anlt_tor = 1 if anlt_enable == True else 0 - - ret_code = self.create_port(entry_to_match.speed, entry_to_match.fec_tor, - entry_to_match.fec_nic, (1 if entry_to_match.anlt_tor == True else 0), - (1 if entry_to_match.anlt_nic == True else 0)) - - if ret_code == True: - self.log(self.LOG_INFO, "Set {} fec mode success".format(fec_mode)) - return True - else: - self.log(self.LOG_ERROR, "Set fec mode failed") - return False - - def get_fec_mode(self, target=None): - """ - This API gets the fec mode of the cable which it is set to. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the actual target to fec mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - fec_mode: - One of the following predefined constants, the actual fec mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - """ - mode_select = self.cable_get_mode() - - if (mode_select < 0): - self.log(self.LOG_ERROR, "get_mode failed ret_code: {}".format(mode_select)) - return self.ERROR_GET_FEC_MODE_FAILED - - return self.FEC_MODE_NONE if (mode_select == self.CABLE_MODE_50G_PCS or mode_select == self.CABLE_MODE_100G_PCS) else self.FEC_MODE_RS - - def set_anlt(self, enable, target): - """ - This API enables/disables the cable auto-negotiation + link training (AN/LT). - The port on which this API is called for can be referred using self.port. - Args: - enable: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled - , False if auto-negotiation + link training (AN/LT) is not to be enabled - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if the auto-negotiation + link training (AN/LT) enable/disable specified is configured - , False if the auto-negotiation + link training (AN/LT) enable/disable specified is not configured - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_INPUT - - values = self.__util_convert_to_phyinfo_details(target, 0x0F) - core_ip = values[0] - lane_mask = values[1] - self.log(self.LOG_DEBUG, "core_ip {} lane_mask {}".format(core_ip, hex(lane_mask))) - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x1 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = enable - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_SET_ANLT, cmd_hdr, cmd_req_body) - if ret_val == 0 and cmd_rsp_body is None: - self.log(self.LOG_INFO, "{} AN/LT Successful".format("Enable" if (enable) else "Disable")) - return True - else: - self.log(self.LOG_ERROR, "Enable/Disable AN LT mode is failed") - return False - - def get_anlt(self, target): - """ - This API gets the mode of the cable for corresponding lane configuration. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the actual target to get the anlt on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if auto-negotiation + link training (AN/LT) is enabled - , False if auto-negotiation + link training (AN/LT) is not enabled - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_INPUT - - values = self.__util_convert_to_phyinfo_details(target, 0x0F) - core_ip = values[0] - lane_mask = values[1] - self.log(self.LOG_DEBUG, "core_ip {} lane_mask {} target {}".format(core_ip, hex(lane_mask), target)) - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 1 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_ANLT, cmd_hdr, cmd_req_body) - - if self.__validate_read_data(cmd_rsp_body, 1, "cable anlt get") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - if ret_val == 0: - if cmd_rsp_body[0] & 1: - self.log(self.LOG_INFO, "AN/LT mode enabled") - return True - else: - self.log(self.LOG_INFO, "AN/LT mode disabled") - return False - else: - self.log(self.LOG_ERROR, "Get AN/LT get mode command execution failed") - return False - - def sort_logs(self, sorted_logs, event_logs): - - for idx in range(len(event_logs)): - event_obj = event_logs[idx] - - # if sorted_logs is empty, simply add the log - if len(sorted_logs) == 0: - sorted_logs.append(event_obj) - #print("[case-0] adding run_no {} timestamp {}".format(event_obj.run_no, event_obj.timestamp)) - else: - #match_run_list_found = False - added_to_list = False - # add the event_obj in run_no & timestamp order - for sidx in range(len(sorted_logs)): - tmp_obj = sorted_logs[sidx] - - if tmp_obj.run_no > event_obj.run_no: - sorted_logs.insert(sidx, event_obj) - #print("[case-1] adding run_no {} timestamp {} at index {}".format(event_obj.run_no, event_obj.timestamp, sidx)) - #print("[case-1] tmp_obj run_no {} timestamp {} at index {}".format(tmp_obj.run_no, tmp_obj.timestamp, sidx)) - added_to_list = True - break - elif tmp_obj.run_no == event_obj.run_no: - if tmp_obj.timestamp > event_obj.timestamp: - sorted_logs.insert(sidx, event_obj) - #print("[case-2] adding run_no {} timestamp {} at index {}".format(event_obj.run_no, event_obj.timestamp, sidx)) - added_to_list = True - break - - if added_to_list == False: - #print("[case-3] adding run_no {} timestamp {} after index {}".format(event_obj.run_no, event_obj.timestamp, sidx)) - sorted_logs.append(event_obj) - - def convert_to_hhmmss(self, millis): - mil = millis%1000 - seconds = (millis/1000)%60 - minutes = (millis/(1000*60))%60 - hours = (millis/(1000*60*60))%24 - - out = ("%02d:%02d:%02d.%03d" % (hours, minutes, seconds, mil)) - - return out - - def get_event_log(self, clear_on_read=False): - """ - This API returns the event log of the cable - The port on which this API is called for can be referred using self.port. - Args: - clear_on_read: - a boolean, True if the log has to be cleared after read - , False if the log is not to be cleared after read - Returns: - list: - a list of strings which correspond to the event logs of the cable - """ - all_logs_list = [] - phy_logs = [] - mcu_logs = [] - sorted_phy_nic_logs = [] - sorted_tor_self_logs = [] - sorted_tor_peer_logs = [] - - all_logs_list.append("Run No : Timestamp : Source : Event ") - all_logs_list.append("------ : --------- : ------ : ----- ") - phy_logs = self.cable_get_phy_chip_event_log() - - # sort phy logs first - self.sort_logs(sorted_phy_nic_logs, phy_logs) - - tmp_list = [] - - # fetch event_logs for each event source and add them to tmp_list - # sort the tmp_list into combined sorted_phy_nic_logs[] - for event_source in range(1, 5): - mcu_logs = self.cable_get_nic_mcu_event_log(event_source) - if mcu_logs: - for j in range(len(mcu_logs)): - event_obj = mcu_logs[j] - event_type = struct.unpack(" 0: - self.sort_logs(sorted_phy_nic_logs, tmp_list) - - log_item = 0 - for evt in range(len(sorted_phy_nic_logs)): - if (type(sorted_phy_nic_logs[evt]) == cable_phy_chip_event_log_s): - tmp_phy_str_list = self.convert_to_phy_chip_event_log_str_list(sorted_phy_nic_logs[evt], log_item) - log_item += 1 - for i in range(len(tmp_phy_str_list)): - all_logs_list.append(tmp_phy_str_list[i]) - elif (type(sorted_phy_nic_logs[evt]) == cable_mcu_event_log_s): - tstamp = self.convert_to_hhmmss(sorted_phy_nic_logs[evt].timestamp) - - #evt_str = self.get_mcu_event_type_str(int.from_bytes(sorted_phy_nic_logs[evt].event_type, "big")) - evt_type = struct.unpack(" 0: - self.sort_logs(sorted_tor_self_logs, tmp_list1) - - for evt in range(len(sorted_tor_self_logs)): - tstamp = self.convert_to_hhmmss(sorted_tor_self_logs[evt].timestamp) - #evt_str = self.get_mcu_event_type_str(int.from_bytes(sorted_tor_self_logs[evt].event_type, "big")) - evt_type = struct.unpack(" 0: - self.sort_logs(sorted_tor_peer_logs, tmp_list1) - - for evt in range(len(sorted_tor_peer_logs)): - tstamp = self.convert_to_hhmmss(sorted_tor_peer_logs[evt].timestamp) - #evt_str = self.get_mcu_event_type_str(int.from_bytes(sorted_tor_peer_logs[evt].event_type, "big")) - evt_type = struct.unpack(" NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - output_dict = {} - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - output_dict["error_message"] = "Invalid target : {}".format(target) - return output_dict - #return self.ERROR_INVALID_INPUT - - mode_select = self.get_fec_mode() - if (mode_select < 0): - self.log(self.LOG_ERROR, "get_mode failed ret_code: {}".format(mode_select)) - output_dict["error_message"] = "get_mode failed ret_code: {}".format(mode_select) - return output_dict - #return self.ERROR_GET_FEC_MODE_FAILED - - if mode_select != self.FEC_MODE_NONE: - output_dict["error_message"] = "get_pcs_stats() on FEC mode not allowed!" - return output_dict - - status = bytearray(121) - lane_mask = 0xF - no_clr_on_rd = 0 - src_ptr = pcsfec_dump_status_short_s() - - status = self.cable_get_pcsfec_stats(target, lane_mask, no_clr_on_rd) - if status is None: - self.log(self.LOG_ERROR, "ERROR: failed to get pcs/fec stats!") - output_dict["error_message"] = "get_mode failed ret_code: {}".format(mode_select) - return output_dict - #return self.RR_ERROR - - # Get fec type and func_mode from the byte array - src_ptr.fec_type = status[0] - src_ptr.func_mode = status[1] - - # if it is PCS, populate PCS stats - if src_ptr.fec_type == self.CAPI_FEC_TYPE_PCS: - - start_idx = 2 # skip first 2 bytes, which are fec_type and func_mode - lane_pcsrx_status = pcsrx_status_short_s() - for lane in range(4): - status_phy_lane = pcsrx_status_phylane_short_s() - status_phy_lane.pcs_block_lock_stat = status[start_idx + lane*15] - status_phy_lane.pcs_block_lolock_sticky = status[start_idx + 1 + lane*15] - status_phy_lane.pcs_am_lock_stat = status[start_idx + 2 + lane*15] - status_phy_lane.pcs_am_lolock_sticky = status[start_idx + 3 + lane*15] - status_phy_lane.pcs_dskw_error_sticky = status[start_idx + 4 + lane*15] - - # PCS BIP ERROR COUNT 2 Bytes - for i in range(5): - bip_offset = start_idx + (lane*15) + 5 + (i*2) - pcs_bip_err_cnt = struct.unpack(" 1)): - break - - output_str += "\n Lane {} Status =============".format(lane) - output_str += "\n Block Lock Live Status = {}".format(hex(src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_block_lock_stat)) - output_str += "\n Block LoLock Sticky Status = {} ".format(hex(src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_block_lolock_sticky)) - output_str += "\n AM Lock Live Status = {} ".format(hex(src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_am_lock_stat)) - output_str += "\n AM LoLock Sticky Status = {} ".format(hex(src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_am_lolock_sticky)) - output_str += "\n Deskew Error Sticky Status = {} ".format(hex(src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_dskw_error_sticky)) - - output_str += "\n BIP Error Count ========== " - for sublane in range(5): - pcsl = 5 * lane + sublane - output_str += "\n sublane@{} (pcsl @ {}) = hex( {} ) | dec( {} ) ; ".format(sublane, pcsl, hex(src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_bip_err_cnt[sublane]), src_ptr.pcs_sts.pcs_status_phylane[lane].pcs_bip_err_cnt[sublane]) - - output_str += "\n" - - output_str += "\n*** Per Port Status *** \n" - output_str += "\n dskw alignment live status = {} ".format(src_ptr.pcs_sts.pcs_dskw_align_stat) - output_str += "\n dskw loss of alignment sticky status = {} \n".format(src_ptr.pcs_sts.pcs_dskw_align_loss_sticky) - - output_str += "\n high ber live status = {} \n".format(src_ptr.pcs_sts.pcs_hiber_stat) - output_str += "\n high ber sticky status = {} \n".format(src_ptr.pcs_sts.pcs_hiber_sticky) - - output_str += "\n pcs ber count = hex( {} ) | dec( {} ) \n".format(hex(src_ptr.pcs_sts.pcs_ber_cnt), src_ptr.pcs_sts.pcs_ber_cnt) - - output_str += "\n live link status = {} \n".format(src_ptr.pcs_sts.pcs_link_stat) - output_str += "\n sticky link status = {} \n".format(src_ptr.pcs_sts.pcs_link_stat_sticky) - - return output_str - - def get_fec_stats(self, target): - """ - This API returns the fec statistics of the cable - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - output_dict = {} - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - output_dict["error_messgae"] = "Invalid target : {}".format(target) - return output_dict - #return self.ERROR_INVALID_INPUT - - mode_select = self.get_fec_mode() - if (mode_select < 0): - self.log(self.LOG_ERROR, "get_mode failed ret_code: {}".format(mode_select)) - output_dict["error_messgae"] = "get_mode failed ret_code: {}".format(mode_select) - return output_dict - #return self.ERROR_GET_FEC_MODE_FAILED - - if mode_select != self.FEC_MODE_RS: - output_dict["error_message"] = "get_fec_stats() on PCS mode not allowed!" - return output_dict - - status = bytearray(121) - lane_mask = 0xF - no_clr_on_rd = 0 - src_ptr = pcsfec_dump_status_short_s() - - status = self.cable_get_pcsfec_stats(target, lane_mask, no_clr_on_rd) - if status is None: - self.log(self.LOG_ERROR, "ERROR: failed to get pcs/fec stats!") - output_dict["error_message"] = "ERROR: failed to get pcs/fec stats!" - return output_dict - #return self.RR_ERROR - - # get fec_type and func_mode - src_ptr.fec_type = status[0] - src_ptr.func_mode = status[1] - - - # FEC - if src_ptr.fec_type != self.CAPI_FEC_TYPE_PCS: - fecrx_status = fecrx_status_short_s() - start_idx = 2 # skip first two bytes, fec_type and func_mode - - fecrx_status.am_lolock_sticky = status[start_idx] - fecrx_status.dgbox_clsn_sticky = status[start_idx+1] - fecrx_status.hi_ser_sticky = status[start_idx+2] - fecrx_status.xdec_err_sticky = status[start_idx+3] - fecrx_status.fec_link_stat = status[start_idx+4] - fecrx_status.fec_link_stat_sticky= status[start_idx+5] - - fecrx_status.tot_frame_rev_cnt = struct.unpack_from("> 1) - self.log(self.LOG_DEBUG, "Timer = {}".format(timer)) - - return timer - else: - self.log(self.LOG_ERROR, "Get Timer value command execution failed") - return False - - def restart_anlt(self, target): - """ - This API restarts auto-negotiation + link training (AN/LT) mode - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the actual target to restart anlt on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if restart is successful - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - values = self.__util_convert_to_phyinfo_details(target, 0x0F) - core_ip = values[0] - lane_mask = values[1] - self.log(self.LOG_DEBUG, "core_ip {} lane_mask {}".format(core_ip, hex(lane_mask))) - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_ANLT_RESTART, cmd_hdr, cmd_req_body) - - if ret_val == 0 and cmd_rsp_body is None: - self.log(self.LOG_INFO, "AN LT Restart successful") - return True - else: - self.log(self.LOG_ERROR, "AN LT Restart failed") - return False - - def get_anlt_stats(self, target): - """ - This API returns auto-negotiation + link training (AN/LT) mode statistics - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the actual target to get anlt stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET, None - - values = self.__util_convert_to_phyinfo_details(target, 0x0F) - core_ip = values[0] - lane_mask = values[1] - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 9 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_ANLT_GET_STATUS, cmd_hdr, cmd_req_body) - - if self.__validate_read_data(cmd_rsp_body, 9, "anlt get status") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR, None - - ret_array = [0 for _ in range(5)] - if ret_val == 0 and len(cmd_rsp_body) == 9: - ret_array[0] = an_state = cmd_rsp_body[0] - ret_array[1] = lp_ability1 = struct.unpack('H', cmd_rsp_body[1:3])[0] - ret_array[2] = lp_ability2 = struct.unpack('H', cmd_rsp_body[3:5])[0] - ret_array[3] = lp_ability3 = struct.unpack('H', cmd_rsp_body[5:7])[0] - ret_array[4] = lp_fec_ability = struct.unpack('H', cmd_rsp_body[7:9])[0] - - self.log(self.LOG_DEBUG, "Get AN LT AN State = {}".format(an_state)) - self.log(self.LOG_DEBUG, "Get AN LT LP ability1 = {}".format(lp_ability1)) - self.log(self.LOG_DEBUG, "Get AN LT LP ability2 = {}".format(lp_ability2)) - self.log(self.LOG_DEBUG, "Get AN LT LP ability3 = {}".format(lp_ability3)) - self.log(self.LOG_DEBUG, "Get AN LT LP FEC ability = {}".format(lp_fec_ability)) - - else: - self.log(self.LOG_ERROR, "Get AN LT status is failed") - return self.EEPROM_ERROR - - return ret_val, ret_array - - -############################################################################################# -### Debug Functionality ### -############################################################################################# - - - def set_debug_mode(self, enable): - """ - This API enables/disables a debug mode that the port is now - going to be run on. If enabled, this means that PRBS/Loopback etc. type diagnostic mode - is now going to be run on the port and hence normal traffic will be disabled - on it if enabled and vice-versa if disabled. - enable is typically to be used at the software level to inform the software - that debug APIs will be called afterwords. - disable will disable any previously enabled debug functionality inside the cable - so that traffic can pass through. Also it'll inform the software to come out of the debug mode. - The port on which this API is called for can be referred using self.port. - Args: - enable: - a boolean, True if the debug mode needs to be enabled - , False if the debug mode needs to be disabled - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 1 - cmd_hdr[1] = 0 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - cmd_req_body[0] = 1 if (enable == True) else 0 - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_SET_PHY_CHIP_DEBUG_MODE, cmd_hdr, cmd_req_body) - - if ret_val == 0: - return True - - return False - - def get_debug_mode(self): - """ - This API checks if a debug mode is currently being run on the port - for which this API is called for. - This means that PRBS/Loopback etc. type diagnostic mode - if any are being run on the port this should return True else False. - The port on which this API is called for can be referred using self.port. - Args: - Returns: - a boolean, True if debug mode enabled - , False if debug mode not enabled - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 1 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_GET_PHY_CHIP_DEBUG_MODE, cmd_hdr, cmd_req_body) - - if self.__validate_read_data(cmd_rsp_body, 1, "get_debug_mode") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR, None - if ret_val == 0: - if cmd_rsp_body[0] == 1: - return True - - return False - - def enable_prbs_mode(self, target, mode_value, lane_mask, direction=PRBS_DIRECTION_BOTH): - """ - This API configures and enables the PRBS mode/type depending upon the mode_value the user provides. - The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. - Target is an integer for selecting which end of the Y cable we want to run PRBS on. - LaneMap specifies the lane configuration to run the PRBS on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to enable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - an Integer, the mode/type for configuring the PRBS mode. - lane_mask: - an Integer, representing the lane_mask to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011 , means running on lane0 and lane1 - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return False - - if (type(lane_mask) is not int) or (lane_mask & 0xF == 0): - self.log(self.LOG_ERROR, "Invalid lane_mask : {}".format(hex(lane_mask))) - return False - - core_ip, lane_mask = self.__util_convert_to_phyinfo_details(target, lane_mask) - - if mode_value == 0: - prbs_type = self.CABLE_PRBS7 - elif mode_value == 1: - prbs_type = self.CABLE_PRBS9 - elif mode_value == 2: - prbs_type = self.CABLE_PRBS11 - elif mode_value == 3: - prbs_type = self.CABLE_PRBS15 - elif mode_value == 4: - prbs_type = self.CABLE_PRBS23 - elif mode_value == 5: - prbs_type = self.CABLE_PRBS31 - elif mode_value == 6: - prbs_type = self.CABLE_PRBS58 - elif mode_value == 7: - prbs_type = self.CABLE_PRBS49 - elif mode_value == 8: - prbs_type = self.CABLE_PRBS13 - else: - self.log(self.LOG_ERROR, "Error: for checking mux_cable enable PRBS mode, the mode_value is wrong") - return self.ERROR_INVALID_PRBS_MODE - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x2 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = 1 # enable - cmd_req_body[1] = prbs_type - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_PRBS_SET, cmd_hdr, cmd_req_body) - - if ret_val == 0 and cmd_rsp_body is None: - self.log(self.LOG_INFO, "Enable PRBS mode is successful") - return True - else: - self.log(self.LOG_ERROR, "Enable PRBS mode is failed") - return False - - def disable_prbs_mode(self, target, direction=PRBS_DIRECTION_BOTH): - """ - This API disables the PRBS mode on the physical port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - core_ip, lane_mask = self.__util_convert_to_phyinfo_details(target, 0xF) - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x2 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = 0 # disable - cmd_req_body[1] = 0 - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_PRBS_SET, cmd_hdr, cmd_req_body) - - if ret_val == 0 and cmd_rsp_body is None: - self.log(self.LOG_INFO, "Disable PRBS mode is successful") - return True - else: - self.log(self.LOG_ERROR, "Disable PRBS mode command execution failed") - return False - - def enable_loopback_mode(self, target, lane_mask, mode=LOOPBACK_MODE_NEAR_END): - """ - This API configures and enables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - LaneMap specifies the lane configuration to run the loopback on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to enable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - lane_mask: - an Integer, representing the lane_mask to be run loopback on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011 , means running on lane0 and lane1 - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - if (target != self.EYE_PRBS_LOOPBACK_TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and \ - (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return False - - if (type(lane_mask) is not int) or (lane_mask & 0xF == 0): - self.log(self.LOG_ERROR, "Invalid lane mask {}".format(hex(lane_mask))) - return False - - ret_val = self.__util_convert_to_loopback_phyinfo(target, lane_mask, mode) - if ret_val == self.ERROR_INVALID_INPUT: - return self.ERROR_INVALID_INPUT - - core_ip = ret_val[0] - lane_mask = ret_val[1] - mode = ret_val[2] - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x2 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = mode - cmd_req_body[1] = 1 # enable - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_SET_LOOPBACK, cmd_hdr, cmd_req_body) - - if ret_val == 0 and cmd_rsp_body is None: - self.log(self.LOG_INFO, "Enable looback mode is successful") - return True - else: - self.log(self.LOG_ERROR, "Enable loopback mode is failed") - return False - - def disable_loopback_mode(self, target): - """ - This API disables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - if (target != self.EYE_PRBS_LOOPBACK_TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and \ - (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return False - - ret_val = self.__util_convert_to_loopback_phyinfo(target, 0xF, self.LOOPBACK_MODE_NEAR_END) - if ret_val == self.ERROR_INVALID_INPUT: - return self.ERROR_INVALID_INPUT - - core_ip = ret_val[0] - lane_mask = ret_val[1] - mode = ret_val[2] - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x2 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - # disable LOOPBACK_MODE_NEAR_END first - cmd_req_body[0] = mode - cmd_req_body[1] = 0 # disable - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_SET_LOOPBACK, cmd_hdr, cmd_req_body) - - if ret_val != 0: - self.log(self.LOG_ERROR, "Disable loopback mode is failed") - return False - - # disable LOOPBACK_MODE_FAR_END next - ret_val = self.__util_convert_to_loopback_phyinfo(target, 0xF, self.LOOPBACK_MODE_FAR_END) - if ret_val == self.ERROR_INVALID_INPUT: - return self.ERROR_INVALID_INPUT - mode = ret_val[2] - - cmd_req_body[0] = mode - cmd_req_body[1] = 0 # disable - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_SET_LOOPBACK, cmd_hdr, cmd_req_body) - - if ret_val == 0 and cmd_rsp_body is None: - self.log(self.LOG_INFO, "Disable looback mode is successful") - return True - else: - self.log(self.LOG_ERROR, "Disable loopback mode is failed") - return False - - def get_loopback_mode(self, target): - """ - This API returns the Loopback mode on the port which it has been configured to - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - """ - - if (target != self.EYE_PRBS_LOOPBACK_TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_A) and \ - (target != self.EYE_PRBS_LOOPBACK_TARGET_TOR_B) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - ret_val = self.__util_convert_to_loopback_phyinfo(target, 0xF, self.LOOPBACK_MODE_FAR_END) - if ret_val == self.ERROR_INVALID_INPUT: - return self.ERROR_INVALID_INPUT - - core_ip = ret_val[0] - lane_mask = ret_val[1] - mode = ret_val[2] - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x1 - cmd_hdr[1] = 0x1 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = mode - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_LOOPBACK, cmd_hdr, cmd_req_body) - if self.__validate_read_data(cmd_rsp_body, 1, "get loopback") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - if ret_val == 0: - if cmd_rsp_body[0] == 1: - self.log(self.LOG_INFO, "The Far-End loopback mode is set ON") - return self.LOOPBACK_MODE_FAR_END - else: - self.log(self.LOG_ERROR, "Error getting the loopback mode ON/OFF") - return self.LOOPBACK_MODE_NONE - - # check NEAR_END loopback - ret_val = self.__util_convert_to_loopback_phyinfo(target, 0xF, self.LOOPBACK_MODE_NEAR_END) - if ret_val == self.ERROR_INVALID_INPUT: - return self.ERROR_INVALID_INPUT - mode = ret_val[2] - - cmd_req_body[0] = mode - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_LOOPBACK, cmd_hdr, cmd_req_body) - if self.__validate_read_data(cmd_rsp_body, 1, "get loopback") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - if ret_val == 0: - if cmd_rsp_body[0] == 1: - self.log(self.LOG_INFO, "The Near-End loopback mode is set ON") - return self.LOOPBACK_MODE_NEAR_END - else: - self.log(self.LOG_ERROR, "Error getting the loopback mode ON/OFF") - return self.LOOPBACK_MODE_NONE - - return self.LOOPBACK_MODE_NONE - - - def reg_dump(self): - """ - This API should dump all registers with meaningful values - for the cable to be diagnosed for proper functioning. - This means that for all the fields on relevant vendor-specific pages - this API should dump the appropriate fields with parsed values - which would help debug the Y-Cable - - Args: - None - Returns: - a string: - with all the relevant key-value pairs for all the meaningful fields - which would help diagnose the cable for proper functioning - """ - - output_str = "PHY CHIP DEBUG info dump\n" - ret_code, reg_val = self.rd_reg_ex(0x5200C820, 0x0) - if ret_code == -1: - self.log(self.LOG_ERROR, "debug dump register read eeprom failed") - return self.EEPROM_ERROR - - output_str += "active port status = {}\n".format(hex(reg_val)) - - ret_code, reg_val = self.rd_reg_ex(0x5200C894, 0x0) - output_str += "standby port status = {}\n".format(hex(reg_val)) - - ret_code = self.wr_reg_ex(0x5200C81C, 0xFFFF, 0x0) - if ret_code is False: - print("ERROR: Writing to 0x5200C81C Failed!") - - ret_code = self.wr_reg_ex(0x5200C81C, 0x0, 0x0) - if ret_code is False: - print("ERROR: Writing to 0x5200C81C Failed!") - - ret_code, reg_val = self.rd_reg_ex(0x5200C8B4, 0x0) - output_str += "GP_REG_45_int register = {} (cmd_ret: {})\n".format(hex(reg_val), ret_code) - - output_str += "\nCW=>LW IPC registers:\n" - for i in range(0, 4): - reg_addr = 0x5200CC20 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - output_str += "Lane {} = {} (cmd_ret: {})\n".format(i, hex(reg_val), ret_code) - - output_str += "\nLW=>CW IPC registers\n" - for i in range(0, 4): - reg_addr = 0x5200CC40 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - output_str += "Lane {} = {} (cmd_ret: {})\n".format(i, hex(reg_val), ret_code) - - output_str += "\nCW=>BH IPC registers\n" - for i in range(0, 8): - reg_addr = 0x5200CC60 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - output_str += "{} Lane {} = {} (cmd_ret: {})\n".format("TORB" if i > - 3 else "TORA", i, hex(reg_val), ret_code) - - output_str += "\nBH=>CW IPC registers\n" - for i in range(0, 8): - reg_addr = 0x5200CCA0 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - output_str += "{} Lane {} = {} (cmd_ret: {})\n".format("TORB" if i > - 3 else "TORA", i, hex(reg_val), ret_code) - - mode = self.cable_get_mode() - output_str += "\npcs receive irq status registers\n" - output_str += "lanes 0 to 3\n" - for i in range(0, 3): - reg_addr = 0x52007E80 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - if(i == 0): - output_str += "{} {} = {}\n".format("DESK_ALIGN_LOSS:", hex(reg_addr), hex(reg_val)) - elif i == 1: - output_str += "{} {} = {}\n".format("DSKW0:", hex(reg_addr), hex(reg_val)) - elif i == 2: - output_str += "{} {} = {}\n".format("DSKW1:", hex(reg_addr), hex(reg_val)) - - for i in range(0, 4): - reg_addr = 0x52007E8C + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - reg_val = reg_val & 0x7FFF # dont clear bit 15 - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - output_str += "Lane {} {} = {}\n".format(i, hex(reg_addr), hex(reg_val)) - if(mode == 0 or mode == 2): # for fec modes - output_str += "FEC irq status\n" - for i in range(0, 4): - reg_addr = 0x52007ED0 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - if(i == 0): - output_str += "{} {} = {}\n".format("DEC_AM_LOCK_UNLOCK:", hex(reg_addr), hex(reg_val)) - elif i == 1: - output_str += "{} {} = {}\n".format("DEC_DGBOX:", hex(reg_addr), hex(reg_val)) - elif i == 2: - output_str += "{} {} = {}\n".format("DEC_IGBOX:", hex(reg_addr), hex(reg_val)) - elif i == 3: - output_str += "{} {} = {}\n".format("XDEC_ERR:", hex(reg_addr), hex(reg_val)) - for i in range(0, 2): - reg_addr = 0x52007E60 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - if(i == 0): - output_str += "{} {} = {}\n".format("ENC_GBOX:", hex(reg_addr), hex(reg_val)) - elif i == 1: - output_str += "{} {} = {}".format("ENC_PFIFO:", hex(reg_addr), hex(reg_val)) - output_str += "lanes 4 to 7\n" - for i in range(0, 3): - reg_addr = 0x52017E80 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - if(i == 0): - output_str += "{} {} = {}\n".format("DESK_ALIGN_LOSS:", hex(reg_addr), hex(reg_val)) - elif i == 1: - output_str += "{} {} = {}\n".format("DSKW0:", hex(reg_addr), hex(reg_val)) - elif i == 2: - output_str += "{} {} = {}\n".format("DSKW1:", hex(reg_addr), hex(reg_val)) - - for i in range(0, 4): - reg_addr = 0x52017E8C + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - reg_val = reg_val & 0x7FFF # dont clear bit 15 - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - output_str += "Lane {} {} = {}\n".format(i, hex(reg_addr), hex(reg_val)) - if(mode == 0 or mode == 2): # for fec modes - output_str += "FEC irq status\n" - for i in range(0, 4): - reg_addr = 0x52017ED0 + i * 4 - ret_code, reg_val = self.rd_reg_ex(reg_addr, 0x0) - if ret_code == -1: - print("ERROR: rd_reg_ex {} Failed!".format(hex(reg_addr))) - ret_code = self.wr_reg_ex(reg_addr, reg_val, 0x0) - if ret_code is False: - print("ERROR: wr_reg_ex to {} Failed!".format(hex(reg_addr))) - if(i == 0): - output_str += "{} {} = {}\n".format("DEC_AM_LOCK_UNLOCK:", hex(reg_addr), hex(reg_val)) - elif i == 1: - output_str += "{} {} = {}\n".format("DEC_DGBOX:", hex(reg_addr), hex(reg_val)) - elif i == 2: - output_str += "{} {} = {}\n".format("DEC_IGBOX:", hex(reg_addr), hex(reg_val)) - elif i == 3: - output_str += "{} {} = {}\n".format("XDEC_ERR:", hex(reg_addr), hex(reg_val)) - print("\n") - - return output_str - - def debug_dump_registers(self, option=None): - """ - This API should dump all registers with meaningful values - for the cable to be diagnosed for proper functioning. - This means that for all the fields on relevant vendor-specific pages - this API should dump the appropriate fields with parsed values - which would help debug the Y-Cable - - Args: - option : command string, optionally. - - The command-string format will contain user readable command with arguments. - Example: - command1 - command1() - command1(1, 2) - command1(1, [-110, 0, 80, 0, 0], 0) - command1(True) - get_switch_count_target(manual, 1, None) - Returns: - a Dictionary: - with all the relevant key-value pairs for all the meaningful fields - which would help diagnose the cable for proper functioning - """ - output_dict = {} - - if platform.system() != "Windows": - path = "/usr/share/sonic/firmware/brcm_cmd_output" - cmd_name = None - cmd_ret_val = None - - # check argument type - if((type(option) is str) or - (option is None)): - pass - else: - self.log(self.LOG_ERROR, "Invalid input {}".format(option)) - output_dict["error_message"] = "Invalid input {}".format(option) - return output_dict - #return self.ERROR_INVALID_INPUT - - # Delete file - if platform.system() != "Windows": - if os.path.exists(path+".db"): - os.remove(path+".db") - - if (option is None) or (option == "None"): - cmd_name = "reg_dump" - arg_list = [] - else: - # parse option to cmd_name and arg_list - # if no argsthen arg_list will be None - cmd_name, arg_list = self.convert_to_arg_list(option) - - if ((cmd_name is None) or - (cmd_name == self.RR_ERROR) or - (arg_list == self.RR_ERROR)): - - self.log(self.LOG_ERROR, "ERROR : invalid command : {} or invalid args : {} ".format(cmd_name, arg_list)) - output_dict["error_message"] = "ERROR : invalid command : {} or invalid args : {}".format(cmd_name, arg_list) - return output_dict - #return self.RR_ERROR - - if cmd_name is not None: - if (self.debug_dump_list.get(cmd_name, None) is not None): - try: - func_name = getattr(self, self.debug_dump_list[cmd_name].func) - - # First process the commands without arguments - if((arg_list == []) and - (len(arg_list) == self.debug_dump_list[cmd_name].arg_len)): - cmd_ret_val = func_name() - - elif (arg_list[0] == "--help" or arg_list[0] == "?"): - cmd_ret_val = self.print_commands_desc(cmd_name) - - # process the commands with arguments - elif((arg_list != []) and - (len(arg_list) == self.debug_dump_list[cmd_name].arg_len)): - cmd_ret_val = func_name(*arg_list) - else: - self.log(self.LOG_ERROR, "ERROR : Command : {} found and arg_length : {} is not macthing".format(cmd_name, len(arg_list))) - output_dict["error_message"] = "ERROR : Command : {} found and arg_length : {} is not macthing".format(cmd_name, len(arg_list)) - return output_dict - #return self.RR_ERROR - - except Exception as e: - self.log(self.LOG_ERROR, "ERROR : function failure") - output_dict["error_message"] = "ERROR : function failure" - return output_dict - #return self.RR_ERROR - else: - self.log(self.LOG_ERROR, "ERROR : Command : {} not found in list".format(cmd_name)) - output_dict["error_message"] = "ERROR : Command : {} not found in list".format(cmd_name) - return output_dict - #return self.RR_ERROR - - else: - self.log(self.LOG_ERROR, "Command not supported: {}".format(cmd_name)) - self.log(self.LOG_ERROR, "Warning: {} command unrecognized".format(option)) - output_dict["error_message"] = "Warning: {} command unrecognized".format(option) - return output_dict - #return self.RR_ERROR - - # write the function output to the file - if platform.system() != "Windows": - s = shelve.open(path) - s["command"] = cmd_name - s["out"] = cmd_ret_val - s.close() - - output_dict["command"] = cmd_name - output_dict["out"] = cmd_ret_val - - return output_dict - - def print_commands_desc(self, cmd): - - for cmd_name in self.debug_dump_list: - if cmd == cmd_name: - output_str = "No of args : {}\t desc : {}".format(self.debug_dump_list[cmd_name].arg_len, self.debug_dump_list[cmd_name].description) - output_str += "\n" - - def convert_to_arg_list(self, str_main): - """ - This internal API converts given command-string into 'command_name' - and list arguments. - The command-string format will contain user readable command with arguments. - Example: - command1 ? - command1 --help - command1 - command1() - command1(1) - command1(1, 2) - command1(1, [-110, 0, 80, 0, 0], 0) - command1(True) - get_switch_count_target(manual, 1, None) - - Args: - command_string - Returns: - command name : string - list : list of arguments - """ - - ## check any delimiter "(" or "[" or "]" to get the command_name - re_cmd = re.search('[\][(]', str_main) - if re_cmd is None: - - if((str_main.find('?') != -1) or (str_main.find("--help") != -1)): - re_cmd = str_main.split(' ')[0] - arg_list = [str_main.split(' ')[1]] - return re_cmd, arg_list - else: - # None means only command name - return str_main, [] - else: - re_cmd = re.search(r'(.*?)\(', str_main) - if re_cmd is None: - return self.RR_ERROR, self.RR_ERROR - else: - cmd = re_cmd.group(1) - - # process arguments list - re_args = re.search(r'\((.*?)\)$', (re.sub('[ ]', '', str_main))) - if re_args is None: - return cmd, [] - else: - args = re_args.group(1) - if (len(args) == 0): - # lenth 0 menas no arguments - return cmd, [] - - # convert args string to list of arguments - - # 1. Check: if list is not having matching "[" and "]" braces, it will error out - if(len(re.findall("[\[]", args)) != len(re.findall("[\]]", args))): - return cmd, self.RR_ERROR - - # 2. split the args with "," delimiter - cmd_str = args.split(",") - arg_list = self.add_list_elements(cmd_str) - - return cmd, arg_list - - def add_list_elements(self, arg_str_list): - """ - This internal API takes the list of strings as arguments and converts - all the types to "int, list, boolean & string" - - The arguments strings in format will be - Example: - ['1', '-2', '3'] - ['manual', '[1', '2', '3]', '0'] - ['manual', '[1', '-2', '3]', 'True'] - - Args: - list_of_strings - Returns: - List - it will get updated with converted types - Example: - list : [1, -2, 3] - list : ['manual', [1,2,3], 0] - list : ['manual', [1,-2,3], True] - - """ - - arg_list = [] - list_found = 0 - - for i in range(len(arg_str_list)): - - arg_name = arg_str_list[i] - arg_name = re.sub("[\"']", "", arg_name) - - if(arg_name.find('[') != -1): - list_found = 1 - sub_list = [] - - # if arg_name starts with "[" remove "[" from arg - arg_name = re.sub("[\[']", "", arg_name) - - if(arg_name.find(']') != -1): - # if arg_name ends with "]" also remove "]" from arg - arg_name = re.sub("[\]']", "", arg_name) - data = self.check_datatype(arg_name) - sub_list.append(data) - - arg_list.append(sub_list) - list_found = 0 - sub_list = [] - else: - data = self.check_datatype(arg_name) - sub_list.append(data) - - elif (arg_name.find(']') != -1): - arg_name = re.sub("[\]']", "", arg_name) - data = self.check_datatype(arg_name) - sub_list.append(data) - - arg_list.append(sub_list) - list_found = 0 - sub_list = [] - - elif list_found == 0: - data = self.check_datatype(arg_name) - arg_list.append(data) - else: - data = self.check_datatype(arg_name) - sub_list.append(data) - - return arg_list - - - def check_datatype(self, arg_str): - """ - This internal API takes the string as arguments and converts - all the types to "int, list, boolean & string" based on the input check - and appends to the arg_list - - The arguments strings in format will be - Example: - '1' - '-2' - 'manual' - 'True' - - Args: - string - Returns : - converted Data - Example : - 1 - True - -2 - 'manual' - """ - ret_data = None - - # digit like 0x2, 0xA5F - if(((arg_str.find('0x') != -1) or - (arg_str.find('0X') != -1)) and - (all(c in string.hexdigits for c in arg_str[2:]) == True)): - ret_data = int(arg_str, 16) - #digit like 2, -3 - elif((arg_str[0:].isdigit() == True) or - (arg_str.startswith("-") and - (arg_str[1:].isdigit() == True))): - ret_data = int(arg_str) - elif(arg_str.upper() == "TRUE"): - ret_data = True - elif(arg_str.upper() == "FALSE"): - ret_data = False - elif(arg_str.upper() == "NONE"): - ret_data = None - else: - ret_data = arg_str - - return ret_data - -############################################################################## -# -# Broadcom internal/debug functions -# -############################################################################## - - def rd_reg_ex(self, reg_addr, lane_map): - """ - This API specifically used to read the register values - - Args: - reg_addr: - an hexadecomal,the register address which we intrested to read - lane_map: - register belong to lane_map to be read - - Returns: - an integer, on sucess returns the register values - unsigned integer, register value - - """ - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 5 - cmd_hdr[1] = 4 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - if lane_map == 0 or lane_map is None: - cmd_req_body[0] = 0 - else: - # if lane_mask is for 4..7 lanes, then set port_id to 1. Else, port_id to 0 - if (lane_map & 0xF0): - cmd_req_body[0] = 1 - else: - cmd_req_body[0] = 0 - - cmd_req_body[1] = (reg_addr & 0xFF) - cmd_req_body[2] = ((reg_addr >> 8) & 0xFF) - cmd_req_body[3] = ((reg_addr >> 16) & 0xFF) - cmd_req_body[4] = ((reg_addr >> 24) & 0xFF) - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_READ_REG, cmd_hdr, cmd_req_body) - if ret_val == 0: - out = struct.unpack('I', cmd_rsp_body)[0] - else: - out = None - - return ret_val, out - - def wr_reg_ex(self, reg_addr, reg_value, lane_map): - """ - This API specifically used to write the register values - - Args: - reg_addr: - an hexadecomal,the register address where we want to write value - reg_value: - an hexadecomal,the register value which we want to write - lane_map: - Write register to be performed to given lane_map block - - Returns: - a Boolean, true if the write register succeeded and false if it did not succeed. - - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 9 - cmd_hdr[1] = 0 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - if lane_map == 0 or lane_map is None: - cmd_req_body[0] = 0 - else: - # if lane_mask is for 4..7 lanes, then set port_id to 1. Else, port_id to 0 - if (lane_map & 0xF0): - cmd_req_body[0] = 1 - else: - cmd_req_body[0] = 0 - - cmd_req_body[1] = (reg_addr & 0xFF) - cmd_req_body[2] = ((reg_addr >> 8) & 0xFF) - cmd_req_body[3] = ((reg_addr >> 16) & 0xFF) - cmd_req_body[4] = ((reg_addr >> 24) & 0xFF) - cmd_req_body[5] = (reg_value & 0xFF) - cmd_req_body[6] = ((reg_value >> 8) & 0xFF) - cmd_req_body[7] = ((reg_value >> 16) & 0xFF) - cmd_req_body[8] = ((reg_value >> 24) & 0xFF) - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_WRITE_REG, cmd_hdr, cmd_req_body) - - if cmd_rsp_body is not None: - self.log(self.LOG_ERROR, "ERROR: response not expected") - - return ret_val - - def util_print_ctx_debug(self): - """ - Utility api to print context debug info - """ - ret_code, cnt_val = self.rd_reg_ex(0x5200CCE0, 0x0) - if ret_code != 0: - return self.EEPROM_ERROR - ret_code, tmp_start_ppm = self.rd_reg_ex(0x5200CCE4, 0x0) - if ret_code != 0: - return self.EEPROM_ERROR - ret_code, tmp_stop_ppm = self.rd_reg_ex(0x5200CCE8, 0x0) - if ret_code != 0: - return self.EEPROM_ERROR - ret_code, tmp_bh_ppm = self.rd_reg_ex(0x5200CCEC, 0x0) - if ret_code != 0: - return self.EEPROM_ERROR - - start_ppm = c_int16(tmp_start_ppm).value - stop_ppm = c_int16(tmp_stop_ppm).value - bh_ppm = c_int16(tmp_bh_ppm).value - #print("cnt_val {} start_ppm {} stop_ppm {} bh_ppm {}".format(cnt_val, start_ppm, stop_ppm, bh_ppm)) - - if (start_ppm & 0x1000): - start_ppm = start_ppm | 0xFFFF0000 - - if (bh_ppm & 0x1000): - bh_ppm = bh_ppm | 0xFFFF0000 - - if (stop_ppm & 0x1000): - stop_ppm = stop_ppm | 0xFFFF0000 - - start_ppm = (start_ppm * 10)/105 - stop_ppm = (stop_ppm * 10)/105 - bh_ppm = (bh_ppm * 10)/105 - - ret_code, switch_time = self.rd_reg_ex(0x5200C7D4, 0x0) - if ret_code != 0: - return self.EEPROM_ERROR - - print("cnt_val = {}".format(cnt_val)) - print("start_ppm = {}".format(start_ppm)) - print("stop_ppm = {}".format(stop_ppm)) - print("bh_ppm = {}".format(bh_ppm)) - print("switch_time = {}".format(switch_time)) - - return ret_code - - def __qsfp_is_valid_page(self, page): - - if ((page == 5 or page == 6 or page == 7 or page == 8 or page == 9 or page == 10 or page == 11 or page == 12 or page == 13 or page == 14) or - (page == 0 or page == 1 or page == 2 or page == 4 or page == 3 or page == 0x80 or page == 0x81 or page == 0x83 or - page == 0x82 or page == 0xB1 or page == 0xFF or page == 0xFE or page == 0xFD)): - return True - - return False - - def cable_print_qsfp_page(self, interface, page_no): - """ - This API prints QSFP registers for give interface/side and page number - - Args: - interface: - 0 - TORA - 1 - TORB - 2 - NIC - page_no: - an Integer, indicates the page number - - Returns: - an bool, True on success - False on failure - """ - - if interface != self.TARGET_NIC and interface != self.TARGET_TOR_A and interface != self.TARGET_TOR_B: - self.log(self.LOG_ERROR, "Invalid target {}".format(interface)) - return False - - if self.__qsfp_is_valid_page(page_no) == False: - self.log(self.LOG_ERROR, "Error: invalid page no {}".format(hex(page_no))) - return False - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 4 - cmd_hdr[1] = 16 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - cmd_req_body[0] = interface - cmd_req_body[1] = page_no - - if (page_no): - itr = 8 - else: - itr = 16 - - for i in range(0, itr): - if (page_no): - start_off = 0x80 + i*16 - else: - start_off = i*16 - - cmd_req_body[2] = start_off - cmd_req_body[3] = 16 - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_DUMP_PAGE, cmd_hdr, cmd_req_body) - - if ret_val == 0: - print('0x{0:0{1}x}'.format((i*16), 2), end=" ") - for j in range(0, 16): - print('0x{0:0{1}x}'.format(cmd_rsp_body[j], 2), end=" ") - print("\n") - - else: - self.log(self.LOG_ERROR, "QSFP_DUMP_PAGE failed! interface {} page {}".format(interface, page_no)) - return False - - return True - - def cable_set_mode(self, cable_mode): - """ - This API specifically set the cable mode on the port user provides. - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - - cable_mode: - an Integer, specifies the cable_mode - CABLE_MODE_100G_FEC -> 0 - CABLE_MODE_100G_PCS -> 1 - CABLE_MODE_50G_FEC -> 2 - CABLE_MODE_50G_PCS -> 3 - Returns: - a boolean, true if the cable mode is set - , false if the cable mode set failed - """ - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 1 - cmd_hdr[1] = 0 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - if cable_mode == 0: - mode = "CABLE_MODE_100G_FEC" - elif cable_mode == 1: - mode = "CABLE_MODE_100G_PCS" - elif cable_mode == 2: - mode = "CABLE_MODE_50G_FEC" - elif cable_mode == 3: - mode = "CABLE_MODE_50G_PCS" - else: - self.log(self.LOG_ERROR, "CABLE MODE input is wrong") - return False - - cmd_req_body[0] = cable_mode - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_SET_MODE, cmd_hdr, cmd_req_body) - if ret_val == -1: - self.log(self.LOG_ERROR, "set mode read eeprom failed") - return self.EEPROM_ERROR - - if ret_val == 0: - self.log(self.LOG_INFO, "CABLE MODE SET {} SUCCESSFUL".format(mode)) - return True - else: - if cmd_rsp_body is not None: - self.log(self.LOG_ERROR, "ERROR: Responce unexpected") - - self.log(self.LOG_ERROR, "CABLE MODE SET {} NOT SUCCESSFUL".format(mode)) - return False - - def cable_get_mode(self): - """ - This API specifically set the cable mode on the port user provides. - - Args: - None - - Returns: - integer , specifies one of the cable_mode (0 - CABLE_MODE_100G_FEC, - 1 - CABLE_MODE_100G_PCS, 2 - CABLE_MODE_50G_FEC, 3 - CABLE_MODE_50G_PCS) - -1 if api fails - """ - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 1 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_MODE, cmd_hdr, cmd_req_body) - - if self.__validate_read_data(cmd_rsp_body, 1, "get cable mode") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR - - if ret_val == 0: - regval_read = struct.unpack(" local side, - 1 - PRBS_TARGET_TOR1 -> TOR 1 - 2 - PRBS_TARGET_TOR2 -> TOR 2 - 3 - PRBS_TARGET_NIC -> NIC - mode_value: - an Integer, the mode/type for configuring the PRBS mode. - 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31 - lane_map: - an Integer, representing the lane_map to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011 , means running on lane0 and lane1 - Returns: - a boolean, true if the PRBS lock is successful - , false if the PRBS lock is failed - - lock_status, lock status - each bit represents a lane PRBS lock stats - - list, error count list contains error count for each lane - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - - if (type(lane_mask) is not int) or (lane_mask & 0xF == 0): - self.log(self.LOG_ERROR, "Lane mask not Valid ") - return self.ERROR_INVALID_INPUT - - core_ip, lane_mask = self.__util_convert_to_phyinfo_details(target, lane_mask) - if mode_value == 0: - prbs_type = self.CABLE_PRBS7 - elif mode_value == 1: - prbs_type = self.CABLE_PRBS9 - elif mode_value == 2: - prbs_type = self.CABLE_PRBS11 - elif mode_value == 3: - prbs_type = self.CABLE_PRBS15 - elif mode_value == 4: - prbs_type = self.CABLE_PRBS23 - elif mode_value == 5: - prbs_type = self.CABLE_PRBS31 - elif mode_value == 6: - prbs_type = self.CABLE_PRBS58 - elif mode_value == 7: - prbs_type = self.CABLE_PRBS49 - elif mode_value == 8: - prbs_type = self.CABLE_PRBS13 - elif mode_value == 0xff: - prbs_type = 0xff - else: - self.log(self.LOG_ERROR, "Error: for checking mux_cable check PRBS mode, the mode_value is wrong") - return self.ERROR_INVALID_PRBS_MODE - - self.log(self.LOG_DEBUG, "Check PRBS for core_ip {} lane_mask {} prbs_type {}".format( - core_ip, hex(lane_mask), prbs_type)) - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0x2 - cmd_hdr[1] = 0x21 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = 1 # enable - cmd_req_body[1] = prbs_type - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_PRBS_CHK, cmd_hdr, cmd_req_body) - - if self.__validate_read_data(cmd_rsp_body, 0x21, "PRBS Check") == self.EEPROM_READ_DATA_INVALID: - return self.EEPROM_ERROR, None, None - - lock_sts = int(cmd_rsp_body[0]) - self.log(self.LOG_DEBUG, "ret_val {} lock_status {}".format(ret_val, hex(lock_sts))) - err_cnt_list = [] - - if ret_val == 0: - if cmd_rsp_body is not None: - for i in range(0, 8): - if lane_mask & (1 << i): - if lock_sts & (1 << i): - self.log(self.LOG_DEBUG, "Lane {} PRBS_LOCKED".format(i)) - else: - self.log(self.LOG_DEBUG, "Lane {} PRBS_NOT_LOCKED".format(i)) - - err_cnt = struct.unpack_from('I', cmd_rsp_body, 1 + i*4)[0] - err_cnt_list.append(err_cnt) - self.log(self.LOG_DEBUG, "Error count[{}] : {} ".format(i, hex(err_cnt_list[i]))) - else: - self.log(self.LOG_WARN, "The check PRBS returned none") - return self.EEPROM_ERROR, None, None - else: - self.log(self.LOG_ERROR, "Check PRBS mode is failed") - return self.EEPROM_ERROR, None, None - - return ret_val, lock_sts, err_cnt_list - - def cable_get_intr_status(self): - """ - This API spcifically gets the Lane interupt status,Chip interupt status - and Port interupt status on torA, torB and NIC. - - bits Name Description - 3-0 TORA torA cdr loss of lock - 7-4 NIC nic cdr loss of lock - - 3-0 TORB torB cdr loss of lock - 7-4 TORB torB loss - - 3-0 TORA torA loss - 7-4 NIC nic loss - - 0-2 phy watchdog,fw ser,fw ded status respectively - 7-3 reserved - - 0 active tor to nic fault - 1 nic to torA link fault - 2 nic to torB link fault - 7-3 reserved - - 0 torA to nic pcs fec_link - 1 torB to nic pcs fec link - 7-2 reserved - - Args: - - physical_port: - an Integer, the actual physical port connected to a Y cable - Returns: - a bytearray, with Nic and torA loss of lock intr status,torB cdr loss of lock - and torB loss intr status,torA loss and Nic loss intr status, - CHIP interupt status ,PORT interupt status1, - PORT interupt status2. - - """ - - intr_status = bytearray(9) - curr_offset = [self.QSFP28_LP_5_TX_RX_CDR_LOL, - self.QSFP28_LOS_LOL_SEC, - self.QSFP28_LP_3_TX_RX_LOSS, - self.QSFP28_MESC_FAULT, - self.QSFP28_LINK_FAULT, - self.QSFP28_LINK_DOWN, - self.QSFP28_BIP_CW_ERR_FAULT, - self.QSFP28_LP_6_TEMP_WARN, - self.QSFP28_INSERT_ERR_FAULT] - - for ind in range(0, len(curr_offset)): - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset[ind], 1) - if result is None: - self.log(self.LOG_ERROR, "intr_status read_eeprom failed") - return self.EEPROM_ERROR - else: - self.log(self.LOG_DEBUG, "intr_result[{}] value : {}".format(ind, hex(result[0]))) - - if curr_offset[ind] == self.QSFP28_LP_5_TX_RX_CDR_LOL: - self.log(self.LOG_DEBUG, "LANE Interupt status") - status = struct.unpack(" is documented below - - Byte offset bits Name Description - < > 0 squelch 0x01 enable squelch - 0x00 enable un-squelch - 0 direction 0x02 direction Egress(Tx) - 0x00 direction Ingress(Rx) - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the actual target to get the cursor values on - TARGET_NIC -> NIC, - TARGET_TOR1-> TOR1, - TARGET_TOR2 -> TOR2 - lane_map: - an Integer, representing the lane_map to be set squelch on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011 , means running on lane0 and lane1 - enable: - an Integer,specifies SQUELCH or UNSQUELCH - SQUELCh -> 1 - UNSQUELCH -> 0 - direction: - an Integer, specifies INGRESS, EGRESS or BOTH - INGRESS -> 0 - EGRESS -> 1 - Returns: - a Boolean, True on sucess - False on api fail - """ - - if (target != self.TARGET_TOR_A) and (target != self.TARGET_TOR_B) and (target != self.TARGET_NIC) and (target != self.EYE_PRBS_LOOPBACK_TARGET_LOCAL): - self.log(self.LOG_ERROR, "Invalid target : {}".format(target)) - return self.ERROR_INVALID_TARGET - elif (type(lane_map) is not int) or (lane_map & 0xF == 0): - self.log(self.LOG_ERROR, "Invalid Lane map {}".format(lane_map)) - return self.ERROR_INVALID_INPUT - elif (enable != 0) and (enable != 1): - self.log(self.LOG_ERROR, "Invalid Squelch {}".format(enable)) - return self.ERROR_INVALID_INPUT - elif (direction != 0) and (direction != 1): - self.log(self.LOG_ERROR, "Invalid direction {}".format(direction)) - return self.ERROR_INVALID_INPUT - - ret_val = self.__util_convert_to_phyinfo_details(target, lane_map) - core_ip = ret_val[0] - lane_mask = ret_val[1] - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 2 - cmd_hdr[1] = 0 - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = core_ip - - cmd_req_body[0] = enable - cmd_req_body[1] = direction - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_SET_SQUELCH, cmd_hdr, cmd_req_body) - if ret_val == 0 and cmd_rsp_body is None: - return True - else: - self.log(self.LOG_ERROR, "Command execution failed. ret_val: {}".format(ret_val)) - return False - - def cable_get_squelch(self): - """ - This API specifically returns the Rx squelch and Tx squelch status on TOR and NIC - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - Returns: - an integer, 0 and cmd_rsp_body contains squelch status on success - -1 on api fail - """ - - if self.platform_chassis is not None: - curr_offset = self.QSFP_SQL_STATUS - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if result is None: - self.log(self.LOG_ERROR, "get_squelch read eeprom failed") - return self.EEPROM_ERROR - else: - self.log(self.LOG_ERROR, "platform_chassis is not loaded") - return self.ERROR_PLATFORM_NOT_LOADED - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 4 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = self.CORE_IP_ALL - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_SQUELCH, cmd_hdr, cmd_req_body) - - if ret_val == 0: - lane = 0 - for _ in range(0, 8): - if cmd_rsp_body[0] & (1 << lane): - self.log(self.LOG_DEBUG, "client side rx lane {} is squelch".format(lane)) - lane += 1 - else: - self.log(self.LOG_DEBUG, "client side rx lane {} is un-squelch".format(lane)) - lane += 1 - lane = 0 - for _ in range(0, 8): - if cmd_rsp_body[1] & (1 << lane): - self.log(self.LOG_DEBUG, "client side tx lane {} is squelch".format(lane)) - lane += 1 - else: - self.log(self.LOG_DEBUG, "client side tx lane {} is un-squelch".format(lane)) - lane += 1 - - lane = 0 - for _ in range(0, 8): - if cmd_rsp_body[2] & (1 << lane): - self.log(self.LOG_DEBUG, "line side rx lane {} is squelch".format(lane)) - lane += 1 - else: - self.log(self.LOG_DEBUG, "line side rx lane {} is un-squelch".format(lane)) - lane += 1 - lane = 0 - for _ in range(0, 8): - if cmd_rsp_body[3] & (1 << lane): - self.log(self.LOG_DEBUG, "line side tx lane {} is squelch".format(lane)) - lane += 1 - else: - self.log(self.LOG_DEBUG, "line side tx lane {} is un-squelch".format(lane)) - lane += 1 - else: - self.log(self.LOG_ERROR, "Command execution failed. ret_val: {}".format(ret_val)) - return None - - return cmd_rsp_body - - def cable_get_snr(self): - """ - cable get snr - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0x10 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0x0F - #cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 - #cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 - cmd_hdr[4] = self.CORE_IP_LW - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_GET_SNR, cmd_hdr, cmd_req_body) - if ret_val == 0: - values = [] - values.append(struct.unpack('> 8) & 0xFF - cmd_req_body[2] = (address >> 16) & 0xFF - cmd_req_body[3] = (address >> 24) & 0xFF - cmd_req_body[4] = 4 - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_READ_MCU_RAM, cmd_hdr, cmd_req_body) - if ret_val == 0 and cmd_rsp_body is not None: - return cmd_rsp_body - else: - self.log(self.LOG_ERROR, "cable_read_nic_mcu_ram failed ") - - return None - - def cable_clear_nic_mcu_dump(self): - """ - utility function reads RAM address and returns value - - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = self.CORE_IP_CENTRAL - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_ID_CLEAR_CRASH, cmd_hdr, cmd_req_body) - if ret_val == 0: - self.log(self.LOG_ERROR, "nic_mcu_crash cleared ") - if cmd_rsp_body is not None: - self.log(self.LOG_DEBUG, "CABLE_CMD_ID_CLEAR_CRASH returned value?") - else: - self.log(self.LOG_ERROR, "cable_clear_nic_mcu_crash failed ") - - return None - - def read_tor_ram(self, address): - """ - Utility function to read SRAM address - """ - addr_array = bytearray(4) - buf = bytearray(4) - - addr_array[0] = address & 0xFF - addr_array[1] = (address >> 8) & 0xFF - addr_array[2] = (address >> 16) & 0xFF - addr_array[3] = (address >> 24) & 0xFF - - # write the ram address to read - curr_offset = (0xFD * 128) + 0xF8 - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 4, addr_array) - if result is False: - return self.ERROR_WR_EEPROM_FAILED - - # write count - curr_offset = (0xFD * 128) + 0xF6 - buf[0] = 4 - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buf) - if result is False: - return self.ERROR_WR_EEPROM_FAILED - - curr_offset = (0xFD * 128) + 0xF6 - for _ in range(0, 3000): - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "read_tor_ram: read_eeprom failed") - return self.EEPROM_ERROR - - if status[0] == 0: - break - - curr_offset = (0xFD * 128) + 0xF7 - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "read_tor_ram: read_eeprom failed") - return self.EEPROM_ERROR - - if status[0] == 0: - curr_offset = (0xFD * 128) + 0xFC - val_arr = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 4) - if val_arr is None: - return self.EEPROM_ERROR - else: - return -1 - - return val_arr - - def cable_clear_tor_mcu_dump(self): - """ - Utility function to cear TOR crash info - """ - # clear TOR crash - buf = bytearray(1) - buf[0] = 1 - curr_offset = ((0xFD * 128) + 0xF2) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buf) - if result is False: - return self.ERROR_WR_EEPROM_FAILED - - curr_offset = ((0xFD * 128) + 0xF2) - for _ in range(0, 3000): - status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if status is None: - self.log(self.LOG_ERROR, "clear_tor_crash_info: read_eeprom failed") - return self.EEPROM_ERROR - if status[0] == 0: - break - - def cable_print_nic_mcu_dump(self): - """ - Dump NIC crash info - """ - buff = bytearray() - itr_count = 2048 - address = 0x20030000 - no_crash = 1 - exp_val = ram2_exp_s() - - self.log(self.LOG_DEBUG, "Reading NIC dump data...") - for i in range(0, itr_count): - tval = self.cable_read_nic_mcu_ram(address) - # if tval is None or tval == -1: - if (tval is None) or (tval == self.EEPROM_ERROR): - self.log(self.LOG_ERROR, "cable_print_nic_mcu_dump: read_tor_ram failed") - break - - if i == 0: - value = struct.unpack("\n") - else: - self.log(self.LOG_INFO, "peer tor pcs/fec statistics---------------------->\n") - - cmd_hdr[0] = 0x1 # len of comnd request - cmd_hdr[1] = 0x3C # len of cmd response - cmd_hdr[2] = lane_mask if (core_ip == self.CORE_IP_CLIENT) else 0 # client lanemask - cmd_hdr[3] = lane_mask if (core_ip == self.CORE_IP_LW) else 0 # Line lanemask - cmd_hdr[4] = core_ip # NIC | TOR - - if no_clr_on_rd: - cmd_req_body[0] = 0x10 - else: - cmd_req_body[0] = 0x0 - - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_GET_PCSFEC_STATS, cmd_hdr, cmd_req_body) - - if ret_val == 0: - dump_status_buff = cmd_rsp_body - - cmd_req_body[0] = 0x01 - ret_val, cmd_rsp_body = self.__cable_cmd_execute(self.CABLE_CMD_GET_PCSFEC_STATS, cmd_hdr, cmd_req_body) - if ret_val == 0: - for i in range(len(cmd_rsp_body)): - dump_status_buff.append(cmd_rsp_body[i]) - return dump_status_buff - - return None - - def cable_set_enadis_phy_chip_idle_loop(self, disable): - """ - This API enable or disable the phy chip idle loop - The port on which this API is called for can be referred using self.port. - Args: - disable: - an integer, - 1 - disable - 0 - enable - - Returns: - integer: - 0 on success and -1 on failure - - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - cmd_id = self.CABLE_CMD_ID_DISABLE_PHY_CHIP if disable else self.CABLE_CMD_ID_ENABLE_PHY_CHIP - ret_val, cmd_rsp_body = self.__cable_cmd_execute(cmd_id, cmd_hdr, cmd_req_body) - - if ret_val == 0: - return ret_val - - return None - - def enable_disable_watchdog_tor(self, disable): - """ - This API enable or disable the watchdog tor - The port on which this API is called for can be referred using self.port. - Args: - disable: - an integer, - 1 - disable - 0 - enable - - Returns: - integer: - 0 on success and -1 on failure - - """ - - curr_offset = ((0xFD * 128) + 180) - buffer1 = bytearray(1) - buffer1[0] = disable - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer1) - if result is False: - return self.ERROR_WR_EEPROM_FAILED, None - - return self.RR_SUCCESS - - def enable_disable_watchdog_peer_tor(self, disable): - """ - This API enable or disable the watchdog tor peer - The port on which this API is called for can be referred using self.port. - Args: - disable: - an integer, - 1 - disable - 0 - enable - - Returns: - integer: - 0 on success and -1 on failure - - """ - - curr_offset = ((0xFC * 128) + 0x80) - command = bytearray(1) - command[0] = 0x8 if disable else 0x4 - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, command) - if result is False: - return self.ERROR_WR_EEPROM_FAILED, None - - curr_offset = (0xFC * 128) + 0x80 - for _ in range(0, 30): - rd_done_status = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if rd_done_status is None: - self.log(self.LOG_ERROR, "read status failed") - return self.EEPROM_ERROR - if rd_done_status[0] == 0: - break - - curr_offset = (0xFC * 128) + 0x82 - rd_err_st = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - if rd_err_st is None: - self.log(self.LOG_ERROR, "read error status failed") - return self.EEPROM_ERROR - - if rd_err_st[0] == 0: - return self.RR_SUCCESS - else: - return self.RR_ERROR - - def cable_enable_disable_watchdog_nic(self, disable): - """ - This API enable or disable the phy chip idle loop - The port on which this API is called for can be referred using self.port. - Args: - disable: - an integer, - 1 - disable - 0 - enable - - Returns: - integer: - 0 on success and -1 on failure - - """ - - cmd_hdr = bytearray(5) - cmd_req_body = bytearray(self.MAX_REQ_PARAM_LEN) - - cmd_hdr[0] = 0 - cmd_hdr[1] = 0 - cmd_hdr[2] = 0 - cmd_hdr[3] = 0 - cmd_hdr[4] = 0 - - cmd_id = self.CABLE_CMD_DISABLE_WATCHDOG if disable else self.CABLE_CMD_ENABLE_WATCHDOG - ret_val, cmd_rsp_body = self.__cable_cmd_execute(cmd_id, cmd_hdr, cmd_req_body) - - if ret_val == 0: - return ret_val - - return self.RR_ERROR - - def internal_pre_cmd_check(self, upgrade_info): - """ - This API calls the internal __pre_cmd_check function - """ - return self.__pre_cmd_check(upgrade_info) - - def internal_handle_cmd(self, upgrade_info, cmd_handle): - """ - This API calls the internal __handle_cmd function - """ - return self.__handle_cmd(upgrade_info, cmd_handle) - diff --git a/sonic_y_cable/credo/__init__.py b/sonic_y_cable/credo/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py deleted file mode 100644 index 9e6af58b5..000000000 --- a/sonic_y_cable/credo/y_cable_credo.py +++ /dev/null @@ -1,3849 +0,0 @@ -""" - y_cable_credo.py - - Implementation of Credo Y-Cable -""" - -import math -import time -import struct -import threading -from contextlib import contextmanager - -from ctypes import c_int8 -from sonic_y_cable.y_cable_base import YCableBase - -try: - import sonic_platform.platform -except ImportError as e: - pass - -class RLocker(): - ACQUIRE_LOCK_TIMEOUT = 15 - - def __init__(self): - self.rlock = threading.RLock() - - @contextmanager - def acquire_timeout(self, timeout): - result = self.rlock.acquire(timeout=timeout) - yield result - if result: - self.rlock.release() - -class YCable(YCableBase): - # definitions of the offset with width accommodated for values - # of MUX register specs of upper page 0x04 starting at 640 - # info eeprom for Y Cable - OFFSET_IDENTIFIER_LOWER_PAGE = 0 - OFFSET_INTERNAL_TEMPERATURE = 22 - OFFSET_INTERNAL_VOLTAGE = 26 - OFFSET_IDENTIFIER_UPPER_PAGE = 128 - OFFSET_VENDOR_NAME = 148 - OFFSET_PART_NUMBER = 168 - OFFSET_SERIAL_NUMBER = 196 - OFFSET_DETERMINE_CABLE_READ_SIDE = 640 - OFFSET_CHECK_LINK_ACTIVE = 641 - OFFSET_SWITCH_MUX_DIRECTION = 642 - OFFSET_MUX_DIRECTION = 644 - OFFSET_ACTIVE_TOR_INDICATOR = 645 - OFFSET_API_VERSION = 650 - OFFSET_ENABLE_AUTO_SWITCH = 651 - OFFSET_AUTO_SWITCH_HYSTERESIS = 652 - OFFSET_MANUAL_SWITCH_COUNT_TOR_A = 653 - OFFSET_AUTO_SWITCH_COUNT = 657 - OFFSET_NIC_CURSOR_VALUES = 661 - OFFSET_TOR1_CURSOR_VALUES = 681 - OFFSET_TOR2_CURSOR_VALUES = 701 - OFFSET_NIC_MODE_CONFIGURATION = 721 - OFFSET_NIC_TEMPERATURE = 727 - OFFSET_NIC_VOLTAGE = 729 - OFFSET_NIC_SIGNAL_DETECTION = 731 - OFFSET_MANUAL_SWITCH_COUNT_TOR_B = 737 - OFFSET_EXTEND_SWITCH_COUNT_TYPE = 741 - OFFSET_EXTEND_SWITCH_COUNT = 742 - OFFSET_CLEAR_SWITCH_COUNT = 746 - OFFSET_OPERATION_TIME = 747 - OFFSET_RESET_CAUSE = 751 - OFFSET_CONFIGURE_PRBS_TYPE = 768 - OFFSET_ENABLE_PRBS = 769 - OFFSET_INITIATE_BER_MEASUREMENT = 770 - OFFSET_LANE_1_BER_RESULT = 771 - OFFSET_INITIATE_EYE_MEASUREMENT = 784 - OFFSET_LANE_1_EYE_RESULT = 785 - OFFSET_ENABLE_LOOPBACK = 793 - OFFSET_TARGET = 794 - OFFSET_SYNC_DEBUG_MODE = 795 - - - # definition of VSC command byte - VSC_BYTE_OPCODE = 128 - VSC_BYTE_STATUS = 129 - VSC_BYTE_ADDR0 = 130 - VSC_BYTE_ADDR1 = 131 - VSC_BYTE_ADDR2 = 132 - VSC_BYTE_ADDR3 = 133 - VSC_BYTE_DATA0 = 134 - VSC_BYTE_DATA1 = 135 - VSC_BYTE_DATA2 = 136 - VSC_BYTE_DATA3 = 137 - VSC_BYTE_CHKSUM_LSB = 138 - VSC_BYTE_CHKSUM_MSB = 139 - VSC_BYTE_OPTION = 140 - - # firmware upgrade command options - FWUPD_OPTION_GET_INFO = 0x01 - FWUPD_OPTION_START = 0x02 - FWUPD_OPTION_LOCAL_XFER = 0x03 - FWUPD_OPTION_LOCAL_XFER_COMPLETE = 0x04 - FWUPD_OPTION_UART_XFER = 0x05 - FWUPD_OPTION_UART_XFER_STATUS = 0x06 - FWUPD_OPTION_RUN = 0x07 - FWUPD_OPTION_COMMIT = 0x08 - FWUPD_OPTION_SYNC = 0x09 - FWUPD_OPTION_SYNC_STATUS = 0x0A - - # upper page 0xFA VSC command attribute length - VSC_CMD_ATTRIBUTE_LENGTH = 141 - VSC_BUFF_SIZE = 512 - VSC_BLOCK_WRITE_LENGTH = 32 - - FIRMWARE_INFO_PAYLOAD_SIZE = 48 - EVENTLOG_PAYLOAD_SIZE = 18 - - MAX_NUM_LANES = 4 - - # definition of MIS memorymap page - MIS_PAGE_VSC = 0xFA - MIS_PAGE_FC = 0xFC - - # eventlog command option - EVENTLOG_OPTION_DUMP = 0x01 - EVENTLOG_OPTION_CLEAR = 0x02 - - # VSC opcode - VSC_OPCODE_QUEUE_INFO = 0x18 - VSC_OPCODE_UART_STAT = 0x1C - VSC_OPCODE_SERDES_INFO = 0x1D - VSC_OPCODE_DSP_LOADFW_STAT = 0x1F - VSC_OPCODE_MEM_READ = 0x40 - VSC_OPCODE_FWUPD = 0x80 - VSC_OPCODE_EVENTLOG = 0x81 - VSC_OPCODE_TCM_READ = 0x82 - VSC_OPCODE_TCM_WRITE = 0x83 - VSC_OPCODE_FW_CMD = 0x84 - VSC_OPCODE_FW_CMD_EXT = 0x85 - VSC_OPCODE_REG_READ = 0x86 - VSC_OPCODE_REG_WRITE = 0x87 - - BER_TIMEOUT_SECS = 1 - EYE_TIMEOUT_SECS = 1 - GET_DEBUG_MODE_TIMEOUT_SECS = 1 - EXTEND_SWITCH_CNT_TIMEOUT_SECS = 1 - FWUPD_UART_XFER_TIMEOUT_SECS = 120 - - # error code of EEPROM - EEPROM_READ_DATA_INVALID = -1 - EEPROM_ERROR = -1 - EEPROM_TIMEOUT_ERROR = -1 - EEPROM_GENERIC_ERROR = -1 - - # side bitamp - SIDE_BMP_NIC = 1 - SIDE_BMP_TOR_A = 2 - SIDE_BMP_TOR_B = 4 - SIDE_BMP_ALL = 7 - - CABLE_HEALTHY = True - CABLE_UNHEALTHY = False - - # MCU error code - MCU_EC_NO_ERROR = 0 - MCU_EC_GET_FW_INFO_ERROR = 11 - MCU_EC_UART_TX_BUSY = 13 - MCU_EC_FWUPD_ABORT = 14 - MCU_EC_FWUPD_HEADER_CRC_ERROR = 15 - MCU_EC_FWUPD_META_CRC_ERROR = 16 - MCU_EC_FWUPD_MCU_CRC_ERROR = 17 - MCU_EC_FWUPD_DSP_CRC_ERROR = 18 - MCU_EC_FWUPD_SCRIPT_CRC_ERROR = 19 - MCU_EC_FWUPD_COMPLETE_ERROR = 20 - MCU_EC_FWUPD_COMMIT_ERROR = 21 - MCU_EC_INVALID_EVENT_LOG = 22 - MCU_EC_FWUPD_UART_TIMEOUT = 26 - MCU_EC_FWUPD_INVALID_SEQUENCE = 27 - MCU_EC_FWUPD_SYNC_ERROR = 28 - MCU_EC_FWUPD_ABORT_FROM_THER_OTHER_SIDE = 30 - MCU_EC_FWUPD_IMAGE_SIZE_ERROR = 31 - MCU_EC_WAIT_VSC_STATUS_TIMEOUT = 254 - MCU_EC_UNDEFINED_ERROR = 255 - - MCU_ERROR_CODE_STRING = { - MCU_EC_NO_ERROR : 'No Error', - MCU_EC_GET_FW_INFO_ERROR : 'Get Firmware Info Error', - MCU_EC_UART_TX_BUSY : 'UART TX Busy', - MCU_EC_FWUPD_ABORT : 'Firmware Update Abort', - MCU_EC_FWUPD_HEADER_CRC_ERROR : 'Firmware Update Header CRC Error', - MCU_EC_FWUPD_META_CRC_ERROR : 'Firmware Update Meta CRC Error', - MCU_EC_FWUPD_MCU_CRC_ERROR : 'Firmware Update MCU CRC Error', - MCU_EC_FWUPD_DSP_CRC_ERROR : 'Firmware Update DSP CRC Error', - MCU_EC_FWUPD_SCRIPT_CRC_ERROR : 'Firmware Update Script CRC Error', - MCU_EC_FWUPD_COMPLETE_ERROR : 'Firmware Update Local Transfer Error', - MCU_EC_FWUPD_COMMIT_ERROR : 'Firmware Update Commit Error', - MCU_EC_INVALID_EVENT_LOG : 'Invalid Event Log', - MCU_EC_FWUPD_UART_TIMEOUT : 'Firmware Update UART Timeout', - MCU_EC_FWUPD_INVALID_SEQUENCE : 'Invalid Firmware Update Sequence', - MCU_EC_FWUPD_SYNC_ERROR : 'Firmware Synchronization Error', - MCU_EC_FWUPD_ABORT_FROM_THER_OTHER_SIDE: 'Firmware Update Abort from the Other Side', - MCU_EC_FWUPD_IMAGE_SIZE_ERROR : 'Firmware Update Image Size Error', - MCU_EC_WAIT_VSC_STATUS_TIMEOUT : 'Wait VSC Status Timeout', - MCU_EC_UNDEFINED_ERROR : 'Undefined Error', - } - - def __init__(self, port, main_logger): - """ - Args: - port: - an Integer, the actual physical port connected to a Y cable - """ - YCableBase.__init__(self, port, main_logger) - - self.platform_chassis = None - self.rlock = RLocker() - - try: - self.platform_chassis = sonic_platform.platform.Platform().get_chassis() - self.log_info("chassis loaded {}".format(self.platform_chassis)) - except Exception as e: - self.log_warning("Failed to load chassis due to {}".format(repr(e))) - - def read_mmap(self, page, byte, len=1): - """ - This API converts memory map page and offset to linear address, then returns eeprom values - by calling read_eeprom() - - Args: - page: - an Integer, page number of memorymap - - byte: - an Integer, byte address of the page - - len: - an Integer, length of the reading - - Returns: - an Integer or bytearray, returns the value of the specified eeprom address, returns 0xFF if it did not succeed - """ - if byte < 128: - linear_addr = byte - else: - linear_addr = page * 128 + byte - - ret = self.platform_chassis.get_sfp(self.port).read_eeprom(linear_addr, len) - - if ret is None: - self.log_error('Read Nack! page:%2X byte:%2X' % (page, byte)) - return 0xFF - else: - if len == 1: - try: - return ret[0] - except Exception as e: - self.log_error('Unknown read_mmap error') - return 0xFF - else: - return ret - - def write_mmap(self, page, byte, value, len=1): - """ - This API converts memory map page and offset to linear address for calling write_eeprom() - - Args: - page: - an Integer, page number of memorymap - - byte: - an Integer, byte address of the page - - value: - an Integer or bytearray, value to be written to the address - - len: - an Integer, length to be written - - Returns: - an Boolean, true if succeeded and false if it did not succeed. - """ - - #print ('write page:%02X byte :%02X len:%d type:%s' % (page, byte, len, type(value))) - - if byte < 128: - linear_addr = byte - else: - linear_addr = page * 128 + byte - - if len == 1: - ba = bytearray([value]) - else: - ba = value - - ret = self.platform_chassis.get_sfp(self.port).write_eeprom(linear_addr, len, ba) - - if (ret == False): - self.log_error('Write Failed! page:%2X byte:%2X value:%2X' % (page, byte, value)) - - return ret - - def send_vsc(self, vsc_req_form, timeout=1200): - """ - This API sends Credo vendor specific command to the MCU - - Args: - vsc_req_form: - a bytearray, command request form follow by vsc command structure - - timeout: - an Integer, unit is 5ms, default value is 1200 (6 seconds). - - Returns: - an Integer, status code of vsc command, find the 'MCU_ERROR_CODE_STRING' for the interpretation. - """ - - if self.platform_chassis is not None: - for idx in range(129, YCable.VSC_CMD_ATTRIBUTE_LENGTH): - if vsc_req_form[idx] != None: - self.write_mmap(YCable.MIS_PAGE_VSC, idx, vsc_req_form[idx]) - self.write_mmap(YCable.MIS_PAGE_VSC, YCable.VSC_BYTE_OPCODE, vsc_req_form[YCable.VSC_BYTE_OPCODE]) - - while True: - done = self.read_mmap(YCable.MIS_PAGE_VSC, YCable.VSC_BYTE_OPCODE) - if done == 0: - break - - time.sleep(0.005) - timeout -= 1 - - if timeout == 0: - self.log_error("wait vsc status value timeout") - return YCable.MCU_EC_WAIT_VSC_STATUS_TIMEOUT - - status = self.read_mmap(YCable.MIS_PAGE_VSC, YCable.VSC_BYTE_STATUS) - else: - self.log_error("platform_chassis is not loaded, failed to send vsc cmd") - return YCable.MCU_EC_UNDEFINED_ERROR - - return status - - def fw_cmd(self, cmd, detail1): - """ - This API sends the firmware command to the serdes chip via VSC cmd - - Args: - cmd: - an Integer, command code of the firmware command - - detail1: - an Integer, extra input parameter 1 - - Returns: - a Bytearray, a list of response code and return value - """ - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FW_CMD - vsc_req_form[YCable.VSC_BYTE_OPTION] = 0 - vsc_req_form[130] = (cmd >> 0) & 0xFF - vsc_req_form[131] = (cmd >> 8) & 0xFF - vsc_req_form[132] = (detail1 >> 0) & 0xFF - vsc_req_form[133] = (detail1 >> 8) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('fw cmd[%04X] detail1[%04X] error[%04X]' % (cmd, detail1, status)) - - response = (self.read_mmap(YCable.MIS_PAGE_VSC, 131) << 8) | self.read_mmap(YCable.MIS_PAGE_VSC, 130) - param1 = (self.read_mmap(YCable.MIS_PAGE_VSC, 137) << 8) | self.read_mmap(YCable.MIS_PAGE_VSC, 136) - - return [response, param1] - - def fw_cmd_ext(self, cmd, detail1, detail2): - """ - This API sends the extended firmware command to the serdes chip via VSC cmd - - Args: - cmd: - an Integer, command code of the firmware command - - detail1: - an Integer, extra input parameter 1 - - detail2: - an Integer, extra input parameter 2 - Returns: - a Bytearray, a list of response code, returned value1 and value2 - """ - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FW_CMD_EXT - vsc_req_form[YCable.VSC_BYTE_OPTION] = 0 - vsc_req_form[130] = (cmd >> 0) & 0xFF - vsc_req_form[131] = (cmd >> 8) & 0xFF - vsc_req_form[132] = (detail1 >> 0) & 0xFF - vsc_req_form[133] = (detail1 >> 8) & 0xFF - vsc_req_form[134] = (detail2 >> 0) & 0xFF - vsc_req_form[135] = (detail2 >> 8) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('fw cmd ext[%04X] detail1[%04X] detail2[%04X] error[%04X]' % (cmd, detail1, detail2, status)) - - response = (self.read_mmap(YCable.MIS_PAGE_VSC, 131) << 8) | self.read_mmap(YCable.MIS_PAGE_VSC, 130) - param1 = (self.read_mmap(YCable.MIS_PAGE_VSC, 137) << 8) | self.read_mmap(YCable.MIS_PAGE_VSC, 136) - param2 = (self.read_mmap(YCable.MIS_PAGE_VSC, 139) << 8) | self.read_mmap(YCable.MIS_PAGE_VSC, 138) - - return [response, param1, param2] - - def tcm_read(self, addr): - """ - This API sends the tcm read command to the serdes chip via VSC cmd - - Args: - addr: - an Integer, address of tcm space - Returns: - an Integer, return data of tcm address - """ - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_TCM_READ - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('tcm read addr[%04X] error[%04X]' % (addr, status)) - return -1 - - data = (self.read_mmap(YCable.MIS_PAGE_VSC, 134) | (self.read_mmap(YCable.MIS_PAGE_VSC, 135) << 8) | - (self.read_mmap(YCable.MIS_PAGE_VSC, 136) << 16) | (self.read_mmap(YCable.MIS_PAGE_VSC, 137) << 24)) - - return data - - def tcm_write(self, addr, data): - """ - This API sends the tcm write command to the serdes chip via VSC cmd - - Args: - addr: - an Integer, address of tcm space - - data: - an Integer, value to be written to the address - - Returns: - a boolean, True if the tcm write succeeded and False if it did not succeed. - """ - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_TCM_WRITE - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - vsc_req_form[134] = (data >> 0) & 0xFF - vsc_req_form[135] = (data >> 8) & 0xFF - vsc_req_form[136] = (data >> 16) & 0xFF - vsc_req_form[137] = (data >> 24) & 0xFF - - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('tcm read addr[%04X] data[%04X] error[%04X]' % (addr, data, status)) - return False - - return True - - def tcm_read_atomic(self, addr): - """ - This API sends the tcm read command to the serdes chip via VSC cmd - - Args: - addr: - an Integer, address of tcm space - Returns: - an Integer, return data of tcm address - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_TCM_READ - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('tcm read addr[%04X] error[%04X]' % (addr, status)) - return -1 - - data = (self.read_mmap(YCable.MIS_PAGE_VSC, 134) | (self.read_mmap(YCable.MIS_PAGE_VSC, 135) << 8) | - (self.read_mmap(YCable.MIS_PAGE_VSC, 136) << 16) | (self.read_mmap(YCable.MIS_PAGE_VSC, 137) << 24)) - else: - self.log_error('acquire lock timeout, failed to read serdes tcm register') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to read serdes tcm register") - return YCable.EEPROM_ERROR - - return data - - def tcm_write_atomic(self, addr, data): - """ - This API sends the tcm write command to the serdes chip via VSC cmd - - Args: - addr: - an Integer, address of tcm space - - data: - an Integer, value to be written to the address - - Returns: - a boolean, True if the tcm write succeeded and False if it did not succeed. - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_TCM_WRITE - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - vsc_req_form[134] = (data >> 0) & 0xFF - vsc_req_form[135] = (data >> 8) & 0xFF - vsc_req_form[136] = (data >> 16) & 0xFF - vsc_req_form[137] = (data >> 24) & 0xFF - - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('tcm read addr[%04X] data[%04X] error[%04X]' % (addr, data, status)) - return False - else: - self.log_error('acquire lock timeout, failed to write serdes tcm register') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to write serdes tcm register") - return YCable.EEPROM_ERROR - - return True - - def reg_read(self, addr): - """ - This API reads the serdes register via vsc - - Args: - addr: - an Integer, address of the serdes register - Returns: - an Integer, return data of the register - """ - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_REG_READ - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('reg read addr[%04X] error[%04X]' % (addr, status)) - return -1 - - return self.read_mmap(YCable.MIS_PAGE_VSC, 134) | (self.read_mmap(YCable.MIS_PAGE_VSC, 135) << 8) - - def reg_write(self, addr, data): - """ - This API writes the serdes register via vsc - - Args: - addr: - an Integer, address of the serdes register - - data: - an Integer, value to be written to the register address - - Returns: - a boolean, True if the register write succeeded and False if it did not succeed. - """ - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_REG_WRITE - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[134] = (data >> 0) & 0xFF - vsc_req_form[135] = (data >> 8) & 0xFF - - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('reg write addr[%04X] data[%04X] error[%04X]' % (addr, data, status)) - return False - - return True - - def reg_read_atomic(self, addr): - """ - This API reads the serdes register in atomic method - - Args: - addr: - an Integer, address of the serdes register - Returns: - an Integer, return data of the register - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_REG_READ - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('reg read addr[%04X] error[%04X]' % (addr, status)) - return YCable.EEPROM_ERROR - - return self.read_mmap(YCable.MIS_PAGE_VSC, 134) | (self.read_mmap(YCable.MIS_PAGE_VSC, 135) << 8) - else: - self.log_error('acquire lock timeout, failed to read serdes register') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to read serdes register") - return YCable.EEPROM_ERROR - - def reg_write_atomic(self, addr, data): - """ - This API writes the serdes register in atomic method - - Args: - addr: - an Integer, address of the serdes register - - data: - an Integer, value to be written to the register address - - Returns: - an Integer, 0 if the register write succeeded. - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_REG_WRITE - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[134] = (data >> 0) & 0xFF - vsc_req_form[135] = (data >> 8) & 0xFF - - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('reg write addr[%04X] data[%04X] error[%04X]' % (addr, data, status)) - return YCable.EEPROM_ERROR - else: - self.log_error('acquire lock timeout, failed to write serdes register') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to write serdes register") - return YCable.EEPROM_ERROR - - return 0 - - def toggle_mux_to_tor_a(self): - """ - This API does a hard switch toggle of the Y cable's MUX regardless of link state to - TOR A on the port this is called for. This means if the Y cable is actively sending traffic, - the "get_active_linked_tor_side" API will now return Tor A. - It also implies that if the link is actively sending traffic on this port, - Y cable MUX will start forwarding packets from TOR A to NIC, and drop packets from TOR B to NIC - regardless of previous forwarding state. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a Boolean, True if the toggle succeeded and False if it did not succeed. - """ - - buffer = bytearray([2]) - curr_offset = YCable.OFFSET_SWITCH_MUX_DIRECTION - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to toggle mux to TOR A') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") - return YCable.EEPROM_ERROR - - return result - - def toggle_mux_to_tor_b(self): - """ - This API does a hard switch toggle of the Y cable's MUX regardless of link state to - TOR B. This means if the Y cable is actively sending traffic, the "get_active_linked_tor_side" - API will now return Tor B. It also implies that if the link is actively sending traffic on this port, - Y cable. MUX will start forwarding packets from TOR B to NIC, and drop packets from TOR A to NIC - regardless of previous forwarding state. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a Boolean, True if the toggle succeeded and False if it did not succeed. - """ - buffer = bytearray([3]) - curr_offset = YCable.OFFSET_SWITCH_MUX_DIRECTION - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to toggle mux to TOR B') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") - return YCable.EEPROM_ERROR - - return result - - def get_read_side(self): - """ - This API checks which side of the Y cable the reads are actually getting performed - from, either TOR A or TOR B or NIC and returns the value. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if reading the Y cable from TOR A side. - TARGET_TOR_B, if reading the Y cable from TOR B side. - TARGET_NIC, if reading the Y cable from NIC side. - TARGET_UNKNOWN, if reading the Y cable API fails. - """ - - curr_offset = YCable.OFFSET_DETERMINE_CABLE_READ_SIDE - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log_error('acquire lock timeout, failed to check read side') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to check read side") - return YCable.EEPROM_ERROR - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - self.log_error("Error: for checking mux_cable read side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error("Error: for checking mux_cable read_side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error( - "Error: for checking mux_cable read_side, eeprom read returned a None value for port {} which is not expected".format(self.port)) - return YCableBase.TARGET_UNKNOWN - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0] >> 2) & 0x01): - self.log_info("Reading from TOR A") - return YCableBase.TARGET_TOR_A - elif ((regval_read[0] >> 1) & 0x01): - self.log_info("Reading from TOR B") - return YCableBase.TARGET_TOR_B - elif (regval_read[0] & 0x01): - self.log_info("Reading from NIC side") - return YCableBase.TARGET_NIC - else: - self.log_error("Error: Credo Y Cable unable to get the read side, Cable not plugged/Faulty Cable register value = {} ".format(result)) - - return YCableBase.TARGET_UNKNOWN - - def get_mux_direction(self): - """ - This API checks which side of the Y cable mux is currently point to - and returns either TOR A or TOR B. Note that this API should return mux-direction - regardless of whether the link is active and sending traffic or not. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if mux is pointing to TOR A side. - TARGET_TOR_B, if mux is pointing to TOR B side. - TARGET_UNKNOWN, if mux direction API fails. - """ - - curr_offset = YCable.OFFSET_MUX_DIRECTION - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log_error('acquire lock timeout, failed to get mux direction') - return YCable.EEPROM_ERROR - else: - self.log_error( - "platform_chassis is not loaded, failed to get mux direction") - return YCable.EEPROM_ERROR - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - self.log_error("Error: for checking mux_cable mux pointing side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error("Error: for checking mux_cable mux pointing side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error( - "Error: for checking mux_cable mux pointing side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(self.port)) - return YCableBase.TARGET_UNKNOWN - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0]) & 0x01): - self.log_info("mux pointing to TOR A") - return YCableBase.TARGET_TOR_A - elif regval_read[0] == 0: - self.log_info("mux pointing to TOR B") - return YCableBase.TARGET_TOR_B - - self.log_error("Error: Credo Y Cable unable to check the status mux direction, cable powered off/Faulty Cable register value = {}".format(result)) - return YCableBase.TARGET_UNKNOWN - - def get_active_linked_tor_side(self): - """ - This API checks which side of the Y cable is actively linked and sending traffic - and returns either TOR A or TOR B. - The port on which this API is called for can be referred using self.port. - This is different from get_mux_direction in a sense it also implies the link on the side - where mux is pointing to must be active and sending traffic, whereas get_mux_direction - just tells where the mux is pointing to. - - Args: - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if TOR A is actively linked and sending traffic. - TARGET_TOR_B, if TOR B is actively linked and sending traffic. - TARGET_UNKNOWN, if checking which side is linked and sending traffic API fails. - """ - - - curr_offset = YCable.OFFSET_ACTIVE_TOR_INDICATOR - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log_error('acquire lock timeout, failed to check Active Linked and routing TOR side') - return YCable.EEPROM_ERROR - else: - self.log_error( - "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") - return YCable.EEPROM_ERROR - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - self.log_error("Error: for checking mux_cable active linked side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error("Error: for checking mux_cable active linked side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error( - "Error: for checking mux_cable active linked side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(self.port)) - return YCableBase.TARGET_UNKNOWN - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0] >> 1) & 0x01): - self.log_info("TOR B active linked and actively routing") - return YCableBase.TARGET_TOR_B - elif ((regval_read[0]) & 0x01): - self.log_info("TOR A standby linked and actively routing") - return YCableBase.TARGET_TOR_A - elif regval_read[0] == 0: - self.log_info("Nothing linked for routing") - return YCableBase.TARGET_NIC - - self.log_error("Error: Credo Y Cable unable to get active linked ToR side Cable powered off/Faulty Cable register value = {} ".format(result)) - return YCableBase.TARGET_UNKNOWN - - def is_link_active(self, target): - """ - This API checks if NIC, TOR_A and TOR_B of the Y cable's link is active. - The target specifies which link is supposed to be checked - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if the link is active - , False if the link is not active - """ - - - curr_offset = YCable.OFFSET_CHECK_LINK_ACTIVE - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log_error('acquire lock timeout, failed to check if link is Active on target side') - return YCable.EEPROM_ERROR - else: - self.log_error( - "platform_chassis is not loaded, failed to check if link is Active on target side") - return YCable.EEPROM_ERROR - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - self.log_error("Error: for checking mux_cable link is active on target side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error("Error: for checking mux_cable link is active on target side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), self.port)) - return YCableBase.TARGET_UNKNOWN - else: - self.log_error( - "Error: for checking mux_cable link is active on target side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(self.port)) - return YCable.EEPROM_ERROR - - regval_read = struct.unpack(">B", result) - - if target == YCableBase.TARGET_NIC: - if (regval_read[0] & 0x01): - self.log_info("NIC link is up") - return True - else: - return False - elif target == YCableBase.TARGET_TOR_A: - if ((regval_read[0] >> 2) & 0x01): - self.log_info("TOR A link is up") - return True - else: - return False - elif target == YCableBase.TARGET_TOR_B: - if ((regval_read[0] >> 1) & 0x01): - self.log_info("TOR B link is up") - return True - else: - return False - else: - return YCableBase.TARGET_UNKNOWN - - def get_eye_heights(self, target): - """ - This API returns the EYE height value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to get the eye: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with EYE values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - - eye_result = [] - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - - buffer = bytearray([0]) - curr_offset = YCable.OFFSET_INITIATE_EYE_MEASUREMENT - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - - time_start = time.time() - while(True): - done = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - time_now = time.time() - time_diff = time_now - time_start - if done[0] == 1: - break - elif time_diff >= YCable.EYE_TIMEOUT_SECS: - return YCable.EEPROM_TIMEOUT_ERROR - - idx = 0 - for lane in range(YCable.MAX_NUM_LANES): - curr_offset = YCable.OFFSET_LANE_1_EYE_RESULT - msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + idx, 1) - lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + idx + 1, 1) - - lane_result = (msb_result[0] << 8 | lsb_result[0]) - eye_result.append(lane_result) - idx += 2 - else: - self.log_error('acquire lock timeout, failed to get eye height') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get eye height") - return YCable.EEPROM_ERROR - - return eye_result - - def get_vendor(self): - """ - This API returns the vendor name of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with vendor name - """ - - curr_offset = YCable.OFFSET_VENDOR_NAME - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) - else: - self.log_error('acquire lock timeout, failed to get vendor name') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get Vendor name") - return YCable.EEPROM_ERROR - - vendor_name = str(result.decode()) - - return vendor_name - - def get_part_number(self): - """ - This API returns the part number of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with part number - """ - curr_offset = YCable.OFFSET_PART_NUMBER - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) - else: - self.log_error('acquire lock timeout, failed to get part number') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get part number") - return YCable.EEPROM_ERROR - - part_number = str(part_result.decode()) - - return part_number - - def get_serial_number(self): - """ - This API returns the serial number of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with serial number - """ - curr_offset = YCable.OFFSET_SERIAL_NUMBER - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) - else: - self.log_error('acquire lock timeout, failed to get serial number') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get serial number") - return YCable.EEPROM_ERROR - - part_number = str(part_result.decode()) - - return part_number - - def get_switch_count_total(self, switch_count_type, clear_on_read=False): - """ - This API returns the total switch count to change the Active TOR which has - been done manually/automatic by the user. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times the Y-cable has been switched - """ - - - count = 0 - - if self.platform_chassis is not None: - if switch_count_type == YCableBase.SWITCH_COUNT_MANUAL: - count = self.get_switch_count_tor_a(clear_on_read) + self.get_switch_count_tor_b(clear_on_read) - elif switch_count_type == YCableBase.SWITCH_COUNT_AUTO: - curr_offset = YCable.OFFSET_AUTO_SWITCH_COUNT - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - msb_result_1 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 1, 1) - msb_result_2 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 2, 1) - lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 3, 1) - count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) - else: - self.log_error('acquire lock timeout, failed to get switch count') - return YCable.EEPROM_ERROR - else: - self.log_error("not a valid switch_count_type, failed to get switch count") - return YCable.EEPROM_ERROR - - if clear_on_read: - if switch_count_type == YCableBase.SWITCH_COUNT_AUTO: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - curr_offset = YCable.OFFSET_AUTO_SWITCH_COUNT - buffer = bytearray([6]) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return YCable.EEPROM_ERROR - else: - self.log_error('acquire lock timeout, failed to clear switch count') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get switch count") - return YCable.EEPROM_ERROR - - return count - - def get_switch_count_tor_a(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR A - This is essentially all the successful switches initiated from ToR A. Toggles which were - initiated to toggle from ToR A and did not succeed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR A - """ - - curr_offset = YCable.OFFSET_MANUAL_SWITCH_COUNT_TOR_A - count = 0 - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - msb_result_1 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 1, 1) - msb_result_2 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 2, 1) - lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+3, 1) - count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) - - if clear_on_read: - buffer = bytearray([4]) - curr_offset = YCable.OFFSET_CLEAR_SWITCH_COUNT - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return YCable.EEPROM_ERROR - else: - self.log_error('acquire lock timeout, failed to get switch count (tor A)') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get manual switch count") - return YCable.EEPROM_ERROR - - return count - - def get_switch_count_tor_b(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR B - This is essentially all the successful switches initiated from ToR B. Toggles which were - initiated to toggle from ToR B and did not succeed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR B - """ - - curr_offset = YCable.OFFSET_MANUAL_SWITCH_COUNT_TOR_B - count = 0 - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - msb_result_1 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 1, 1) - msb_result_2 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 2, 1) - lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+3, 1) - count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) - - if clear_on_read: - buffer = bytearray([5]) - curr_offset = YCable.OFFSET_CLEAR_SWITCH_COUNT - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return YCable.EEPROM_ERROR - else: - self.log_error('acquire lock timeout, failed to get switch count (tor B)') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get manual switch count") - return YCable.EEPROM_ERROR - - return count - - def get_switch_count_target(self, switch_count_type, target, clear_on_read=False): - """ - This API returns the total number of times the Active TOR has - been done manually/automaticlly toggled towards a target. - For example, TARGET_TOR_A as target would imply - how many times the mux has been toggled towards TOR A. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times manually the Y-cable has been switched - """ - - curr_offset = YCable.OFFSET_EXTEND_SWITCH_COUNT_TYPE - - if switch_count_type == YCableBase.SWITCH_COUNT_MANUAL: - if target == YCableBase.TARGET_TOR_A: - buffer = bytearray([0]) - elif target == YCableBase.TARGET_TOR_B: - buffer = bytearray([1]) - else: - self.log_error("not a valid target") - return YCable.EEPROM_ERROR - elif switch_count_type == YCableBase.SWITCH_COUNT_AUTO: - if target == YCableBase.TARGET_TOR_A: - buffer = bytearray([2]) - elif target == YCableBase.TARGET_TOR_B: - buffer = bytearray([3]) - else: - self.log_error("not a valid target") - return YCable.EEPROM_ERROR - else: - self.log_error("not a valid switch_count_type, failed to get switch count") - return YCable.EEPROM_ERROR - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return YCable.EEPROM_ERROR - time_start = time.time() - while(True): - done = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - time_now = time.time() - time_diff = time_now - time_start - if done[0] & 0x80: - break - elif time_diff >= YCable.EXTEND_SWITCH_CNT_TIMEOUT_SECS: - return YCable.EEPROM_TIMEOUT_ERROR - - curr_offset = YCable.OFFSET_EXTEND_SWITCH_COUNT - msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 3, 1) - msb_result_1 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 2, 1) - msb_result_2 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 1, 1) - lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) - - if clear_on_read: - curr_offset = YCable.OFFSET_CLEAR_SWITCH_COUNT - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return YCable.EEPROM_ERROR - else: - self.log_error('acquire lock timeout, failed to get switch count target') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get switch count target") - return YCable.EEPROM_ERROR - - return count - - def get_target_cursor_values(self, lane, target): - """ - This API returns the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two, main, post one, post two, post three cursor values - If any of the value is not available please return None for that filter - The port on which this API is called for can be referred using self.port. - - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a list, with pre one, pre two, main, post one, post two, post three cursor values in the order - """ - curr_offset = YCable.OFFSET_NIC_CURSOR_VALUES - - result = [] - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - pre1 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5, 1) - result.append(c_int8(pre1[0]).value) - pre2 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 1, 1) - result.append(c_int8(pre2[0]).value) - main = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 2, 1) - result.append(c_int8(main[0]).value) - post1 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 3, 1) - result.append(c_int8(post1[0]).value) - post2 = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 4, 1) - result.append(c_int8(post2[0]).value) - else: - self.log_error('acquire lock timeout, failed to get target cursor values') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get target cursor values") - return YCable.EEPROM_ERROR - - return result - - def set_target_cursor_values(self, lane, cursor_values, target): - """ - This API sets the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two, main, post one, post two etc. cursor values - The port on which this API is called for can be referred using self.port. - - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - cursor_values: - a list, with pre one, pre two, main, post one, post two cursor, post three etc. values in the order - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if cursor values setting is successful - , False if cursor values setting is not successful - """ - curr_offset = YCable.OFFSET_NIC_CURSOR_VALUES - idx = 0 - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - for data in cursor_values: - data = data & 0xFF - buffer = bytearray([data]) - self.platform_chassis.get_sfp(self.port).write_eeprom( - curr_offset + (target)*20 + (lane-1)*5 + idx, 1, buffer) - idx += 1 - else: - self.log_error('acquire lock timeout, failed to set target cursor values') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get target cursor values") - return YCable.EEPROM_ERROR - - return True - - def get_firmware_version(self, target): - """ - This routine should return the active, inactive and next (committed) - firmware running on the target. Each of the version values in this context - could be a string with a major and minor number and a build value. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the firmware version on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a Dictionary: - with version_active, version_inactive and version_next keys - and their corresponding values - - """ - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_GET_INFO - status = self.send_vsc(vsc_req_form) - - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Get firmware version error (error code:0x%04X)' % (status)) - return None - - data = bytearray(YCable.FIRMWARE_INFO_PAYLOAD_SIZE) - for byte_idx in range(0, YCable.FIRMWARE_INFO_PAYLOAD_SIZE): - curr_offset = 0xfc * 128 + 128 + byte_idx - read_out = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - data[byte_idx] = read_out[0] - else: - self.log_error('acquire lock timeout, failed to get firmware version') - return None - else: - self.log_error("platform_chassis is not loaded, failed to get firmware version") - return None - - result = {} - NUM_MCU_SIDE = 3 - - base_addr = int(target * (YCable.FIRMWARE_INFO_PAYLOAD_SIZE / NUM_MCU_SIDE)) - rev_major_slot1 = struct.unpack_from('B', fwImage[5 : 6])[0] - mcu_pid = self.read_mmap(0xFB, 187) - - if bin_pid != mcu_pid: - self.log_error('Firmware binary ID Mismatched Bin[%d] MCU[%d]' % (bin_pid, mcu_pid)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS - - ''' - Firmware update start - ''' - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_START - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Firmware binary start transfer error (error code:%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - else: - self.log_error('acquire lock timeout, failed to start firmware update') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - - ''' - Transfer firmware image to local side MCU - ''' - total_chunk = len(fwImage) // YCable.VSC_BUFF_SIZE - chunk_idx = 0 - retry_count = 0 - while chunk_idx < total_chunk: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - checksum = 0 - fw_img_offset = chunk_idx * YCable.VSC_BUFF_SIZE - for byte_offset in range(YCable.VSC_BUFF_SIZE): - checksum += fwImage[fw_img_offset] - fw_img_offset += 1 - if (((byte_offset + 1) % YCable.VSC_BLOCK_WRITE_LENGTH) == 0): - page = YCable.MIS_PAGE_FC + byte_offset // 128 - byte = 128 + ((byte_offset + 1) - YCable.VSC_BLOCK_WRITE_LENGTH) % 128 - self.write_mmap(page, byte, bytearray( - fwImage[fw_img_offset - YCable.VSC_BLOCK_WRITE_LENGTH: fw_img_offset]), YCable.VSC_BLOCK_WRITE_LENGTH) - - fw_img_offset = chunk_idx * YCable.VSC_BUFF_SIZE - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_LOCAL_XFER - vsc_req_form[YCable.VSC_BYTE_ADDR0] = (fw_img_offset >> 0) & 0xFF - vsc_req_form[YCable.VSC_BYTE_ADDR1] = (fw_img_offset >> 8) & 0xFF - vsc_req_form[YCable.VSC_BYTE_ADDR2] = (fw_img_offset >> 16) & 0xFF - vsc_req_form[YCable.VSC_BYTE_ADDR3] = (fw_img_offset >> 24) & 0xFF - vsc_req_form[YCable.VSC_BYTE_CHKSUM_MSB] = (checksum >> 8) & 0xFF - vsc_req_form[YCable.VSC_BYTE_CHKSUM_LSB] = (checksum >> 0) & 0xFF - status = self.send_vsc(vsc_req_form) - - if status == YCable.MCU_EC_NO_ERROR: - chunk_idx += 1 - retry_count = 0 - else: - self.log_error('Firmware binary transfer error (error code:%04X)' % (status)) - - if retry_count == 3: - self.log_error('Retry Xfer Fw Bin Error, abort firmware update') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - retry_count += 1 - else: - self.log_error('acquire lock timeout, failed to xfer firmware') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - - ''' - Complete the local side firmware transferring - ''' - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_LOCAL_XFER_COMPLETE - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Veriyf firmware binary error (error code:0x%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - else: - self.log_error('acquire lock timeout, failed to complete firmware xfer') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - - ''' - transfer firmware image from local side MCU to the other two via UART - ''' - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_UART_XFER - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Firmware binary UART transfer error (error code:0x%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - else: - self.log_error('acquire lock timeout, failed to uart xfer') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - - uartXferStartTime = time.time() - while True: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_UART_XFER_STATUS - status = self.send_vsc(vsc_req_form) - - busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) - self.read_mmap(YCable.MIS_PAGE_FC, 129) - self.read_mmap(YCable.MIS_PAGE_FC, 130) - self.read_mmap(YCable.MIS_PAGE_FC, 131) - - if busy == 0: - break - - if (time.time() - uartXferStartTime) > YCable.FWUPD_UART_XFER_TIMEOUT_SECS: - self.log_error( - 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - - time.sleep(1) - else: - self.log_error('acquire lock timeout, failed to get uart xfer status') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - else: - self.log_error("platform_chassis is not loaded, failed to download firmware") - return YCable.EEPROM_ERROR - - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED - - return YCableBase.FIRMWARE_DOWNLOAD_SUCCESS - - def activate_firmware(self, fwfile=None, hitless=False): - """ - This routine should activate the downloaded firmware on all the - components of the Y cable of the port for which this API is called.. - This API is meant to be used in conjunction with download_firmware API, and - should be called once download_firmware API is successful. - This means that the firmware which has been downloaded should be - activated (start being utilized by the cable) once this API is - successfully executed. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in activate_firmware, the API should - have the logic to retrieve the firmware version from this file - which has to be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should activate whatever - firmware is marked to be activated next. - If provided, it should retrieve the firmware version(s) from this file, ensure - they are downloaded on the cable, then activate them. - - hitless (optional): - a boolean, True, Hitless upgrade: it will backup/restore the current state - (ex. variables of link status, API attributes...etc.) before - and after firmware upgrade. - a boolean, False, Non-hitless upgrade: it will update the firmware regardless - the current status, a link flip can be observed during the upgrade. - Returns: - One of the following predefined constants: - FIRMWARE_ACTIVATE_SUCCESS - FIRMWARE_ACTIVATE_FAILURE - """ - if self.platform_chassis is not None: - if fwfile is None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS - side_bitmap = YCable.SIDE_BMP_ALL - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_COMMIT - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = side_bitmap - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Firmware commit error (error code:%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_RUN - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = side_bitmap - vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless - status = self.send_vsc(vsc_req_form) - time.sleep(5) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Firmware run error (error code:%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED - else: - self.log_error('acquire lock timeout, failed to activate firmware') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - else: - try: - inFile = open(fwfile, 'rb') - fwImage = bytearray(inFile.read()) - inFile.close() - except Exception as e: - self.log_error('activate_firmware, open fw bin error(%s), fwfile:%s' % (e, fwfile)) - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - - build_msb = struct.unpack_from(' NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in activate_firmware, the API should - have the logic to retrieve the firmware version from this file - which has to be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should activate whatever - firmware is marked to be activated next. - If provided, it should retrieve the firmware version(s) from this file, ensure - they are downloaded on the cable, then activate them. - hitless (optional): - a boolean, True, Hitless upgrade: it will backup/restore the current state - (ex. variables of link status, API attributes...etc.) before - and after firmware upgrade. - a boolean, False, Non-hitless upgrade: it will update the firmware regardless - the current status, a link flip can be observed during the upgrade. - Returns: - One of the following predefined constants: - FIRMWARE_ACTIVATE_SUCCESS - FIRMWARE_ACTIVATE_FAILURE - """ - if self.platform_chassis is not None: - - if target == YCableBase.TARGET_NIC: - act_bmp = YCable.SIDE_BMP_NIC - elif target == YCableBase.TARGET_TOR_A: - act_bmp = YCable.SIDE_BMP_TOR_A - elif target == YCableBase.TARGET_TOR_B: - act_bmp = YCable.SIDE_BMP_TOR_B - else: - act_bmp = YCable.SIDE_BMP_ALL - - if fwfile is None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_COMMIT - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = act_bmp - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Firmware commit error (error code:%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_RUN - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = act_bmp - vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless - status = self.send_vsc(vsc_req_form) - time.sleep(5) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Firmware run error (error code:%04X)' % (status)) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED - else: - self.log_error('acquire lock timeout, failed to activate target firmware') - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - else: - try: - inFile = open(fwfile, 'rb') - fwImage = bytearray(inFile.read()) - inFile.close() - except Exception as e: - self.log_error('activate_target_firmware, open fw bin error(%s), fwfile:%s' % (e, fwfile)) - return YCableBase.FIRMWARE_ACTIVATE_FAILURE - - build_msb = struct.unpack_from(' NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if the cable is target reset - , False if the cable target is not reset - """ - - ''' - use firmare_run cmd to emulate module reset - ''' - if self.platform_chassis is not None: - if target != YCableBase.TARGET_NIC and target != YCableBase.TARGET_TOR_A and target != YCableBase.TARGET_TOR_B: - self.log_error("reset: unsupported target") - return False - - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_RUN - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD - vsc_req_form[YCable.VSC_BYTE_ADDR0] = (1 << target) - vsc_req_form[YCable.VSC_BYTE_ADDR1] = 0 - status = self.send_vsc(vsc_req_form) - - if status != YCable.MCU_EC_NO_ERROR: - self.log_error("unable to reset the module") - return False - - if target == YCableBase.TARGET_NIC: - time.sleep(4) - else: - time.sleep(2) - else: - self.log_error('acquire lock timeout, failed to reset') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to reset") - return YCable.EEPROM_ERROR - - return True - - def create_port(self, speed, fec_mode_tor = YCableBase.FEC_MODE_NONE, fec_mode_nic = YCableBase.FEC_MODE_NONE, anlt_tor = False, anlt_nic = False): - """ - This API sets the mode of the cable/port for corresponding lane/FEC etc. configuration as specified. - The speed specifies which mode is supposed to be set 50G, 100G etc - the AN/LT specifies if auto-negotiation + link training (AN/LT) has to be enabled - Note that in case create_port is called multiple times, the most recent api call will take the precedence - on either of TOR side. - The port on which this API is called for can be referred using self.port. - - Args: - speed: - an Integer, the value for the link speed to be configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - - fec_mode_tor: - One of the following predefined constants, the actual FEC mode for the ToR to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - - fec_mode_nic: - One of the following predefined constants, the actual FEC mode for the nic to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - - anlt_tor: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on ToR's - , False if auto-negotiation + link training (AN/LT) is not to be enabled on ToR's - - anlt_nic: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on nic - , False if auto-negotiation + link training (AN/LT) is not to be enabled on nic - - - Returns: - a boolean, True if the port is configured - , False if the port is not configured - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - mode = 0 - if speed == 50000: - mode |= (0 << 6) - elif speed == 100000: - mode |= (1 << 6) - else: - self.log_error("create port: unsupported speed:%d" % (speed)) - return False - - mode |= (1 << 0) if anlt_nic else (0 << 0) - mode |= (1 << 1) if anlt_tor else (0 << 1) - mode |= (1 << 3) if fec_mode_nic == YCableBase.FEC_MODE_RS else (0 << 3) - mode |= (1 << 4) if fec_mode_tor == YCableBase.FEC_MODE_RS else (0 << 4) - - curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION - buffer = bytearray([mode]) - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - else: - self.log_error('acquire lock timeout, failed to create port') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to create port") - return YCable.EEPROM_ERROR - - return True - - def get_speed(self): - """ - This API gets the mode of the cable for corresponding lane configuration. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - speed: - an Integer, the value for the link speed is configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - """ - - speed = 0 - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION - mode = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - - if (mode[0] >> 6) == 0: - speed = 50000 - elif (mode[0] >> 6) == 1: - speed = 100000 - else: - self.log_error("unsupported speed") - return -1 - else: - self.log_error('acquire lock timeout, failed to get speed') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get speed") - return YCable.EEPROM_ERROR - - return speed - - def set_fec_mode(self, fec_mode, target): - """ - This API gets the FEC mode of the cable for which it is set to. - The port on which this API is called for can be referred using self.port. - - Args: - fec_mode: - One of the following predefined constants, the actual FEC mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - target: - One of the following predefined constants, the actual target to set the FEC mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - - Returns: - a boolean, True if the FEC mode is configured - , False if the FEC mode is not configured - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION - mode = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - - if target == YCableBase.TARGET_NIC: - mode[0] &= ~(1 << 3) - mode[0] |= (1 << 3) if fec_mode == YCableBase.FEC_MODE_RS else (0 << 3) - elif target == YCableBase.TARGET_TOR_A or target == YCableBase.TARGET_TOR_B: - mode[0] &= ~(1 << 4) - mode[0] |= (1 << 4) if fec_mode == YCableBase.FEC_MODE_RS else (0 << 4) - else: - self.log_error("set fec mode: unsupported target") - return False - - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, mode) - if result is False: - return result - else: - self.log_error('acquire lock timeout, failed to set fec mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to set fec mode") - return YCable.EEPROM_ERROR - - return True - - def get_fec_mode(self, target): - """ - This API gets the FEC mode of the cable which it is set to. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to FEC mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - fec_mode: - One of the following predefined constants, the actual FEC mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - """ - - fec_mode = YCableBase.FEC_MODE_NONE - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION - mode = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - - if target == YCableBase.TARGET_NIC: - if mode[0] & (1 << 3): - fec_mode = YCableBase.FEC_MODE_RS - elif target == YCableBase.TARGET_TOR_A or target == YCableBase.TARGET_TOR_B: - if mode[0] & (1 << 4): - fec_mode = YCableBase.FEC_MODE_RS - else: - self.log_error("get fec mode: unsupported target") - else: - self.log_error('acquire lock timeout, failed to get fec mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get fec mode") - return YCable.EEPROM_ERROR - - return fec_mode - - def set_anlt(self, enable, target): - """ - This API enables/disables the cable auto-negotiation + link training (AN/LT). - The port on which this API is called for can be referred using self.port. - - Args: - enable: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled - , False if auto-negotiation + link training (AN/LT) is not to be enabled - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - - Returns: - a boolean, True if the auto-negotiation + link training (AN/LT) enable/disable specified is configured - , False if the auto-negotiation + link training (AN/LT) enable/disable specified is not configured - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION - mode = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - - if target == YCableBase.TARGET_NIC: - mode[0] &= ~(1 << 0) - mode[0] |= (1 << 0) if enable else (0 << 0) - elif target == YCableBase.TARGET_TOR_A or target == YCableBase.TARGET_TOR_B: - mode[0] &= ~(1 << 1) - mode[0] |= (1 << 1) if enable else (0 << 1) - else: - self.log_error("set anlt: unsupported target") - return False - - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, mode) - if result is False: - return result - else: - self.log_error('acquire lock timeout, failed to set anlt') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to set anlt") - return YCable.EEPROM_ERROR - - return True - - def get_anlt(self, target): - """ - This API gets the auto-negotiation + link training (AN/LT) mode of the cable for corresponding port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the AN/LT on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if auto-negotiation + link training (AN/LT) is enabled - , False if auto-negotiation + link training (AN/LT) is not enabled - """ - - anlt_mode = False - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION - mode = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - - if target == YCableBase.TARGET_NIC: - if mode[0] & (1 << 0): - anlt_mode = True - - elif target == YCableBase.TARGET_TOR_A or target == YCableBase.TARGET_TOR_B: - if mode[0] & (1 << 1): - anlt_mode = True - else: - self.log_error("get anlt: unsupported target") - else: - self.log_error('acquire lock timeout, failed to get anlt') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get anlt") - return YCable.EEPROM_ERROR - - return anlt_mode - - def get_event_log(self, clear_on_read=False): - """ - This API returns the event log of the cable - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the log has to be cleared after read - , False if the log is not to be cleared after read - - Returns: - list: - a list of strings which correspond to the event logs of the cable - """ - - result = [] - - if self.platform_chassis is not None: - if (clear_on_read): - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_EVENTLOG - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.EVENTLOG_OPTION_CLEAR - status = self.send_vsc(vsc_req_form) - - if status != YCable.MCU_EC_NO_ERROR: - self.log_error("clear event log error(error code:%04X)" % (status)) - return YCable.EEPROM_ERROR - else: - self.log_error("acquire lock timeout, failed to clear event log") - return YCable.EEPROM_ERROR - - last_read_id = -1 - - event_type_str = { - 0x0000: 'EventLog Header', - 0x0001: 'Auto Switch', - 0x0002: 'Manual Switch', - 0x0003: 'BER Measurement', - 0x0004: 'PRBS Generation', - 0x0005: 'Loopback Mode', - 0x0006: 'Eye Measurement', - 0x0007: 'Epoch Time', - 0x0008: 'Temperature', - 0x0009: 'Voltage', - 0x0100: 'Link Down', - 0x0200: 'Firmware Update', - } - - read_cycle = 0 - while (True): - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_EVENTLOG - vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.EVENTLOG_OPTION_DUMP - vsc_req_form[YCable.VSC_BYTE_ADDR0] = (last_read_id >> 0) & 0xFF - vsc_req_form[YCable.VSC_BYTE_ADDR1] = (last_read_id >> 8) & 0xFF - vsc_req_form[YCable.VSC_BYTE_ADDR2] = (last_read_id >> 16) & 0xFF - vsc_req_form[YCable.VSC_BYTE_ADDR3] = (last_read_id >> 24) & 0xFF - status = self.send_vsc(vsc_req_form) - - if status == YCable.MCU_EC_NO_ERROR: - fetch_cnt = self.read_mmap(YCable.MIS_PAGE_VSC, 134) - if (fetch_cnt == 0): - break - else: - self.log_error("download event log error(error code:%04X)" % (status)) - return YCable.EEPROM_ERROR - - event_data = bytearray(YCable.EVENTLOG_PAYLOAD_SIZE * fetch_cnt) - - for byte_offset in range(0, YCable.EVENTLOG_PAYLOAD_SIZE * fetch_cnt): - byte_data = self.read_mmap(YCable.MIS_PAGE_FC, 128 + byte_offset) - event_data[byte_offset] = byte_data - - for curr_idx in range(0, fetch_cnt): - byte_offset = curr_idx * YCable.EVENTLOG_PAYLOAD_SIZE - event_id = struct.unpack_from(' 150: - break - else: - self.log_error('acquire lock timeout, failed to get event log') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get event log") - return YCable.EEPROM_ERROR - - return result - - def get_pcs_stats(self, target): - """ - This API returns the pcs statistics of the cable - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - pcs_stats = {} - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - quad = 0 - ch = 0 - if target == YCableBase.TARGET_NIC: - quad = 0 - elif target == YCableBase.TARGET_TOR_A: - quad = 4 - elif target == YCableBase.TARGET_TOR_B: - quad = 6 - else: - self.log_error("get pcs stats: unsupported target") - return pcs_stats - - base = (quad << 20) + 0xa0000 - Rx = (ch * 35) + 0x40 - pcs_stats['Rx Frames OK'] = self.tcm_read(base + 4 * (Rx + 6)) - pcs_stats['Rx Chk SEQ Errs'] = self.tcm_read(base + 4 * (Rx + 7)) - pcs_stats['Rx Alignment Errs'] = self.tcm_read(base + 4 * (Rx + 2)) - pcs_stats['Rx In Errs'] = self.tcm_read(base + 4 * (Rx + 9)) - pcs_stats['Rx FrameTooLong Errs'] = self.tcm_read(base + 4 * (Rx + 4)) - pcs_stats['Rx Octets OK'] = self.tcm_read(base + 4 * (Rx + 1)) - - Tx = (ch * 26) + 0xC - pcs_stats['Tx Frames OK'] = self.tcm_read(base + 4 * (Tx + 3)) - pcs_stats['Tx Out Errs'] = self.tcm_read(base + 4 * (Tx + 5)) - pcs_stats['Tx Octets OK'] = self.tcm_read(base + 4 * (Tx + 1)) - else: - self.log_error('acquire lock timeout, failed to get pcs statisics') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get pcs statisics") - return YCable.EEPROM_ERROR - - return pcs_stats - - def get_fec_stats(self, target): - """ - This API returns the FEC statistics of the cable - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - fec_stats = {} - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - quad = 0 - ch = 0 - if target == YCableBase.TARGET_NIC: - quad = 0 - elif target == YCableBase.TARGET_TOR_A: - quad = 4 - elif target == YCableBase.TARGET_TOR_B: - quad = 6 - else: - self.log_error("get fec stats: unsupported target") - return fec_stats - - base = (quad << 20) + 0xA2800 - - self.tcm_write(base + (3 << 2), 0x10000000 | (1 << ch)) - - lsb = self.tcm_read(base + (8 << 2)) - msb = self.tcm_read(base + (0 << 2)) - fec_stats['Total recevied CW'] = (msb << 32) | lsb - - lsb = self.tcm_read(base + (9 << 2)) - msb = self.tcm_read(base + (0 << 2)) - fec_stats['Total correct CW'] = (msb << 32) | lsb - - lsb = self.tcm_read(base + (10 << 2)) - msb = self.tcm_read(base + (0 << 2)) - fec_stats['Total corrected CW'] = (msb << 32) | lsb - - fec_stats['Total uncorrectable CW'] = self.tcm_read(base + (11 << 2)) - - lsb = self.tcm_read(base + (12 << 2)) - msb = self.tcm_read(base + ( 0 << 2)) - fec_stats['Corrected CW ( 1 sym err)'] = (msb << 32) | lsb - lsb = self.tcm_read(base + (13 << 2)) - msb = self.tcm_read(base + ( 0 << 2)) - fec_stats['Corrected CW ( 2 sym err)'] = (msb << 32) | lsb - fec_stats['Corrected CW ( 3 sym err)'] = self.tcm_read(base + (14 << 2)) - fec_stats['Corrected CW ( 4 sym err)'] = self.tcm_read(base + (15 << 2)) - fec_stats['Corrected CW ( 5 sym err)'] = self.tcm_read(base + (16 << 2)) - fec_stats['Corrected CW ( 6 sym err)'] = self.tcm_read(base + (17 << 2)) - fec_stats['Corrected CW ( 7 sym err)'] = self.tcm_read(base + (18 << 2)) - fec_stats['Corrected CW ( 8 sym err)'] = self.tcm_read(base + (19 << 2)) - fec_stats['Corrected CW ( 9 sym err)'] = self.tcm_read(base + (20 << 2)) - fec_stats['Corrected CW (10 sym err)'] = self.tcm_read(base + (21 << 2)) - fec_stats['Corrected CW (11 sym err)'] = self.tcm_read(base + (22 << 2)) - fec_stats['Corrected CW (12 sym err)'] = self.tcm_read(base + (23 << 2)) - fec_stats['Corrected CW (13 sym err)'] = self.tcm_read(base + (24 << 2)) - fec_stats['Corrected CW (14 sym err)'] = self.tcm_read(base + (25 << 2)) - fec_stats['Corrected CW (15 sym err)'] = self.tcm_read(base + (26 << 2)) - else: - self.log_error('acquire lock timeout, failed to get fec statisics') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get fec statisics") - return YCable.EEPROM_ERROR - - return fec_stats - - def set_autoswitch_hysteresis_timer(self, time): - """ - This API sets the hysteresis timer of the cable. This is basically the time in auto-switch mode - which the mux has to wait after toggling it once, before again toggling the mux to a different ToR - The port on which this API is called for can be referred using self.port. - - Args: - time: - an Integer, the time value for hysteresis to be set in milliseconds - - Returns: - a boolean, True if the time is configured - , False if the time is not configured - """ - curr_offset = YCable.OFFSET_AUTO_SWITCH_HYSTERESIS - - buffer = bytearray([time]) - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to set autoswitch hysteresis timer') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to set autoswitch hysteresis timer") - return YCable.EEPROM_ERROR - - return True - - def get_autoswitch_hysteresis_timer(self): - """ - This API gets the hysteresis timer of the cable. This is basically the time in auto-switch mode - which the mux has to wait after toggling it once, before again toggling the mux to a different ToR - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - time: - an Integer, the time value for hysteresis is configured in milliseconds - """ - curr_offset = YCable.OFFSET_AUTO_SWITCH_HYSTERESIS - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - time = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - else: - self.log_error('acquire lock timeout, failed to get autoswitch hysteresis timer') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get autoswitch hysteresis timer") - return YCable.EEPROM_ERROR - - return int(time[0]) - - def restart_anlt(self, target): - """ - This API restarts auto-negotiation + link training (AN/LT) mode - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to restart AN/LT on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if restart is successful - , False if the restart is not successful - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - lane = 0 - if target == YCableBase.TARGET_NIC: - lane = 0 - elif target == YCableBase.TARGET_TOR_A: - lane = 12 - elif target == YCableBase.TARGET_TOR_B: - lane = 20 - else: - self.log_error("restart anlt: unsupported target") - return False - - self.fw_cmd_ext(0x7040, 0, lane) - else: - self.log_error('acquire lock timeout, failed to restart anlt') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to restart anlt") - return YCable.EEPROM_ERROR - - return True - - def get_anlt_stats(self, target): - """ - This API returns auto-negotiation + link training (AN/LT) mode statistics - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get AN/LT stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - anlt_stat = {} - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - an_sm = 0 - if target == YCableBase.TARGET_NIC: - an_sm = self.reg_read(0x0048) - lanes=[0,4] - elif target == YCableBase.TARGET_TOR_A: - an_sm = self.reg_read(0x5448) - lanes=[12,16] - elif target == YCableBase.TARGET_TOR_B: - an_sm = self.reg_read(0x5C48) - lanes=[20,24] - else: - self.log_error("get anlt stats: unsupported target") - - anlt_stat['AN_StateMachine'] = an_sm - - for idx, ln in enumerate(range(lanes[0], lanes[1])): - lt_tx1 = self.reg_read(0xB3 | 0x200 * ln) - lt_tx2 = self.reg_read(0xB4 | 0x200 * ln) - anlt_stat['LT_TX_lane%d' % idx] = [(lt_tx1 >> 8) & 0xFF, lt_tx1 & 0xFF, (lt_tx2 >> 8) & 0xFF, lt_tx2 & 0xFF] - else: - self.log_error('acquire lock timeout, failed to get anlt stat') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get anlt stats") - return YCable.EEPROM_ERROR - - return anlt_stat - -############################################################################################# -### Debug Functionality ### -############################################################################################# - - def set_debug_mode(self, enable): - """ - This API enables/disables a debug mode that the port is now - going to be run on. If enabled, this means that PRBS/Loopback etc. type diagnostic mode - is now going to be run on the port and hence normal traffic will be disabled - on it if enabled and vice-versa if disabled. - enable is typically to be used at the software level to inform the software - that debug APIs will be called afterwords. - disable will disable any previously enabled debug functionality inside the cable - so that traffic can pass through. Also it'll inform the software to come out of the debug mode. - The port on which this API is called for can be referred using self.port. - - Args: - enable: - a boolean, True if the debug mode needs to be enabled - , False if the debug mode needs to be disabled - - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - raise NotImplementedError - - def get_debug_mode(self): - """ - This API checks if a debug mode is currently being run on the port - for which this API is called for. - This means that PRBS/Loopback etc. type diagnostic mode - if any are being run on the port this should return True else False. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a boolean, True if debug mode enabled - , False if debug mode not enabled - """ - - raise NotImplementedError - - def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.PRBS_DIRECTION_BOTH): - """ - This API configures and enables the PRBS mode/type depending upon the mode_value the user provides. - The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. - Target is an integer for selecting which end of the Y cable we want to run PRBS on. - LaneMap specifies the lane configuration to run the PRBS on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to enable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - an Integer, the mode/type for configuring the PRBS mode. - - lane_mask: - an Integer, representing the lane_mask to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011, means running on lane0 and lane1 - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - - """ - - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - - buffer = bytearray([0]) - curr_offset = YCable.OFFSET_ENABLE_PRBS - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - - buffer = bytearray([mode_value]) - curr_offset = YCable.OFFSET_CONFIGURE_PRBS_TYPE - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - - buffer = bytearray([lane_mask]) - curr_offset = YCable.OFFSET_ENABLE_PRBS - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to enable the PRBS mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to enable the PRBS mode") - return YCable.EEPROM_ERROR - - return result - - def disable_prbs_mode(self, target, direction): - """ - This API disables the PRBS mode on the physical port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = YCable.OFFSET_ENABLE_PRBS - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to disable the PRBS mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to disable the PRBS mode") - return YCable.EEPROM_ERROR - - return result - - def enable_loopback_mode(self, target, lane_mask, mode=YCableBase.LOOPBACK_MODE_NEAR_END): - """ - This API configures and enables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - LaneMap specifies the lane configuration to run the loopback on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to enable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - lane_mask: - an Integer, representing the lane_mask to be run loopback on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011, means running on lane0 and lane1 - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([lane_mask]) - curr_offset = YCable.OFFSET_ENABLE_LOOPBACK - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to enable the loopback mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to enable the loopback mode") - return YCable.EEPROM_ERROR - - return result - - def disable_loopback_mode(self, target): - """ - This API disables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = YCable.OFFSET_ENABLE_LOOPBACK - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - else: - self.log_error('acquire lock timeout, failed to disable loopback mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to disable loopback mode") - return YCable.EEPROM_ERROR - - return result - - def get_loopback_mode(self, target): - """ - This API returns the Loopback mode on the port which it has been configured to - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - - Returns: - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NONE - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return -1 - - buffer = bytearray([0]) - curr_offset = YCable.OFFSET_SYNC_DEBUG_MODE - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return -1 - time_start = time.time() - while(True): - done = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - time_now = time.time() - time_diff = time_now - time_start - if done[0] == 1: - break - elif time_diff >= YCable.GET_DEBUG_MODE_TIMEOUT_SECS: - return YCable.EEPROM_TIMEOUT_ERROR - - curr_offset = YCable.OFFSET_ENABLE_LOOPBACK - result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - - if result[0]: - return YCableBase.LOOPBACK_MODE_NEAR_END - else: - self.log_error('acquire lock timeout, failed to get loopback mode') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get loopback mode") - return YCable.EEPROM_ERROR - - return YCableBase.LOOPBACK_MODE_NONE - - def get_ber_info(self, target): - """ - This API returns the BER (Bit error rate) value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to get the BER: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with BER values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - buffer = bytearray([target]) - curr_offset = YCable.OFFSET_TARGET - - ber_result = [] - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = YCable.OFFSET_INITIATE_BER_MEASUREMENT - result = self.platform_chassis.get_sfp( - self.port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - time_start = time.time() - while(True): - done = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) - time_now = time.time() - time_diff = time_now - time_start - if done[0] == 1: - break - elif time_diff >= YCable.BER_TIMEOUT_SECS: - return YCable.EEPROM_TIMEOUT_ERROR - - idx = 0 - curr_offset = YCable.OFFSET_LANE_1_BER_RESULT - for lane in range(YCable.MAX_NUM_LANES): - msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+idx, 1) - lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+1+idx, 1) - lane_result = msb_result[0] * math.pow(10, (lsb_result[0]-24)) - ber_result.append(lane_result) - idx += 2 - else: - self.log_error('acquire lock timeout, failed to get ber info') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get ber info") - return YCable.EEPROM_ERROR - - return ber_result - - def debug_dump_registers(self, option=None): - """ - This API should dump all registers with meaningful values - for the cable to be diagnosed for proper functioning. - This means that for all the fields on relevant vendor-specific pages - this API should dump the appropriate fields with parsed values - which would help debug the Y-Cable - - Args: - option: - a string, the option param can be a string which if passed can help a vendor utilize it - as an input param or a concatenation of params for a function which they can call internally. - This essentially helps if the vendor chooses to dump only some of the registers instead of all - the registers, and thus provides more granularity for debugging/printing. - For example, the option can serdes_lane0, in this case the vendor would just dump - registers related to serdes lane 0. - - - Returns: - a Dictionary: - with all the relevant key-value pairs for all the meaningful fields - which would help diagnose the cable for proper functioning - """ - if self.platform_chassis is not None: - api_ver = self.platform_chassis.get_sfp(self.port).read_eeprom(YCable.OFFSET_API_VERSION, 1)[0] - - result = {} - result['vendor'] = self.get_vendor() - result['pn'] = self.get_part_number() - result['sn'] = self.get_serial_number() - result['uart_stat'] = self.get_uart_stat() - result['nic_temp'] = self.get_nic_temperature() - result['nic_voltage'] = self.get_nic_voltage() - result['fw_init_status'] = self.get_dsp_fw_init_stat() - result['serdes_detect'] = self.get_dsp_link_detect() - - if api_ver >= 0x18: - result['queue_info'] = self.queue_info() - - lanes = [0,1,2,3,12,13,14,15,20,21,22,23] - - for ln in list(lanes): - data = self.get_serdes_params(ln) - serdes = {} - serdes['ch_est'] = struct.unpack_from(' 512: size = 512 - else: size = length - curr - else: - size = 4 - - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_MEM_READ - vsc_req_form[YCable.VSC_BYTE_OPTION] = target - vsc_req_form[130] = (addr >> 0) & 0xFF - vsc_req_form[131] = (addr >> 8) & 0xFF - vsc_req_form[132] = (addr >> 16) & 0xFF - vsc_req_form[133] = (addr >> 24) & 0xFF - vsc_req_form[134] = (size >> 0) & 0xFF - vsc_req_form[135] = (size >> 8) & 0xFF - vsc_req_form[136] = (size >> 16) & 0xFF - vsc_req_form[137] = (size >> 24) & 0xFF - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('read MCU internal memory error error (error code:0x%04X)' % (status)) - return YCable.EEPROM_ERROR - - idx = 0 - while idx < size: - if (size - idx) > 128: - data.extend(self.read_mmap(YCable.MIS_PAGE_FC + idx // 128, 128 + idx % 128, 128)) - idx += 128 - else: - data.extend(self.read_mmap(YCable.MIS_PAGE_FC + idx // 128, 128 + idx % 128, size - idx)) - idx = size - else: - self.log_error('acquire lock timeout, failed to read memory') - return YCable.EEPROM_ERROR - - curr += size - addr += size - else: - self.log_error("platform_chassis is not loaded, failed to read memory") - - return data - - def health_check(self): - """ - This API checks the health of the cable, where it is healthy/unhealythy for RMA purposes/diagnostics. - The port on which this API is called for can be referred using self.port. - - Args: - Returns: - a Boolean, True if the cable is healthy and False if it is not healthy. - """ - - if self.platform_chassis is not None: - api_ver = self.platform_chassis.get_sfp(self.port).read_eeprom(YCable.OFFSET_API_VERSION, 1)[0] - - vendor = self.get_vendor() - if vendor != "Credo ": - self.log_error("check cable health fail: unable to get correct vendor name:%s" % (vendor)) - return YCable.CABLE_UNHEALTHY - - uart_stat = self.get_uart_stat() - if api_ver >= 0x18 and uart_stat['Local']['UART2']['RxErrorCnt'] > 100: - self.log_error("check cable health fail: uart rx error count overlimit:%d" % (uart_stat['local']['UART2']['RxErrorCnt'])) - return YCable.CABLE_UNHEALTHY - - serdes_fw_tag = self.reg_read_atomic(0xB71A) - if serdes_fw_tag != 0x6A6A: - self.log_error("check cable health fail: serdes fw is not loaded correctly:%04X" % (serdes_fw_tag)) - return YCable.CABLE_UNHEALTHY - else: - self.log_error("platform_chassis is not loaded, failed to check cable health") - return YCable.EEPROM_ERROR - - return YCable.CABLE_HEALTHY - - def get_dsp_link_detect(self): - """ - This API returns rdy/sd of DSP. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - if self.platform_chassis is not None: - result = {} - curr_offset = YCable.OFFSET_NIC_SIGNAL_DETECTION - result['sdNic'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 0, 1)[0] - result['rdyNic'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 1, 1)[0] - result['sdTorA'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 2, 1)[0] - result['rdyTorA'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 3, 1)[0] - result['sdTorB'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 4, 1)[0] - result['rdyTorB'] = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset + 5, 1)[0] - else: - self.log_error("platform_chassis is not loaded, failed to get init. status of DSP firmware") - - return result - - def get_dsp_fw_init_stat(self): - """ - This API returns init. status of DSP FW. - The port on which this API is called for can be referred using self.port. - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - if self.platform_chassis is not None: - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - result = {} - - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_DSP_LOADFW_STAT - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Get DSP firmware init status error (error code:0x%04X)' % (status)) - return result - - result['err_code'] = self.read_mmap(YCable.MIS_PAGE_VSC, 134) - result['err_stat'] = self.read_mmap(YCable.MIS_PAGE_VSC, 135) - else: - self.log_error('acquire lock timeout, failed to get init status') - return YCable.EEPROM_ERROR - else: - self.log_error("platform_chassis is not loaded, failed to get init status") - - return result - - def get_uart_stat(self): - """ - This API returns Uart statstics. - The port on which this API is called for can be referred using self.port. - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - if self.platform_chassis is not None: - result = {} - - with self.rlock.acquire_timeout(RLocker.ACQUIRE_LOCK_TIMEOUT) as lock_status: - if lock_status: - for option in range(2): - vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) - vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_UART_STAT - vsc_req_form[YCable.VSC_BYTE_OPTION] = option - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error('Dump Uart statstics error (error code:0x%04X)' % (status)) - return result - - data = self.read_mmap(YCable.MIS_PAGE_FC, 128, 64) - ver = self.read_mmap(YCable.MIS_PAGE_VSC, 130, 1) - - uartPort = {} - cnt = {} - cnt['TxPktCnt'] = struct.unpack_from(' self.POLL_TIMEOUT: - self.log_error('Retry GET {} for physical port {} timeout after {} seconds, attempted={}'.format( - get_url, - self.port, - self.POLL_TIMEOUT, - attempt - )) - break - else: - self.log_notice('Sleep {} seconds to retry GET {} for physical port {}'.format( - self.POLL_INTERVAL, - get_url, - self.port - )) - attempt += 1 - time.sleep(self.POLL_INTERVAL) - - return None - - def _post(self, url=None, data=None): - if not self._initialized: - return None - - if url: - post_url = url - else: - post_url = self._url - - if data is not None: - post_data = json.dumps(data).encode('utf-8') - else: - post_data = None - - start_time = time.time() - attempt = 1 - while True: - try: - try: - headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} - req = urllib.request.Request(post_url, post_data, headers, method='POST') - with urllib.request.urlopen(req, timeout=self.URLOPEN_TIMEOUT) as resp: - return json.loads(resp.read().decode('utf-8')) - except urllib.error.HTTPError as e: - self.log_error('attempt={}, POST {} with data {} for physical_port {} failed with {}, detail: {}'.format( - attempt, - post_url, - post_data, - self.port, - repr(e), - e.read() - )) - except (urllib.error.URLError, json.decoder.JSONDecodeError, Exception) as e: - self.log_error('attempt={}, POST {} with data {} for physical_port {} failed with {}'.format( - attempt, - post_url, - post_data, - self.port, - repr(e) - )) - - # Retry in case of exception, to workaround 'no route to host' issue after pmon restart - if time.time() - start_time > self.POLL_TIMEOUT: - self.log_error('Retry POST {} with data{} for physical port {} timeout after {} seconds, attempted={}'.format( - post_url, - post_data, - self.port, - self.POLL_TIMEOUT, - attempt - )) - break - else: - self.log_notice('Sleep {} seconds to retry POST {} with data {} for physical port {}'.format( - self.POLL_INTERVAL, - post_url, - post_data, - self.port - )) - attempt += 1 - time.sleep(self.POLL_INTERVAL) - - return None - - def _get_status(self): - if not self._initialized: - return None - try: - return self._get() - except Exception as e: - self.log_warning('Get {} failed, exception: {}'.format(self._url, repr(e))) - return None - - def _toggle_to(self, target): - """ - Helper function for toggling active side of physical_port to target side. - - Args: - target: UPPER_TOR / LOWER_TOR - Returns: - Latest mux status. None otherwise - """ - self.log_notice("Toggle active side of physical_port {} to {}".format(self.port, target)) - status = self._post(data={"active_side": target}) # mux simulator returns latest mux status - if not status: - return False - if 'active_side' in status and status['active_side'] == target: - return True - else: - return False - - def _clear_counter(self): - if self.port_index is not None: - self._post(url="{}/clear_flap_counter".format(self._vmset_url), - data={'port_to_clear': str(self.port_index)}) - - def toggle_mux_to_tor_a(self): - """ - This API does a hard switch toggle of the Y cable's MUX regardless of link state to - TOR A on the port this is called for. This means if the Y cable is actively sending traffic, - the "get_active_linked_tor_side" API will now return Tor A. - It also implies that if the link is actively sending traffic on this port, - Y cable MUX will start forwarding packets from TOR A to NIC, and drop packets from TOR B to NIC - regardless of previous forwarding state. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a Boolean, True if the toggle succeeded and False if it did not succeed. - """ - - return self._toggle_to(self.UPPER_TOR) - - def toggle_mux_to_tor_b(self): - """ - This API does a hard switch toggle of the Y cable's MUX regardless of link state to - TOR B. This means if the Y cable is actively sending traffic, the "get_active_linked_tor_side" - API will now return Tor B. It also implies that if the link is actively sending traffic on this port, - Y cable. MUX will start forwarding packets from TOR B to NIC, and drop packets from TOR A to NIC - regardless of previous forwarding state. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a Boolean, True if the toggle succeeded and False if it did not succeed. - """ - return self._toggle_to(self.LOWER_TOR) - - def get_read_side(self): - """ - This API checks which side of the Y cable the reads are actually getting performed - from, either TOR A or TOR B or NIC and returns the value. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if reading the Y cable from TOR A side. - TARGET_TOR_B, if reading the Y cable from TOR B side. - TARGET_NIC, if reading the Y cable from NIC side. - TARGET_UNKNOWN, if reading the Y cable API fails. - """ - if not self._initialized: - return self.TARGET_UNKNOWN - - return self.TARGET_TOR_A if self.side == self.UPPER_TOR else self.TARGET_TOR_B - - def get_mux_direction(self): - """ - This API checks which side of the Y cable mux is currently point to - and returns either TOR A or TOR B. Note that this API should return mux-direction - regardless of whether the link is active and sending traffic or not. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if mux is pointing to TOR A side. - TARGET_TOR_B, if mux is pointing to TOR B side. - TARGET_UNKNOWN, if mux direction API fails. - """ - status = self._get_status() - - if not isinstance(status, dict): - return self.TARGET_UNKNOWN - - if 'active_side' in status: - if status['active_side'] == self.UPPER_TOR: - return self.TARGET_TOR_A - elif status['active_side'] == self.LOWER_TOR: - return self.TARGET_TOR_B - else: - return self.TARGET_UNKNOWN - else: - return self.TARGET_UNKNOWN - - def get_active_linked_tor_side(self): - """ - This API checks which side of the Y cable is actively linked and sending traffic - and returns either TOR A or TOR B. - The port on which this API is called for can be referred using self.port. - This is different from get_mux_direction in a sense it also implies the link on the side - where mux is pointing to must be active and sending traffic, whereas get_mux_direction - just tells where the mux is pointing to. - - Args: - - Returns: - One of the following predefined constants: - TARGET_TOR_A, if TOR A is actively linked and sending traffic. - TARGET_TOR_B, if TOR B is actively linked and sending traffic. - TARGET_UNKNOWN, if checking which side is linked and sending traffic API fails. - """ - - return self.get_mux_direction() # For simulated y-cable, it is same as get_mux_direction. - - def is_link_active(self, target): - """ - This API checks if NIC, TOR_A and TOR_B of the Y cable's link is active. - The target specifies which link is supposed to be checked - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if the link is active - , False if the link is not active - """ - - # For simulated y-cable, the DUT is connected to fanout. Link should always be active. - return True - - def get_eye_heights(self, target): - """ - This API returns the EYE height value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to get the eye: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with EYE values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - return [0, 1, 2, 3] - - def get_vendor(self): - """ - This API returns the vendor name of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with vendor name - """ - - return self.VENDOR - - def get_part_number(self): - """ - This API returns the part number of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with part number - """ - - return self.PART_NUMBER - - def get_switch_count_total(self, switch_count_type, clear_on_read=False): - """ - This API returns the total switch count to change the Active TOR which has - been done manually/automatic by the user. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times the Y-cable has been switched - """ - - # Currently the mux simulator only supports single flap counter. There is no difference between manual - # flap, auto flap. - status = self._get_status() - if not status: - return 0 - if clear_on_read: - self._clear_counter() - return int(status['flap_counter']) - - - def get_switch_count_tor_a(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR A - This is essentially all the successful switches initiated from ToR A. Toggles which were - initiated to toggle from ToR A and did not succeed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR A - """ - # Currently the mux simulator only supports single flap counter. There is no difference between manual - # flap, auto flap. - self.get_switch_count_total(clear_on_read=clear_on_read)//2 - - def get_switch_count_tor_b(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR B - This is essentially all the successful switches initiated from ToR B. Toggles which were - initiated to toggle from ToR B and did not succeed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR B - """ - # Currently the mux simulator only supports single flap counter. There is no difference between manual - # flap, auto flap. - self.get_switch_count_total(clear_on_read=clear_on_read)//2 - - def get_switch_count_target(self, switch_count_type, target, clear_on_read=False): - """ - This API returns the total number of times the Active TOR has - been done manually/automaticlly toggled towards a target. - For example, TARGET_TOR_A as target would imply - how many times the mux has been toggled towards TOR A. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times manually the Y-cable has been switched - """ - # Currently the mux simulator only supports single flap counter. There is no difference between manual - # flap, auto flap. There is also no dedicated counter for tor_a or tor_b. - self.get_switch_count_total(clear_on_read=clear_on_read)//2 - - def get_target_cursor_values(self, lane, target): - """ - This API returns the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two, main, post one, post two, post three cursor values - If any of the value is not available please return None for that filter - The port on which this API is called for can be referred using self.port. - - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a list, with pre one, pre two, main, post one, post two, post three cursor values in the order - """ - - return [None, None, None, None, None, None] - - def set_target_cursor_values(self, lane, cursor_values, target): - """ - This API sets the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two, main, post one, post two etc. cursor values - The port on which this API is called for can be referred using self.port. - - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - cursor_values: - a list, with pre one, pre two, main, post one, post two cursor, post three etc. values in the order - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if cursor values setting is successful - , False if cursor values setting is not successful - """ - - return True - - def get_firmware_version(self, target): - """ - This routine should return the active, inactive and next (committed) - firmware running on the target. Each of the version values in this context - could be a string with a major and minor number and a build value. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the firmware version on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a Dictionary: - with version_active, version_inactive and version_next keys - and their corresponding values - - """ - - return self.VERSION - - def download_firmware(self, fwfile): - """ - This routine should download and store the firmware on all the - components of the Y cable of the port for which this API is called.. - This should include any internal transfers, checksum validation etc. - from TOR to TOR or TOR to NIC side of the firmware specified by the fwfile. - This basically means that the firmware which is being downloaded should be - available to be activated (start being utilized by the cable) once this API is - successfully executed. - Note that this API should ideally not require any rollback even if it fails - as this should not interfere with the existing cable functionality because - this has not been activated yet. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile: - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable - Returns: - One of the following predefined constants: - FIRMWARE_DOWNLOAD_SUCCESS - FIRMWARE_DOWNLOAD_FAILURE - - a predefined code stating whether the firmware download was successful - or an error code as to what was the cause of firmware download failure - """ - - return self.FIRMWARE_DOWNLOAD_SUCCESS - - def activate_firmware(self, fwfile=None, hitless=False): - """ - This routine should activate the downloaded firmware on all the - components of the Y cable of the port for which this API is called.. - This API is meant to be used in conjunction with download_firmware API, and - should be called once download_firmware API is succesful. - This means that the firmware which has been downloaded should be - activated (start being utilized by the cable) once this API is - successfully executed. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in activate_firmware, the API should - have the logic to retreive the firmware version from this file - which has to be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should activate whatever - firmware is marked to be activated next. - If provided, it should retreive the firmware version(s) from this file, ensure - they are downloaded on the cable, then activate them. - - hitless (optional): - a boolean, True, Hitless upgrade: it will backup/restore the current state - (ex. variables of link status, API attributes...etc.) before - and after firmware upgrade. - a boolean, False, Non-hitless upgrade: it will update the firmware regardless - the current status, a link flip can be observed during the upgrade. - Returns: - One of the following predefined constants: - FIRMWARE_ACTIVATE_SUCCESS - FIRMWARE_ACTIVATE_FAILURE - """ - - return self.FIRMWARE_ACTIVATE_SUCCESS - - def rollback_firmware(self, fwfile=None): - """ - This routine should rollback the firmware to the previous version - which was being used by the cable. This API is intended to be called when the - user either witnesses an activate_firmware API failure or sees issues with - newer firmware in regards to stable cable functioning. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in rollback_firmware, the API should - have the logic to retreive the firmware version from this file - which should not be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should rollback whatever - firmware is marked to be rollback next. - If provided, it should retreive the firmware version(s) from this file, ensure - that the firmware is rollbacked to a version which does not match to retreived version(s). - This is exactly the opposite behavior of this param to activate_firmware - Returns: - One of the following predefined constants: - FIRMWARE_ROLLBACK_SUCCESS - FIRMWARE_ROLLBACK_FAILURE - """ - - return self.FIRMWARE_ROLLBACK_SUCCESS - - def set_switching_mode(self, mode): - """ - This API enables the auto switching or manual switching feature on the Y-Cable, - depending upon the mode entered by the user. - Autoswitch feature if enabled actually does an automatic toggle of the mux in case the active - side link goes down and basically points the mux to the other side. - The port on which this API is called for can be referred using self.port. - - Args: - mode: - One of the following predefined constants: - SWITCHING_MODE_AUTO - SWITCHING_MODE_MANUAL - - specifies which type of switching mode we set the Y-Cable to - either SWITCHING_MODE_AUTO or SWITCHING_MODE_MANUAL - - Returns: - a Boolean, True if the switch succeeded and False if it did not succeed. - """ - - self.switching_mode = mode - return True - - def get_switching_mode(self): - """ - This API returns which type of switching mode the cable is set to auto/manual - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - One of the following predefined constants: - SWITCHING_MODE_AUTO if auto switch is enabled. - SWITCHING_MODE_MANUAL if manual switch is enabled. - """ - - return self.switching_mode - - def get_nic_temperature(self): - """ - This API returns nic temperature of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - an Integer, the temperature of the NIC MCU - """ - - return self.NIC_TEMPERATURE - - def get_local_temperature(self): - """ - This API returns local ToR temperature of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - an Integer, the temperature of the local MCU - """ - - return self.LOCAL_TEMPERATURE - - def get_nic_voltage(self): - """ - This API returns nic voltage of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a float, the voltage of the NIC MCU - """ - - return self.NIC_VOLTAGE - - def get_local_voltage(self): - """ - This API returns local ToR voltage of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a float, the voltage of the local MCU - """ - - return self.LOCAL_VOLTAGE - - def get_alive_status(self): - """ - This API checks if cable is connected to all the ports and is healthy. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a boolean, True if the cable is alive - , False if the cable is not alive - """ - return False if self._get_status is None else True - - def reset(self, target): - """ - This API resets the MCU to which this API is called for. - The target specifies which MCU is supposed to be reset - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if the cable is target reset - , False if the cable target is not reset - """ - return False if self._post('{}/reset'.format(self._url)) is None else True - - def create_port(self, speed, fec_mode_tor=YCableBase.FEC_MODE_NONE, fec_mode_nic=YCableBase.FEC_MODE_NONE, anlt_tor=False, anlt_nic=False): - """ - This API sets the mode of the cable/port for corresponding lane/FEC etc. configuration as specified. - The speed specifies which mode is supposed to be set 50G, 100G etc - the AN/LT specifies if auto-negotiation + link training (AN/LT) has to be enabled - Note that in case create_port is called multiple times, the most recent api call will take the precedence - on either of TOR side. - The port on which this API is called for can be referred using self.port. - - Args: - speed: - an Integer, the value for the link speed to be configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - - fec_mode_tor: - One of the following predefined constants, the actual FEC mode for the ToR to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - - fec_mode_nic: - One of the following predefined constants, the actual FEC mode for the nic to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - - anlt_tor: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on ToR's - , False if auto-negotiation + link training (AN/LT) is not to be enabled on ToR's - - anlt_nic: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on nic - , False if auto-negotiation + link training (AN/LT) is not to be enabled on nic - - - Returns: - a boolean, True if the port is configured - , False if the port is not configured - """ - - return True - - def get_speed(self): - """ - This API gets the mode of the cable for corresponding lane configuration. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - speed: - an Integer, the value for the link speed is configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - """ - - if self._initialized: - return self.port_speed - else: - return 0 - - def set_fec_mode(self, fec_mode, target): - """ - This API gets the FEC mode of the cable for which it is set to. - The port on which this API is called for can be referred using self.port. - - Args: - fec_mode: - One of the following predefined constants, the actual FEC mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - target: - One of the following predefined constants, the actual target to set the FEC mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - - Returns: - a boolean, True if the FEC mode is configured - , False if the FEC mode is not configured - """ - - return False - - def get_fec_mode(self, target): - """ - This API gets the FEC mode of the cable which it is set to. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to FEC mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - fec_mode: - One of the following predefined constants, the actual FEC mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - """ - - return self.FEC_MODE_NONE - - def set_anlt(self, enable, target): - """ - This API enables/disables the cable auto-negotiation + link training (AN/LT). - The port on which this API is called for can be referred using self.port. - - Args: - enable: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled - , False if auto-negotiation + link training (AN/LT) is not to be enabled - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - - Returns: - a boolean, True if the auto-negotiation + link training (AN/LT) enable/disable specified is configured - , False if the auto-negotiation + link training (AN/LT) enable/disable specified is not configured - """ - - return True - - def get_anlt(self, target): - """ - This API gets the auto-negotiation + link training (AN/LT) mode of the cable for corresponding port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the AN/LT on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if auto-negotiation + link training (AN/LT) is enabled - , False if auto-negotiation + link training (AN/LT) is not enabled - """ - - return True - - def get_event_log(self, clear_on_read=False): - """ - This API returns the event log of the cable - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the log has to be cleared after read - , False if the log is not to be cleared after read - - Returns: - list: - a list of strings which correspond to the event logs of the cable - """ - - return [] - - def get_pcs_stats(self, target): - """ - This API returns the pcs statistics of the cable - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - return {} - - def get_fec_stats(self, target): - """ - This API returns the FEC statistics of the cable - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - return {} - - def set_autoswitch_hysteresis_timer(self, time): - """ - This API sets the hysteresis timer of the cable. This is basically the time in auto-switch mode - which the mux has to wait after toggling it once, before again toggling the mux to a different ToR - The port on which this API is called for can be referred using self.port. - - Args: - time: - an Integer, the time value for hysteresis to be set in milliseconds - - Returns: - a boolean, True if the time is configured - , False if the time is not configured - """ - - # The mux simulator does not support auto-switch. Let's assume this timer is always configured and value is 0 - return True - - def get_autoswitch_hysteresis_timer(self): - """ - This API gets the hysteresis timer of the cable. This is basically the time in auto-switch mode - which the mux has to wait after toggling it once, before again toggling the mux to a different ToR - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - time: - an Integer, the time value for hysteresis is configured in milliseconds - """ - - # The mux simulator does not support auto-switch. Let's assume this timer is always configured and value is 0 - return 0 - - def restart_anlt(self, target): - """ - This API restarts auto-negotiation + link training (AN/LT) mode - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to restart AN/LT on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if restart is successful - , False if the restart is not successful - """ - - return True - - def get_anlt_stats(self, target): - """ - This API returns auto-negotiation + link training (AN/LT) mode statistics - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get AN/LT stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - return {} - -############################################################################################# -### Debug Functionality ### -############################################################################################# - - def set_debug_mode(self, enable): - """ - This API enables/disables a debug mode that the port is now - going to be run on. If enabled, this means that PRBS/Loopback etc. type diagnostic mode - is now going to be run on the port and hence normal traffic will be disabled - on it if enabled and vice-versa if disabled. - enable is typically to be used at the software level to inform the software - that debug APIs will be called afterwords. - disable will disable any previously enabled debug functionality inside the cable - so that traffic can pass through. Also it'll inform the software to come out of the debug mode. - The port on which this API is called for can be referred using self.port. - - Args: - enable: - a boolean, True if the debug mode needs to be enabled - , False if the debug mode needs to be disabled - - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - self.debug_mode = enable - return True - - def get_debug_mode(self): - """ - This API checks if a debug mode is currently being run on the port - for which this API is called for. - This means that PRBS/Loopback etc. type diagnostic mode - if any are being run on the port this should return True else False. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a boolean, True if debug mode enabled - , False if debug mode not enabled - """ - - return self.debug_mode - - def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.PRBS_DIRECTION_BOTH): - """ - This API configures and enables the PRBS mode/type depending upon the mode_value the user provides. - The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. - Target is an integer for selecting which end of the Y cable we want to run PRBS on. - LaneMap specifies the lane configuration to run the PRBS on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to enable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - an Integer, the mode/type for configuring the PRBS mode. - - lane_mask: - an Integer, representing the lane_mask to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011, means running on lane0 and lane1 - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - - """ - - return True - - def disable_prbs_mode(self, target, direction=YCableBase.PRBS_DIRECTION_BOTH): - """ - This API disables the PRBS mode on the physical port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - return True - - def enable_loopback_mode(self, target, lane_mask, mode=YCableBase.LOOPBACK_MODE_NEAR_END): - """ - This API configures and enables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - LaneMap specifies the lane configuration to run the loopback on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to enable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - lane_mask: - an Integer, representing the lane_mask to be run loopback on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011, means running on lane0 and lane1 - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - return True - - def disable_loopback_mode(self, target): - """ - This API disables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - return True - - def get_loopback_mode(self, target): - """ - This API returns the Loopback mode on the port which it has been configured to - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - - Returns: - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - """ - - # Assume the loopback mode is always LOOPBACK_MODE_NEAR_END - return self.LOOPBACK_MODE_NEAR_END - - def get_ber_info(self, target): - """ - This API returns the BER (Bit error rate) value for a specific port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to get the BER: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with BER values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - # Assume there are 4 lanes for simulated y-cable - return [0, 0, 0, 0] - - def debug_dump_registers(self, option=None): - """ - This API should dump all registers with meaningful values - for the cable to be diagnosed for proper functioning. - This means that for all the fields on relevant vendor-specific pages - this API should dump the appropriate fields with parsed values - which would help debug the Y-Cable - - Args: - option: - a string, the option param can be a string which if passed can help a vendor utilize it - as an input param or a concatenation of params for a function which they can call internally. - This essentially helps if the vendor chooses to dump only some of the registers instead of all - the registers, and thus provides more granularity for debugging/printing. - For example, the option can serdes_lane0, in this case the vendor would just dump - registers related to serdes lane 0. - - - Returns: - a Dictionary: - with all the relevant key-value pairs for all the meaningful fields - which would help diagnose the cable for proper functioning - """ - - return {} diff --git a/sonic_y_cable/y_cable.py b/sonic_y_cable/y_cable.py deleted file mode 100644 index f2ae3d3c7..000000000 --- a/sonic_y_cable/y_cable.py +++ /dev/null @@ -1,1530 +0,0 @@ -# -# y_cable.py -# -# definitions for implementing Y cable access and configurations -# API's for Y cable functionality in SONiC - -try: - import math - import time - import struct - from ctypes import c_int8 - - from sonic_py_common import logger - import sonic_platform.platform -except ImportError as e: - # When build python3 xcvrd, it tries to do basic check which will import this file. However, - # not all platform supports python3 API now, so it could cause an issue when importing - # sonic_platform.platform. We skip the ImportError here. This is safe because: - # 1. If any python package is not available, there will be exception when use it - # 2. Vendors know their platform API version, they are responsible to use correct python - # version when importing this file. - pass - -# definitions of the offset with width accommodated for values -# of MUX register specs of upper page 0x04 starting at 640 -# info eeprom for Y Cable -OFFSET_IDENTFIER_LOWER_PAGE = 0 -OFFSET_IDENTFIER_UPPER_PAGE = 128 -OFFSET_DETERMINE_CABLE_READ_SIDE = 640 -OFFSET_CHECK_LINK_ACTIVE = 641 -OFFSET_SWITCH_MUX_DIRECTION = 642 -OFFSET_MUX_DIRECTION = 644 -OFFSET_ACTIVE_TOR_INDICATOR = 645 -OFFSET_CONFIGURE_PRBS_TYPE = 768 -OFFSET_ENABLE_PRBS = 769 -OFFSET_INITIATE_BER_MEASUREMENT = 770 -OFFSET_TARGET = 794 -OFFSET_ENABLE_LOOPBACK = 793 -OFFSET_LANE_1_BER_RESULT = 771 -OFFSET_MAX_LANES = 2 -OFFSET_INITIATE_EYE_MEASUREMENT = 784 -OFFSET_LANE_1_EYE_RESULT = 785 -OFFSET_PART_NUMBER = 168 -OFFSET_VENDOR_NAME = 148 -OFFSET_MANUAL_SWITCH_COUNT = 653 -OFFSET_AUTO_SWITCH_COUNT = 657 -OFFSET_NIC_CURSOR_VALUES = 661 -OFFSET_TOR1_CURSOR_VALUES = 681 -OFFSET_TOR2_CURSOR_VALUES = 701 -OFFSET_NIC_LANE_ACTIVE = 721 -OFFSET_INTERNAL_TEMPERATURE = 22 -OFFSET_INTERNAL_VOLTAGE = 26 -OFFSET_NIC_TEMPERATURE = 727 -OFFSET_NIC_VOLTAGE = 729 -OFFSET_ENABLE_AUTO_SWITCH = 651 - -# definitions of targets for getting the cursor -# equalization parameters from the register spec -# the name of the target denotes which side cursor -# values will be retreived - -TARGET_NIC = 0 -TARGET_TOR1 = 1 -TARGET_TOR2 = 2 - -# definitions of targets for getting the EYE/BER -# and initiating PRBS/Loopback on the Y cable -# the name of the target denotes which side values -# will be retreived/initiated - -EYE_PRBS_TARGET_LOCAL = 0 -EYE_PRBS_TARGET_TOR1 = 1 -EYE_PRBS_TARGET_TOR2 = 2 -EYE_PRBS_TARGET_NIC = 3 - -# definitions of switch counter types -# to be entered by the user in get_switch_count api -# for retreiving the counter values - -SWITCH_COUNT_MANUAL = "manual" -SWITCH_COUNT_AUTO = "auto" - -FIRMWARE_INFO_PAYLOAD_SIZE = 48 -NUM_MCU_SIDE = 3 - -EEPROM_READ_DATA_INVALID = -1 -EEPROM_ERROR = -1 -EEPROM_TIMEOUT_ERROR = -1 - -BER_TIMEOUT_SECS = 1 -EYE_TIMEOUT_SECS = 1 - -MAX_NUM_LANES = 4 - -# switching modes inside muxcable -SWITCHING_MODE_MANUAL = 0 -SWITCHING_MODE_AUTO = 1 - -# Valid return codes for upgrade firmware routine steps -FIRMWARE_DOWNLOAD_SUCCESS = 0 -FIRMWARE_DOWNLOAD_FAILURE = 1 -FIRMWARE_ACTIVATE_SUCCESS = 0 -FIRMWARE_ACTIVATE_FAILURE = 1 -FIRMWARE_ROLLBACK_SUCCESS = 0 -FIRMWARE_ROLLBACK_FAILURE = 1 - -SYSLOG_IDENTIFIER = "sonic_y_cable" - -# Global logger instance for helper functions and classes to log -helper_logger = logger.Logger(SYSLOG_IDENTIFIER) - -# Global platform_chassis instance to call get_sfp required for read/write eeprom -platform_chassis = None - -try: - platform_chassis = sonic_platform.platform.Platform().get_chassis() - helper_logger.log_info("chassis loaded {}".format(platform_chassis)) -except Exception as e: - helper_logger.log_warning("Failed to load chassis due to {}".format(repr(e))) - - -def y_cable_validate_read_data(result, size, physical_port, message): - - if result is not None: - if isinstance(result, bytearray): - if len(result) != size: - LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a size {} not equal to 1 for port {}" - helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, len(result), physical_port)) - return EEPROM_READ_DATA_INVALID - else: - LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned an instance value of type {} which is not a bytearray for port {}" - helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, type(result), physical_port)) - return EEPROM_READ_DATA_INVALID - else: - LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a None value for port {} which is not expected" - helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, physical_port)) - return EEPROM_READ_DATA_INVALID - - -def hook_y_cable_simulator(target): - """Decorator to add hook for calling y_cable_simulator_client. - - This decorator updates the y_cable driver functions to call hook functions defined in the y_cable_simulator_client - module if importing the module is successful. If importing the y_cable_simulator_client module failed, just call - the original y_cable driver functions defined in this module. - - Args: - target (function): The y_cable driver function to be updated. - """ - def wrapper(*args, **kwargs): - try: - import y_cable_simulator_client - y_cable_func = getattr(y_cable_simulator_client, target.__name__, None) - if y_cable_func and callable(y_cable_func): - return y_cable_func(*args, **kwargs) - else: - return target(*args, **kwargs) - except ImportError: - return target(*args, **kwargs) - wrapper.__name__ = target.__name__ - return wrapper - - -@hook_y_cable_simulator -def toggle_mux_to_torA(physical_port): - """ - This API specifically does a hard switch toggle of the Y cable's MUX regardless of link state to - TOR A. This means if the Y cable is actively routing, the "check_active_linked_tor_side(physical_port)" - API will now return Tor A. It also implies that if the link is actively routing on this port, Y cable - MUX will start forwarding packets from TOR A to NIC, and drop packets from TOR B to NIC - regardless of previous forwarding state. This API basically writes to upper page 4 offset 130 the - value of 0x2 and expects the MUX to toggle to TOR A. Bit 0 value 0 means TOR A. - - Register Specification at offset 130 is documented below - - Byte offset bits Name Description - 130 7-2 Reserved Reserved - 1 Hard vs. soft switch 0b0 - Switch only if a valid TOR link on target; 0b1 Switch to new target regardless of link status - 0 Switch Target Switch Target - 0b0 - TOR#1, 0b1 - TOR#2; default is TOR #1 - - Args: - physical_port: - an Integer, the actual physical port connected to Y end of a Y cable which can toggle the MUX - - Returns: - a Boolean, true if the toggle succeeded and false if it did not succeed. - """ - - buffer = bytearray([2]) - curr_offset = OFFSET_SWITCH_MUX_DIRECTION - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") - return False - - return result - - -@hook_y_cable_simulator -def toggle_mux_to_torB(physical_port): - """ - This API specifically does a hard switch toggle of the Y cable's MUX regardless of link state to - TOR B. This means if the Y cable is actively routing, the "check_active_linked_tor_side(physical_port)" - API will now return Tor B. It also implies that if the link is actively routing on this port, Y cable - MUX will start forwarding packets from TOR B to NIC, and drop packets from TOR A to NIC - regardless of previous forwarding state. API basically writes to upper page 4 offset 130 the value - of 0x3 and expects the MUX to toggle to TOR B. Bit 0 value 1 means TOR B - - Register Specification at offset 130 is documented below - - Byte offset bits Name Description - 130 7-2 Reserved Reserved - 1 Hard vs. soft switch 0b0 - Switch only if a valid TOR link on target; 0b1 Switch to new target regardless of link status - 0 Switch Target Switch Target - 0b0 - TOR#1, 0b1 - TOR#2; default is TOR #1 - - Args: - physical_port: - an Integer, the actual physical port connected to Y end of a Y cable which can toggle the MUX - - Returns: - a Boolean, true if the toggle succeeded and false if it did not succeed. - """ - - buffer = bytearray([3]) - curr_offset = OFFSET_SWITCH_MUX_DIRECTION - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") - return False - - return result - - -@hook_y_cable_simulator -def check_read_side(physical_port): - """ - This API specifically checks which side of the Y cable the reads are actually getting performed - from, either TOR A or TOR B or NIC and returns the value. API basically reads 1 byte at upper - page 4 offset 128 and checks which side of the Y cable the read is being performed from. - - Register Specification of upper page 0x4 at offset 128 is documented below - - Byte offset bits Name Description - 7-3 Reserved Determine which side of the cable you are reading from - specifically to differentiate TOR #1 and TOR #2: - 0b1 : Reading from indicated side, 0b0 not reading from that side. - 2 TOR #1 Side - 1 TOR #2 Side - 0 NIC Side - Args: - physical_port: - an Integer, the actual physical port connected to Y end of a Y cable which can which side reading the MUX from - - Returns: - an Integer, 1 if reading the Y cable from TOR A side(TOR 1). - , 2 if reading the Y cable from TOR B side(TOR 2). - , 0 if reading the Y cable from NIC side. - , -1 if reading the Y cable API fails. - """ - - curr_offset = OFFSET_DETERMINE_CABLE_READ_SIDE - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).read_eeprom(curr_offset, 1) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to check read side") - return -1 - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - helper_logger.log_error("Error: for checking mux_cable read side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), physical_port)) - return -1 - else: - helper_logger.log_error("Error: for checking mux_cable read_side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), physical_port)) - return -1 - else: - helper_logger.log_error( - "Error: for checking mux_cable read_side, eeprom read returned a None value for port {} which is not expected".format(physical_port)) - return -1 - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0] >> 2) & 0x01): - helper_logger.log_info("Reading from TOR A") - return 1 - elif ((regval_read[0] >> 1) & 0x01): - helper_logger.log_info("Reading from TOR B") - return 2 - elif (regval_read[0] & 0x01): - helper_logger.log_info("Reading from NIC side") - return 0 - else: - helper_logger.log_error( - "Error: unknown status for checking which side regval = {} ".format(result)) - - return -1 - - -@hook_y_cable_simulator -def check_mux_direction(physical_port): - """ - This API specifically checks which side of the Y cable mux is currently point to - and returns either TOR A or TOR B. API basically reads 1 byte at upper page 4 offset 132 - and checks which side the mux is pointing to - - - Register Specification of upper page 0x4 at offset 133 is documented below - - Byte offset bits Name Description - 132 7-0 MUX Switch Status Register 0x00 : MUX pointing at TOR#2, 0x01 MUX pointing at TOR#1 regardless of connection status - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - - Returns: - an Integer, 1 if the mux is pointing to TOR A . - , 2 if the mux is pointing to TOR B. - , -1 if checking which side mux is pointing to API fails. - """ - - curr_offset = OFFSET_MUX_DIRECTION - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).read_eeprom(curr_offset, 1) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to check Active Linked and routing TOR side") - return -1 - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - helper_logger.log_error("Error: for checking mux_cable mux pointing side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), physical_port)) - return -1 - else: - helper_logger.log_error("Error: for checking mux_cable mux pointing side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), physical_port)) - return -1 - else: - helper_logger.log_error( - "Error: for checking mux_cable mux pointing side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(physical_port)) - return -1 - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0]) & 0x01): - helper_logger.log_info("mux pointing to TOR A") - return 1 - elif regval_read[0] == 0: - helper_logger.log_info("mux pointing to TOR B") - return 2 - else: - helper_logger.log_error( - "Error: unknown status for mux direction regval = {} ".format(result)) - return -1 - - return -1 - - -@hook_y_cable_simulator -def check_active_linked_tor_side(physical_port): - """ - This API specifically checks which side of the Y cable is actively linked and routing - and returns either TOR A or TOR B. API basically reads 1 byte at upper page 4 offset 133 - and checks which side is actively linked and routing. - - - Register Specification of upper page 0x4 at offset 133 is documented below - - Byte offset bits Name Description - 133 7-0 TOR Active Indicator 0x00, no sides linked and routing frames, 0x01 TOR #1 linked and routing, 0x02, TOR #2 linked and routing - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - - Returns: - an Integer, 1 if TOR A is actively linked and routing(TOR 1). - , 2 if TOR B is actively linked and routing(TOR 2). - , 0 if nothing linked and actively routing - , -1 if checking which side linked for routing API fails. - """ - - curr_offset = OFFSET_ACTIVE_TOR_INDICATOR - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).read_eeprom(curr_offset, 1) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to check Active Linked and routing TOR side") - return -1 - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - helper_logger.log_error("Error: for checking mux_cable active linked side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), physical_port)) - return -1 - else: - helper_logger.log_error("Error: for checking mux_cable active linked side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), physical_port)) - return -1 - else: - helper_logger.log_error( - "Error: for checking mux_cable active linked side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(physical_port)) - return -1 - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0] >> 1) & 0x01): - helper_logger.log_info("TOR B active linked and actively routing") - return 2 - elif ((regval_read[0]) & 0x01): - helper_logger.log_info("TOR A standby linked and actively routing") - return 1 - elif regval_read[0] == 0: - helper_logger.log_info("Nothing linked for routing") - return 0 - else: - helper_logger.log_error( - "Error: unknown status for active TOR regval = {} ".format(result)) - return -1 - - return -1 - - -@hook_y_cable_simulator -def check_if_link_is_active_for_NIC(physical_port): - """ - This API specifically checks if NIC side of the Y cable's link is active - API basically reads 1 byte at upper page 4 offset 129 and checks if the link is active on NIC side - - Register Specification of upper page 0x4 at offset 129 is documented below - - Byte offset bits Name Description - 129 7-3 Reserved Cable link status is for each end. 0b1 : Link up, 0b0 link not up. - 2 TOR #1 Side - 1 TOR #2 Side - 0 NIC Side - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - - Returns: - a boolean, true if the link is active - , false if the link is not active - """ - curr_offset = OFFSET_CHECK_LINK_ACTIVE - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).read_eeprom(curr_offset, 1) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to check if link is Active on NIC side") - return -1 - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - helper_logger.log_error("Error: for checking mux_cable link is active on NIC side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), physical_port)) - return -1 - else: - helper_logger.log_error("Error: for checking mux_cable link is active on NIC side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), physical_port)) - return -1 - else: - helper_logger.log_error( - "Error: for checking mux_cable link is active on NIC side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(physical_port)) - return -1 - - regval_read = struct.unpack(">B", result) - - if (regval_read[0] & 0x01): - helper_logger.log_info("NIC link is up") - return True - else: - return False - - -@hook_y_cable_simulator -def check_if_link_is_active_for_torA(physical_port): - """ - This API specifically checks if TOR A side of the Y cable's link is active - API basically reads 1 byte at upper page 4 offset 129 and checks if the link is active on NIC side - - Register Specification of upper page 0x4 at offset 129 is documented below - - Byte offset bits Name Description - 129 7-3 Reserved Cable link status is for each end. 0b1 : Link up, 0b0 link not up. - 2 TOR #1 Side - 1 TOR #2 Side - 0 NIC Side - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - - Returns: - a boolean, true if the link is active - , false if the link is not active - """ - - curr_offset = OFFSET_CHECK_LINK_ACTIVE - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).read_eeprom(curr_offset, 1) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to check if link is Active on TOR A side") - return -1 - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - helper_logger.log_error("Error: for checking mux_cable link is active on TOR A side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), physical_port)) - return -1 - else: - helper_logger.log_error("Error: for checking mux_cable link is active on TOR A side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), physical_port)) - return -1 - else: - helper_logger.log_error( - "Error: for checking mux_cable link is active on TOR A side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(physical_port)) - return -1 - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0] >> 2) & 0x01): - helper_logger.log_info("TOR A link is up") - return True - else: - return False - - -@hook_y_cable_simulator -def check_if_link_is_active_for_torB(physical_port): - """ - This API specifically checks if TOR B side of the Y cable's link is active - API basically reads 1 byte at upper page 4 offset 129 and checks if the link is active on NIC side - - Register Specification of upper page 0x4 at offset 129 is documented below - - Byte offset bits Name Description - 129 7-3 Reserved Cable link status is for each end. 0b1 : Link up, 0b0 link not up. - 2 TOR #1 Side - 1 TOR #2 Side - 0 NIC Side - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - - Returns: - a boolean, true if the link is active - , false if the link is not active - """ - - curr_offset = OFFSET_CHECK_LINK_ACTIVE - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).read_eeprom(curr_offset, 1) - else: - helper_logger.log_error("platform_chassis is not loaded, failed to check if link is Active on TOR B side") - return -1 - - if result is not None: - if isinstance(result, bytearray): - if len(result) != 1: - helper_logger.log_error("Error: for checking mux_cable link is active on TOR B side, eeprom read returned a size {} not equal to 1 for port {}".format( - len(result), physical_port)) - return -1 - else: - helper_logger.log_error("Error: for checking mux_cable link is active on TOR B side, eeprom read returned an instance value of type {} which is not a bytearray for port {}".format( - type(result), physical_port)) - return -1 - else: - helper_logger.log_error( - "Error: for checking mux_cable link is active on TOR B side, eeprom read returned a None value from eeprom read for port {} which is not expected".format(physical_port)) - return -1 - - regval_read = struct.unpack(">B", result) - - if ((regval_read[0] >> 1) & 0x01): - helper_logger.log_info("TOR B link is up") - return True - else: - return False - - -@hook_y_cable_simulator -def enable_prbs_mode(physical_port, target, mode_value, lane_map): - """ - This API specifically configures and enables the PRBS mode/type depending upon the mode_value the user provides. - The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. - Each side can only R/W its own value. 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31, 0x04-0xFF reserved. - Target is an integer for selecting which end of the Y cable we want to run PRBS on. - LaneMap specifies the lane configuration to run the PRBS on. - - - Register Specification of upper page 0x5 at offset 128, 129 is documented below - - Byte offset bits Name Description - 128 7-0 Reserved PRBS Type for generation and BER sensing on a per side basis. - Each side can only R/W its own value. - 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31, 0x04-0xFF reserved - - 129 7-4 Reserved - 3 Lane 4 enable "Enable PRBS generation on target lane 0b1 : - Enable, 0b0 disable If any lanes are enabled, - then that side of cable is removed fro mission mode and no longer passing valid traffic." - 2 Lane 3 enable - 1 Lane 2 enable - 0 Lane 1 enable - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the target on which to enable the PRBS - EYE_PRBS_TARGET_LOCAL -> local side, - EYE_PRBS_TARGET_TOR1 -> TOR 1 - EYE_PRBS_TARGET_TOR2 -> TOR 2 - EYE_PRBS_TARGET_NIC -> NIC - mode_value: - an Integer, the mode/type for configuring the PRBS mode. - 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31 - lane_map: - an Integer, representing the lane_map to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011 , means running on lane0 and lane1 - - Returns: - a boolean, true if the enable is successful - , false if the enable failed - """ - - buffer = bytearray([target]) - curr_offset = OFFSET_TARGET - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([mode_value]) - curr_offset = OFFSET_CONFIGURE_PRBS_TYPE - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([lane_map]) - curr_offset = OFFSET_ENABLE_PRBS - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") - return -1 - - return result - - -@hook_y_cable_simulator -def disable_prbs_mode(physical_port, target): - """ - This API specifically disables the PRBS mode on the physcial port. - - Register Specification of upper page 0x5 at offset 129 is documented below - - Byte offset bits Name Description - 129 7-4 Reserved - 3 Lane 4 enable "Enable PRBS generation on target lane 0b1 : - Enable, 0b0 disable If any lanes are enabled, - then that side of cable is removed fro mission mode and no longer passing valid traffic." - 2 Lane 3 enable - 1 Lane 2 enable - 0 Lane 1 enable - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the target on which to enable the PRBS - EYE_PRBS_TARGET_LOCAL -> local side, - EYE_PRBS_TARGET_TOR1 -> TOR 1 - EYE_PRBS_TARGET_TOR2 -> TOR 2 - EYE_PRBS_TARGET_NIC -> NIC - - Returns: - a boolean, true if the disable is successful - , false if the disable failed - """ - - buffer = bytearray([target]) - curr_offset = OFFSET_TARGET - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = OFFSET_ENABLE_PRBS - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") - return -1 - - return result - - -@hook_y_cable_simulator -def enable_loopback_mode(physical_port, target, lane_map): - """ - This API specifically configures and enables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - LaneMap specifies the lane configuration to run the loopback on. - - - Register Specification of upper page 0x5 at offset 153 is documented below - - Byte offset bits Name Description - 153 7-4 Reserved - 3 Lane 4 enable "Enable loopback generation on target lane 0b1 : - Enable, 0b0 disable.The cable supports 3 modes of operation : mission mode; PRBS mode or loopback mode. - Enabling loopback on any lane of any sides puts cable in loopback mode and disables PRBS. - 2 Lane 3 enable - 1 Lane 2 enable - 0 Lane 1 enable - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the target on which to enable the PRBS - EYE_PRBS_TARGET_LOCAL -> local side, - EYE_PRBS_TARGET_TOR1 -> TOR 1 - EYE_PRBS_TARGET_TOR2 -> TOR 2 - EYE_PRBS_TARGET_NIC -> NIC - lane_map: - an Integer, representing the lane_map to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011 , means running on lane0 and lane1 - - Returns: - a boolean, true if the enable is successful - , false if the enable failed - """ - - buffer = bytearray([target]) - curr_offset = OFFSET_TARGET - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([lane_map]) - curr_offset = OFFSET_ENABLE_LOOPBACK - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") - return -1 - - return result - - -@hook_y_cable_simulator -def disable_loopback_mode(physical_port, target): - """ - This API specifically disables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - - - Register Specification of upper page 0x5 at offset 153 is documented below - - Byte offset bits Name Description - 153 7-4 Reserved - 3 Lane 4 enable "Enable loopback generation on target lane 0b1 : - Enable, 0b0 disable.The cable supports 3 modes of operation : - mission mode; PRBS mode or loopback mode. - Enabling loopback on any lane of any sides puts cable in loopback mode and disables PRBS. - 2 Lane 3 enable - 1 Lane 2 enable - 0 Lane 1 enable - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the target on which to enable the PRBS - EYE_PRBS_TARGET_LOCAL -> local side, - EYE_PRBS_TARGET_TOR1 -> TOR 1 - EYE_PRBS_TARGET_TOR2 -> TOR 2 - EYE_PRBS_TARGET_NIC -> NIC - - Returns: - a boolean, true if the disable is successful - , false if the disable failed - """ - - buffer = bytearray([target]) - curr_offset = OFFSET_TARGET - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = OFFSET_ENABLE_LOOPBACK - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") - return -1 - - return result - - -@hook_y_cable_simulator -def get_ber_info(physical_port, target): - """ - This API specifically returns the BER (Bit error rate) value for a specfic port. - The target could be local side, TOR1, TOR2, NIC etc. - - - Register Specification of upper page 0x5 at offset 130 is documented below - - Byte offset bits Name Description - 130 1-0 Initiate BER Measurement "Write 0x00 - initiate gated BER measurement on target side with PRBS traffic - Write 0x01-0xFF - reserved - Read 0x00 - BER Gate in process - Read 0x01 - BER Gate complete, valid values in Lane BER registers - NB this command is only valid when PRBS has been enabled on at least one lane - The cable supports 3 modes of operation : mission mode; PRBS mode or loopback mode. - Enabling PRBS on any lane of any sides puts cable in PRBS mode and disables loopback and mission mode." - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the target on which to enable the PRBS - EYE_PRBS_TARGET_LOCAL -> local side, - EYE_PRBS_TARGET_TOR1 -> TOR 1 - EYE_PRBS_TARGET_TOR2 -> TOR 2 - EYE_PRBS_TARGET_NIC -> NIC - Returns: - a list, with BER values of lane 0 and lane 1 with corresponding index - """ - - buffer = bytearray([target]) - curr_offset = OFFSET_TARGET - - ber_result = [] - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = OFFSET_INITIATE_BER_MEASUREMENT - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - time_start = time.time() - while(True): - done = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) - if y_cable_validate_read_data(done, 1, physical_port, "BER data ready to read") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - time_now = time.time() - time_diff = time_now - time_start - if done[0] == 1: - break - elif time_diff >= BER_TIMEOUT_SECS: - return EEPROM_TIMEOUT_ERROR - - idx = 0 - curr_offset = OFFSET_LANE_1_BER_RESULT - for lane in range(MAX_NUM_LANES): - msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+idx, 1) - if y_cable_validate_read_data(msb_result, 1, physical_port, "BER data msb result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+1+idx, 1) - if y_cable_validate_read_data(lsb_result, 1, physical_port, "BER data lsb result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - lane_result = msb_result[0] * math.pow(10, (lsb_result[0]-24)) - ber_result.append(lane_result) - idx += 2 - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") - return -1 - - return ber_result - - -@hook_y_cable_simulator -def get_eye_info(physical_port, target): - """ - This API specifically returns the EYE height value for a specfic port. - The target could be local side, TOR1, TOR2, NIC etc. - - - Register Specification of upper page 0x5 at offset 144 is documented below - - Byte offset bits Name Description - 144 1-0 Initiate EYE Measurement "Write 0x00 - initiate gated eye height measurement on target side with any traffic (PRBS or mission mode) - Write 0x01-0xFF - reserved - Read 0x00 - Eye Height Measurement in process - Read 0x01 - Eye Height Gate complete, valid values in Eye Height Registers - NB this command can be issued whenever the side is linked, this does not interrupt mission mode traffic" R/W - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - target: - an Integer, the target on which to enable the PRBS - EYE_PRBS_TARGET_LOCAL -> local side, - EYE_PRBS_TARGET_TOR1 -> TOR 1 - EYE_PRBS_TARGET_TOR2 -> TOR 2 - EYE_PRBS_TARGET_NIC -> NIC - Returns: - a list, with EYE values of lane 0 and lane 1 with corresponding index - """ - - buffer = bytearray([target]) - curr_offset = OFFSET_TARGET - - eye_result = [] - - if platform_chassis is not None: - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - buffer = bytearray([0]) - curr_offset = OFFSET_INITIATE_EYE_MEASUREMENT - result = platform_chassis.get_sfp( - physical_port).write_eeprom(curr_offset, 1, buffer) - if result is False: - return result - - time_start = time.time() - while(True): - done = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) - if y_cable_validate_read_data(done, 1, physical_port, "EYE data ready to read") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - time_now = time.time() - time_diff = time_now - time_start - if done[0] == 1: - break - elif time_diff >= EYE_TIMEOUT_SECS: - return EEPROM_TIMEOUT_ERROR - - idx = 0 - for lane in range(MAX_NUM_LANES): - curr_offset = OFFSET_LANE_1_EYE_RESULT - msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+idx, 1) - if y_cable_validate_read_data(msb_result, 1, physical_port, "EYE data msb result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+1+idx, 1) - if y_cable_validate_read_data(lsb_result, 1, physical_port, "EYE data lsb result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - lane_result = (msb_result[0] << 8 | lsb_result[0]) - eye_result.append(lane_result) - idx += 2 - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") - return -1 - - return eye_result - - -@hook_y_cable_simulator -def get_part_number(physical_port): - """ - This API specifically returns the part number of the Y cable for a specfic port. - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - Returns: - a string, with part number - """ - - curr_offset = OFFSET_PART_NUMBER - - if platform_chassis is not None: - part_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 16) - if y_cable_validate_read_data(part_result, 16, physical_port, "Part number") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - else: - helper_logger.log_error("platform_chassis is not loaded, failed to get part number") - return -1 - - part_number = str(part_result.decode()) - - return part_number - - -@hook_y_cable_simulator -def get_vendor(physical_port): - """ - This API specifically returns the vendor name of the Y cable for a specfic port. - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - Returns: - a string, with vendor name - """ - - curr_offset = OFFSET_VENDOR_NAME - - if platform_chassis is not None: - result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 16) - if y_cable_validate_read_data(result, 16, physical_port, "Vendor name") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - else: - helper_logger.log_error("platform_chassis is not loaded, failed to get Vendor name") - return -1 - - vendor_name = str(result.decode()) - - return vendor_name - - -@hook_y_cable_simulator -def get_switch_count(physical_port, count_type): - """ - This API specifically returns the switch count to change the Active TOR which has - been done manually by the user. - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - count_type: - a string, for getting the count type - "manual" -> manual switch count - "auto" -> automatic switch count - Returns: - an integer, the number of times manually the Y-cable has been switched - """ - - if count_type == SWITCH_COUNT_MANUAL: - curr_offset = OFFSET_MANUAL_SWITCH_COUNT - elif count_type == SWITCH_COUNT_AUTO: - curr_offset = OFFSET_AUTO_SWITCH_COUNT - else: - helper_logger.log_error("not a valid count_type, failed to get switch count") - return -1 - - count = 0 - - if platform_chassis is not None: - msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) - if y_cable_validate_read_data(msb_result, 1, physical_port, "{} switch count msb result".format(count_type)) == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - msb_result_1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + 1, 1) - if y_cable_validate_read_data(msb_result_1, 1, physical_port, "{} switch count msb result 1".format(count_type)) == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - msb_result_2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + 2, 1) - if y_cable_validate_read_data(msb_result_2, 1, physical_port, "{} switch count msb result 2".format(count_type)) == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+3, 1) - if y_cable_validate_read_data(lsb_result, 1, physical_port, "{} switch count lsb result".format(count_type)) == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to get manual switch count") - return -1 - - return count - - -@hook_y_cable_simulator -def get_target_cursor_values(physical_port, lane, target): - """ - This API specifically returns the cursor equalization parameters for a target(NIC, TOR1, TOR2). - This includes pre one, pre two , main, post one, post two cursor values - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - target: - an Integer, the actual target to get the cursor values on - TARGET_NIC -> NIC, - TARGET_TOR1-> TOR1, - TARGET_TOR2 -> TOR2 - Returns: - an list, with pre one, pre two , main, post one, post two cursor values in the order - """ - - curr_offset = OFFSET_NIC_CURSOR_VALUES - - result = [] - - if platform_chassis is not None: - pre1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5, 1) - if y_cable_validate_read_data(pre1, 1, physical_port, "target cursor result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - result.append(c_int8(pre1[0]).value) - pre2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 1, 1) - if y_cable_validate_read_data(pre2, 1, physical_port, "target cursor result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - result.append(c_int8(pre2[0]).value) - main = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 2, 1) - if y_cable_validate_read_data(main, 1, physical_port, "target cursor result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - result.append(c_int8(main[0]).value) - post1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 3, 1) - if y_cable_validate_read_data(post1, 1, physical_port, "target cursor result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - result.append(c_int8(post1[0]).value) - post2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 4, 1) - if y_cable_validate_read_data(post2, 1, physical_port, "target cursor result") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - result.append(c_int8(post2[0]).value) - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") - return -1 - - return result - - -@hook_y_cable_simulator -def check_if_nic_lanes_active(physical_port): - """ - This API specifically returns the byte value which denotes which nic lanes - are detected and active - - Args: - physical_port: - an Integer, the actual physical port connected to a Y cable - Returns: - an integer, with lower 4 bits representing which lanes are active from 1, 2, 3, 4 - in that order. - """ - - curr_offset = OFFSET_NIC_LANE_ACTIVE - - result = None - - if platform_chassis is not None: - res = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) - if y_cable_validate_read_data(res, 1, physical_port, "nic lanes active") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - result = res[0] - - else: - helper_logger.log_error("platform_chassis is not loaded, failed to get NIC lanes active") - return -1 - - return result - - -@hook_y_cable_simulator -def get_firmware_version(physical_port, target): - - data = bytearray(FIRMWARE_INFO_PAYLOAD_SIZE) - - if platform_chassis is not None: - for byte_idx in range(0, FIRMWARE_INFO_PAYLOAD_SIZE): - curr_offset = 0xfc * 128 + 128 + byte_idx - read_out = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) - if y_cable_validate_read_data(read_out, 1, physical_port, "firmware info") == EEPROM_READ_DATA_INVALID: - return EEPROM_ERROR - data[byte_idx] = read_out[0] - else: - helper_logger.log_error("platform_chassis is not loaded, failed to get NIC lanes active") - return -1 - - result = {} - NUM_MCU_SIDE = 3 - - base_addr = int(target * (FIRMWARE_INFO_PAYLOAD_SIZE / NUM_MCU_SIDE)) - rev_major_slot1 = struct.unpack_from(' NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if the link is active - , False if the link is not active - """ - - raise NotImplementedError - - def get_eye_heights(self, target): - """ - This API returns the EYE height value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to get the eye: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with EYE values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - raise NotImplementedError - - - def get_vendor(self): - """ - This API returns the vendor name of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with vendor name - """ - - raise NotImplementedError - - def get_part_number(self): - """ - This API returns the part number of the Y cable for a specfic port. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a string, with part number - """ - - raise NotImplementedError - - def get_switch_count_total(self, switch_count_type, clear_on_read=False): - """ - This API returns the total switch count to change the Active TOR which has - been done manually/automatic by the user. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times the Y-cable has been switched - """ - - raise NotImplementedError - - def get_switch_count_tor_a(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR A - This is essentially all the successful switches initiated from ToR A. Toggles which were - initiated to toggle from ToR A and did not succeed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR A - """ - - raise NotImplementedError - - def get_switch_count_tor_b(self, clear_on_read=False): - """ - This API returns the switch count to change the Active TOR which has - been done manually by the user initiated from ToR B - This is essentially all the successful switches initiated from ToR B. Toggles which were - initiated to toggle from ToR B and did not succeed do not count. - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - - Returns: - an integer, the number of times the Y-cable has been switched from ToR B - """ - - raise NotImplementedError - - def get_switch_count_target(self, switch_count_type, target, clear_on_read=False): - """ - This API returns the total number of times the Active TOR has - been done manually/automaticlly toggled towards a target. - For example, TARGET_TOR_A as target would imply - how many times the mux has been toggled towards TOR A. - The port on which this API is called for can be referred using self.port. - - Args: - switch_count_type: - One of the following predefined constants, for getting the count type: - SWITCH_COUNT_MANUAL -> manual switch count - SWITCH_COUNT_AUTO -> automatic switch count - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - clear_on_read: - a boolean, True if the count has to be reset after read to zero - , False if the count is not to be reset after read - Returns: - an integer, the number of times manually the Y-cable has been switched - """ - - raise NotImplementedError - - def get_target_cursor_values(self, lane, target): - """ - This API returns the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two, main, post one, post two, post three cursor values - If any of the value is not available please return None for that filter - The port on which this API is called for can be referred using self.port. - - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a list, with pre one, pre two, main, post one, post two, post three cursor values in the order - """ - - raise NotImplementedError - - def set_target_cursor_values(self, lane, cursor_values, target): - """ - This API sets the cursor equalization parameters for a target(NIC, TOR_A, TOR_B). - This includes pre one, pre two, main, post one, post two etc. cursor values - The port on which this API is called for can be referred using self.port. - - Args: - lane: - an Integer, the lane on which to collect the cursor values - 1 -> lane 1, - 2 -> lane 2 - 3 -> lane 3 - 4 -> lane 4 - cursor_values: - a list, with pre one, pre two, main, post one, post two cursor, post three etc. values in the order - target: - One of the following predefined constants, the actual target to get the cursor values on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a boolean, True if cursor values setting is successful - , False if cursor values setting is not successful - """ - - raise NotImplementedError - - def get_firmware_version(self, target): - """ - This routine should return the active, inactive and next (committed) - firmware running on the target. Each of the version values in this context - could be a string with a major and minor number and a build value. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the firmware version on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - Returns: - a Dictionary: - with version_active, version_inactive and version_next keys - and their corresponding values - - """ - - raise NotImplementedError - - def download_firmware(self, fwfile): - """ - This routine should download and store the firmware on all the - components of the Y cable of the port for which this API is called.. - This should include any internal transfers, checksum validation etc. - from TOR to TOR or TOR to NIC side of the firmware specified by the fwfile. - This basically means that the firmware which is being downloaded should be - available to be activated (start being utilized by the cable) once this API is - successfully executed. - Note that this API should ideally not require any rollback even if it fails - as this should not interfere with the existing cable functionality because - this has not been activated yet. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile: - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable - Returns: - One of the following predefined constants: - FIRMWARE_DOWNLOAD_SUCCESS - FIRMWARE_DOWNLOAD_FAILURE - - a predefined code stating whether the firmware download was successful - or an error code as to what was the cause of firmware download failure - """ - - raise NotImplementedError - - def activate_firmware(self, fwfile=None, hitless=False): - """ - This routine should activate the downloaded firmware on all the - components of the Y cable of the port for which this API is called.. - This API is meant to be used in conjunction with download_firmware API, and - should be called once download_firmware API is succesful. - This means that the firmware which has been downloaded should be - activated (start being utilized by the cable) once this API is - successfully executed. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in activate_firmware, the API should - have the logic to retreive the firmware version from this file - which has to be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should activate whatever - firmware is marked to be activated next. - If provided, it should retreive the firmware version(s) from this file, ensure - they are downloaded on the cable, then activate them. - - hitless (optional): - a boolean, True, Hitless upgrade: it will backup/restore the current state - (ex. variables of link status, API attributes...etc.) before - and after firmware upgrade. - a boolean, False, Non-hitless upgrade: it will update the firmware regardless - the current status, a link flip can be observed during the upgrade. - Returns: - One of the following predefined constants: - FIRMWARE_ACTIVATE_SUCCESS - FIRMWARE_ACTIVATE_FAILURE - """ - - raise NotImplementedError - - def rollback_firmware(self, fwfile=None): - """ - This routine should rollback the firmware to the previous version - which was being used by the cable. This API is intended to be called when the - user either witnesses an activate_firmware API failure or sees issues with - newer firmware in regards to stable cable functioning. - The port on which this API is called for can be referred using self.port. - - Args: - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in rollback_firmware, the API should - have the logic to retreive the firmware version from this file - which should not be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should rollback whatever - firmware is marked to be rollback next. - If provided, it should retreive the firmware version(s) from this file, ensure - that the firmware is rollbacked to a version which does not match to retreived version(s). - This is exactly the opposite behavior of this param to activate_firmware - Returns: - One of the following predefined constants: - FIRMWARE_ROLLBACK_SUCCESS - FIRMWARE_ROLLBACK_FAILURE - """ - - raise NotImplementedError - - def set_switching_mode(self, mode): - """ - This API enables the auto switching or manual switching feature on the Y-Cable, - depending upon the mode entered by the user. - Autoswitch feature if enabled actually does an automatic toggle of the mux in case the active - side link goes down and basically points the mux to the other side. - The port on which this API is called for can be referred using self.port. - - Args: - mode: - One of the following predefined constants: - SWITCHING_MODE_AUTO - SWITCHING_MODE_MANUAL - - specifies which type of switching mode we set the Y-Cable to - either SWITCHING_MODE_AUTO or SWITCHING_MODE_MANUAL - - Returns: - a Boolean, True if the switch succeeded and False if it did not succeed. - """ - - raise NotImplementedError - - def get_switching_mode(self): - """ - This API returns which type of switching mode the cable is set to auto/manual - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - One of the following predefined constants: - SWITCHING_MODE_AUTO if auto switch is enabled. - SWITCHING_MODE_MANUAL if manual switch is enabled. - """ - - raise NotImplementedError - - def get_nic_temperature(self): - """ - This API returns nic temperature of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - an Integer, the temperature of the NIC MCU - """ - - raise NotImplementedError - - def get_local_temperature(self): - """ - This API returns local ToR temperature of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - an Integer, the temperature of the local MCU - """ - - raise NotImplementedError - - def get_nic_voltage(self): - """ - This API returns nic voltage of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a float, the voltage of the NIC MCU - """ - - raise NotImplementedError - - def get_local_voltage(self): - """ - This API returns local ToR voltage of the physical port for which this API is called. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a float, the voltage of the local MCU - """ - - raise NotImplementedError - - def get_alive_status(self): - """ - This API checks if cable is connected to all the ports and is healthy. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a boolean, True if the cable is alive - , False if the cable is not alive - """ - - raise NotImplementedError - - def reset(self, target): - """ - This API resets the MCU to which this API is called for. - The target specifies which MCU is supposed to be reset - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to check the link on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if the cable is target reset - , False if the cable target is not reset - """ - - raise NotImplementedError - - def create_port(self, speed, fec_mode_tor=FEC_MODE_NONE, fec_mode_nic= FEC_MODE_NONE, anlt_tor=False, anlt_nic=False): - """ - This API sets the mode of the cable/port for corresponding lane/FEC etc. configuration as specified. - The speed specifies which mode is supposed to be set 50G, 100G etc - the AN/LT specifies if auto-negotiation + link training (AN/LT) has to be enabled - Note that in case create_port is called multiple times, the most recent api call will take the precedence - on either of TOR side. - The port on which this API is called for can be referred using self.port. - - Args: - speed: - an Integer, the value for the link speed to be configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - - fec_mode_tor: - One of the following predefined constants, the actual FEC mode for the ToR to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - - fec_mode_nic: - One of the following predefined constants, the actual FEC mode for the nic to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - - anlt_tor: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on ToR's - , False if auto-negotiation + link training (AN/LT) is not to be enabled on ToR's - - anlt_nic: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on nic - , False if auto-negotiation + link training (AN/LT) is not to be enabled on nic - - - Returns: - a boolean, True if the port is configured - , False if the port is not configured - """ - - raise NotImplementedError - - def get_speed(self): - """ - This API gets the mode of the cable for corresponding lane configuration. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - speed: - an Integer, the value for the link speed is configured (in megabytes). - examples: - 50000 -> 50G - 100000 -> 100G - """ - - raise NotImplementedError - - def set_fec_mode(self, fec_mode, target): - """ - This API gets the FEC mode of the cable for which it is set to. - The port on which this API is called for can be referred using self.port. - - Args: - fec_mode: - One of the following predefined constants, the actual FEC mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - target: - One of the following predefined constants, the actual target to set the FEC mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - - Returns: - a boolean, True if the FEC mode is configured - , False if the FEC mode is not configured - """ - - raise NotImplementedError - - def get_fec_mode(self, target): - """ - This API gets the FEC mode of the cable which it is set to. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to FEC mode on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - fec_mode: - One of the following predefined constants, the actual FEC mode for the port to be configured: - FEC_MODE_NONE, - FEC_MODE_RS, - FEC_MODE_FC - """ - - raise NotImplementedError - - def set_anlt(self, enable, target): - """ - This API enables/disables the cable auto-negotiation + link training (AN/LT). - The port on which this API is called for can be referred using self.port. - - Args: - enable: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled - , False if auto-negotiation + link training (AN/LT) is not to be enabled - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - - Returns: - a boolean, True if the auto-negotiation + link training (AN/LT) enable/disable specified is configured - , False if the auto-negotiation + link training (AN/LT) enable/disable specified is not configured - """ - - raise NotImplementedError - - def get_anlt(self, target): - """ - This API gets the auto-negotiation + link training (AN/LT) mode of the cable for corresponding port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the AN/LT on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if auto-negotiation + link training (AN/LT) is enabled - , False if auto-negotiation + link training (AN/LT) is not enabled - """ - - raise NotImplementedError - - def get_event_log(self, clear_on_read=False): - """ - This API returns the event log of the cable - The port on which this API is called for can be referred using self.port. - - Args: - clear_on_read: - a boolean, True if the log has to be cleared after read - , False if the log is not to be cleared after read - - Returns: - list: - a list of strings which correspond to the event logs of the cable - """ - - raise NotImplementedError - - def get_pcs_stats(self, target): - """ - This API returns the pcs statistics of the cable - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - raise NotImplementedError - - def get_fec_stats(self, target): - """ - This API returns the FEC statistics of the cable - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get the stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - raise NotImplementedError - - def set_autoswitch_hysteresis_timer(self, time): - """ - This API sets the hysteresis timer of the cable. This is basically the time in auto-switch mode - which the mux has to wait after toggling it once, before again toggling the mux to a different ToR - The port on which this API is called for can be referred using self.port. - - Args: - time: - an Integer, the time value for hysteresis to be set in milliseconds - - Returns: - a boolean, True if the time is configured - , False if the time is not configured - """ - - raise NotImplementedError - - def get_autoswitch_hysteresis_timer(self): - """ - This API gets the hysteresis timer of the cable. This is basically the time in auto-switch mode - which the mux has to wait after toggling it once, before again toggling the mux to a different ToR - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - time: - an Integer, the time value for hysteresis is configured in milliseconds - """ - - raise NotImplementedError - - def restart_anlt(self, target): - """ - This API restarts auto-negotiation + link training (AN/LT) mode - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to restart AN/LT on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a boolean, True if restart is successful - , False if the restart is not successful - """ - - raise NotImplementedError - - def get_anlt_stats(self, target): - """ - This API returns auto-negotiation + link training (AN/LT) mode statistics - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to get AN/LT stats on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - - Returns: - a dictionary: - a detailed format agreed upon by vendors - """ - - raise NotImplementedError - -############################################################################################# -### Debug Functionality ### -############################################################################################# - - def set_debug_mode(self, enable): - """ - This API enables/disables a debug mode that the port is now - going to be run on. If enabled, this means that PRBS/Loopback etc. type diagnostic mode - is now going to be run on the port and hence normal traffic will be disabled - on it if enabled and vice-versa if disabled. - enable is typically to be used at the software level to inform the software - that debug APIs will be called afterwords. - disable will disable any previously enabled debug functionality inside the cable - so that traffic can pass through. Also it'll inform the software to come out of the debug mode. - The port on which this API is called for can be referred using self.port. - - Args: - enable: - a boolean, True if the debug mode needs to be enabled - , False if the debug mode needs to be disabled - - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - raise NotImplementedError - - def get_debug_mode(self): - """ - This API checks if a debug mode is currently being run on the port - for which this API is called for. - This means that PRBS/Loopback etc. type diagnostic mode - if any are being run on the port this should return True else False. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a boolean, True if debug mode enabled - , False if debug mode not enabled - """ - - raise NotImplementedError - - def enable_prbs_mode(self, target, mode_value, lane_mask, direction=PRBS_DIRECTION_BOTH): - """ - This API configures and enables the PRBS mode/type depending upon the mode_value the user provides. - The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. - Target is an integer for selecting which end of the Y cable we want to run PRBS on. - LaneMap specifies the lane configuration to run the PRBS on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to enable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - an Integer, the mode/type for configuring the PRBS mode. - - lane_mask: - an Integer, representing the lane_mask to be run PRBS on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011, means running on lane0 and lane1 - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - - """ - - raise NotImplementedError - - def disable_prbs_mode(self, target, direction=PRBS_DIRECTION_BOTH): - """ - This API disables the PRBS mode on the physical port. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the PRBS: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - direction: - One of the following predefined constants, the direction to run the PRBS: - PRBS_DIRECTION_BOTH - PRBS_DIRECTION_GENERATOR - PRBS_DIRECTION_CHECKER - - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - raise NotImplementedError - - def enable_loopback_mode(self, target, lane_mask, mode=LOOPBACK_MODE_NEAR_END): - """ - This API configures and enables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - LaneMap specifies the lane configuration to run the loopback on. - Note that this is a diagnostic mode command and must not run during normal traffic/switch operation - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to enable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - lane_mask: - an Integer, representing the lane_mask to be run loopback on - 0bit for lane 0, 1bit for lane1 and so on. - for example 3 -> 0b'0011, means running on lane0 and lane1 - - Returns: - a boolean, True if the enable is successful - , False if the enable failed - """ - - raise NotImplementedError - - def disable_loopback_mode(self, target): - """ - This API disables the Loopback mode on the port user provides. - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - - Returns: - a boolean, True if the disable is successful - , False if the disable failed - """ - - raise NotImplementedError - - def get_loopback_mode(self, target): - """ - This API returns the Loopback mode on the port which it has been configured to - Target is an integer for selecting which end of the Y cable we want to run loopback on. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to disable the loopback: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - - Returns: - mode_value: - One of the following predefined constants, the mode to be run for loopback: - LOOPBACK_MODE_NONE - LOOPBACK_MODE_NEAR_END - LOOPBACK_MODE_FAR_END - """ - - raise NotImplementedError - - def get_ber_info(self, target): - """ - This API returns the BER (Bit error rate) value for a specfic port. - The target could be local side, TOR_A, TOR_B, NIC etc. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the target on which to get the BER: - EYE_PRBS_LOOPBACK_TARGET_LOCAL -> local side, - EYE_PRBS_LOOPBACK_TARGET_TOR_A -> TOR A - EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B - EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - Returns: - a list, with BER values of lane 0 lane 1 lane 2 lane 3 with corresponding index - """ - - raise NotImplementedError - - - def debug_dump_registers(self, option=None): - """ - This API should dump all registers with meaningful values - for the cable to be diagnosed for proper functioning. - This means that for all the fields on relevant vendor-specific pages - this API should dump the appropriate fields with parsed values - which would help debug the Y-Cable - - Args: - option: - a string, the option param can be a string which if passed can help a vendor utilize it - as an input param or a concatenation of params for a function which they can call internally. - This essentially helps if the vendor chooses to dump only some of the registers instead of all - the registers, and thus provides more granularity for debugging/printing. - For example, the option can serdes_lane0, in this case the vendor would just dump - registers related to serdes lane 0. - - - Returns: - a Dictionary: - with all the relevant key-value pairs for all the meaningful fields - which would help diagnose the cable for proper functioning - """ - - raise NotImplementedError - - def queue_info(self): - """ - This API should dump all the meaningful data from the eeprom which can - help vendor debug the queue info for the UART stats in particular - currently relevant to the MCU - using this API the vendor could check how many txns are currently waiting to be processed,proceessed - in the queue etc for debugging purposes - - Args: - None - - Returns: - a Dictionary: - with all the relevant key-value pairs for all the meaningful fields - for the queue inside the MCU firmware - which would help diagnose the cable for proper functioning - """ - - raise NotImplementedError - - def reset_cause(self): - """ - This API should return the reset cause for the NIC MCU. - This should help ascertain whether a reset was caused by soft reboot or - cable poweroff - - Args: - None - - Returns: - a string: - the string should be self explnatory as to what was the cause of reset - - """ - raise NotImplementedError - - def operation_time(self): - """ - This API should return the time since the cable is powered on from NIC MCU side - This should be helpful in debugging purposes as to if/when the cable has been powered on - - Args: - None - - Returns: - a float: - the float should represent how much time the mux cable is alive/powered on - """ - - raise NotImplementedError - - def mem_read(self, target, addr, length): - """ - This API should return the memory contents of the cable which would be useful in debug for the - y-cable - - Args: - target: - local (TOR) or remote (NIC) MCU - addr: - the starting address of the MCU's memory space - length: - length to be read, unit: byte - - Returns: - a Bytearray: - the contents of the memory inside the MCU firmware - which would help diagnose the cable for proper functioning - """ - - raise NotImplementedError - - def activate_target_firmware(self, target, fwfile=None, hitless=False): - """ - This routine should activate the downloaded firmware on all the target - of the Y cable of the port for which this API is called.. - This API is meant to be used in conjunction with download_firmware API, and - should be called once download_firmware API is succesful. - This means that the firmware which has been downloaded should be - activated (start being utilized by the cable) once this API is - successfully executed. - The port on which this API is called for can be referred using self.port. - - Args: - target: - One of the following predefined constants, the actual target to activate the firmware on: - TARGET_NIC -> NIC, - TARGET_TOR_A -> TORA, - TARGET_TOR_B -> TORB - fwfile (optional): - a string, a path to the file which contains the firmware image. - Note that the firmware file can be in the format of the vendor's - choosing (binary, archive, etc.). But note that it should be one file - which contains firmware for all components of the Y-cable. In case the - vendor chooses to pass this file in activate_firmware, the API should - have the logic to retreive the firmware version from this file - which has to be activated on the components of the Y-Cable - this API has been called for. - If None is passed for fwfile, the cable should activate whatever - firmware is marked to be activated next. - If provided, it should retreive the firmware version(s) from this file, ensure - they are downloaded on the cable, then activate them. - - hitless (optional): - a boolean, True, Hitless upgrade: it will backup/restore the current state - (ex. variables of link status, API attributes...etc.) before - and after firmware upgrade. - a boolean, False, Non-hitless upgrade: it will update the firmware regardless - the current status, a link flip can be observed during the upgrade. - Returns: - One of the following predefined constants: - FIRMWARE_ACTIVATE_SUCCESS - FIRMWARE_ACTIVATE_FAILURE - """ - - raise NotImplementedError - - def health_check(self): - """ - This API checks the health of the cable, where it is healthy/unhealythy for RMA purposes/diagnostics. - The port on which this API is called for can be referred using self.port. - - Args: - - Returns: - a Boolean, True if the cable is healthy and False if it is not healthy. - """ - - raise NotImplementedError diff --git a/sonic_y_cable/y_cable_vendor_mapping.py b/sonic_y_cable/y_cable_vendor_mapping.py deleted file mode 100644 index b2529677a..000000000 --- a/sonic_y_cable/y_cable_vendor_mapping.py +++ /dev/null @@ -1,30 +0,0 @@ -mapping = { - "credo": { - "cacl05321p2pa1ms": "credo.y_cable_credo", - "cacl1x321p2pa1ms": "credo.y_cable_credo", - "cacl15321p2pa1ms": "credo.y_cable_credo", - "cacl2x321p2pa1ms": "credo.y_cable_credo", - - "cac105321p2pa2ms": "credo.y_cable_credo", - "cac11x321p2pa2ms": "credo.y_cable_credo", - "cac115321p2pa2ms": "credo.y_cable_credo", - "cac12x321p2pa2ms": "credo.y_cable_credo" - }, - "molex": { - "2164351001": "broadcom.y_cable_broadcom", - "2164351002": "broadcom.y_cable_broadcom", - "2164351003": "broadcom.y_cable_broadcom", - "2164351004": "broadcom.y_cable_broadcom", - "2164352001": "broadcom.y_cable_broadcom", - "2164352002": "broadcom.y_cable_broadcom", - "2164352003": "broadcom.y_cable_broadcom", - "2164352004": "broadcom.y_cable_broadcom", - "2164352501": "broadcom.y_cable_broadcom", - "2164352502": "broadcom.y_cable_broadcom", - "2164352503": "broadcom.y_cable_broadcom", - "2164352504": "broadcom.y_cable_broadcom" - }, - "microsoft": { - "simulated": "microsoft.y_cable_simulated" - } -} diff --git a/tests/0/port_config.ini b/tests/0/port_config.ini deleted file mode 100644 index 4fb083de5..000000000 --- a/tests/0/port_config.ini +++ /dev/null @@ -1,7 +0,0 @@ -# name lanes alias index -Ethernet0 29,30,31,32 fortyGigE0/0 1 -Ethernet4 25,26,27,28 fortyGigE0/4 2 -Ethernet8 37,38,39,40 fortyGigE0/8 3 -Ethernet12 33,34,35,36 fortyGigE0/12 4 -Ethernet16 41,42,43,44 fortyGigE0/16 5 -Ethernet20 45,46,47,48 fortyGigE0/20 6 diff --git a/tests/1/port_config.ini b/tests/1/port_config.ini deleted file mode 100644 index 01f154659..000000000 --- a/tests/1/port_config.ini +++ /dev/null @@ -1,8 +0,0 @@ -# name lanes alias index -Ethernet24 5,6,7,8 fortyGigE0/24 7 -Ethernet28 1,2,3,4 fortyGigE0/28 8 -Ethernet32 9,10,11,12 fortyGigE0/32 9 -Ethernet36 13,14,15,16 fortyGigE0/36 10 -Ethernet40 21,22,23,24 fortyGigE0/40 11 -Ethernet44 17,18,19,20 fortyGigE0/44 12 -Ethernet48 49,50,51,52 fortyGigE0/48 13 diff --git a/tests/chassis_base_test.py b/tests/chassis_base_test.py deleted file mode 100644 index c2f2e5f97..000000000 --- a/tests/chassis_base_test.py +++ /dev/null @@ -1,18 +0,0 @@ -from sonic_platform_base.chassis_base import ChassisBase - -class TestChassisBase: - - def test_reboot_cause(self): - chassis = ChassisBase() - assert(chassis.REBOOT_CAUSE_POWER_LOSS == "Power Loss") - assert(chassis.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU == "Thermal Overload: CPU") - assert(chassis.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC == "Thermal Overload: ASIC") - assert(chassis.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER == "Thermal Overload: Other") - assert(chassis.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED == "Insufficient Fan Speed") - assert(chassis.REBOOT_CAUSE_WATCHDOG == "Watchdog") - assert(chassis.REBOOT_CAUSE_HARDWARE_OTHER == "Hardware - Other") - assert(chassis.REBOOT_CAUSE_HARDWARE_BIOS == "BIOS") - assert(chassis.REBOOT_CAUSE_HARDWARE_CPU == "CPU") - assert(chassis.REBOOT_CAUSE_HARDWARE_BUTTON == "Push button") - assert(chassis.REBOOT_CAUSE_HARDWARE_RESET_FROM_ASIC == "Reset from ASIC") - assert(chassis.REBOOT_CAUSE_NON_HARDWARE == "Non-Hardware") diff --git a/tests/eeprom_base_test.py b/tests/eeprom_base_test.py deleted file mode 100644 index 0328ae2c3..000000000 --- a/tests/eeprom_base_test.py +++ /dev/null @@ -1,169 +0,0 @@ -import os -import subprocess -from unittest import mock -from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo -EEPROM_SYMLINK = "vpd_info" -EEPROM_HEX_FILE = "syseeprom.hex" -TEST_PATH = os.path.dirname(os.path.abspath(__file__)) -EEPROM_HEX_FILE_FULL_PATH = os.path.join(TEST_PATH, EEPROM_HEX_FILE) -EEPROM_SYMLINK_FULL_PATH = os.path.join(TEST_PATH, EEPROM_SYMLINK) -class TestEepromTlvinfo: - - @classmethod - def setup_class(cls): - """ - Use a HEX file to generate a mock eeprom, the decoded content of the eeprom is like below: - - TlvInfo Header: - Id String: TlvInfo - Version: 1 - Total Length: 527 - TLV Name Code Len Value - -------------------- ---- --- ----- - Product Name 0x21 64 MSN2700 - Part Number 0x22 20 MSN2700-CS2FO - Serial Number 0x23 24 MT1623X09522 - Base MAC Address 0x24 6 7C:FE:90:F5:36:40 - Manufacture Date 0x25 19 06/10/2016 01:57:31 - Device Version 0x26 1 0 - MAC Addresses 0x2A 2 128 - Manufacturer 0x2B 8 Mellanox - Platform Name 0x28 18 x86_64-mlnx_x86-r0 - ONIE Version 0x29 21 2018.05-5.2.0004-9600 - CRC-32 0xFE 4 0x89D74C56 - - """ - if not os.path.exists(os.path.dirname(EEPROM_HEX_FILE_FULL_PATH)): - assert False, "File {} is not exist".format(EEPROM_HEX_FILE_FULL_PATH) - subprocess.check_call(['/usr/bin/xxd', '-r', '-p', EEPROM_HEX_FILE_FULL_PATH, EEPROM_SYMLINK_FULL_PATH]) - - @classmethod - def teardown_class(cls): - # Remove the mock eeprom after test - if os.path.exists(os.path.dirname(EEPROM_HEX_FILE_FULL_PATH)): - subprocess.check_call(['rm', '-f', EEPROM_SYMLINK_FULL_PATH]) - - def test_eeprom_tlvinfo_read_api(self): - # Test using the api to fetch Base MAC, Switch Addr Range, Model, - # Serial Number and Part Number. - eeprom_class = eeprom_tlvinfo.TlvInfoDecoder(EEPROM_SYMLINK_FULL_PATH, 0, '', True) - eeprom = eeprom_class.read_eeprom() - eeprom_class.decode_eeprom(eeprom) - assert(eeprom_class.base_mac_addr(eeprom).rstrip('\0') == '7C:FE:90:F5:36:40') - assert(eeprom_class.switchaddrrange(eeprom).rstrip('\0') == '128') - assert(eeprom_class.modelstr(eeprom).rstrip('\0') == 'MSN2700') - assert(eeprom_class.serial_number_str(eeprom).rstrip('\0') == 'MT1623X09522') - assert(eeprom_class.part_number_str(eeprom).rstrip('\0') == 'MSN2700-CS2FO') - - def test_eeprom_tlvinfo_get_tlv_field(self): - # Test getting fields by field code - eeprom_class = eeprom_tlvinfo.TlvInfoDecoder(EEPROM_SYMLINK_FULL_PATH, 0, '', True) - eeprom = eeprom_class.read_eeprom() - (is_valid, t) = eeprom_class.get_tlv_field(eeprom, eeprom_class._TLV_CODE_MANUF_DATE) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == '06/10/2016 01:57:31') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom, eeprom_class._TLV_CODE_MANUF_NAME) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'Mellanox') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom, eeprom_class._TLV_CODE_PLATFORM_NAME) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'x86_64-mlnx_x86-r0') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom, eeprom_class._TLV_CODE_ONIE_VERSION) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == '2018.05-5.2.0004-9600') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom, 0xFF) - assert(not is_valid) - - def test_eeprom_tlvinfo_set_eeprom(self): - eeprom_class = eeprom_tlvinfo.TlvInfoDecoder(EEPROM_SYMLINK_FULL_PATH, 0, '', True) - eeprom = eeprom_class.read_eeprom() - - # Test updating existing fields - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x21 = MSN3700']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x21) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'MSN3700') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x22 = MSN3700-CS2FO']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x22) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'MSN3700-CS2FO') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x23 = MT1234567890']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x23) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'MT1234567890') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x24 = FF:FF:FF:FF:FF:FF']) - assert(eeprom_class.base_mac_addr(eeprom_new).rstrip('\0') == 'FF:FF:FF:FF:FF:FF') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x25 = 11/11/1111 11:11:11']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x25) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == '11/11/1111 11:11:11') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x26 = 11']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x26) - assert(is_valid and str(ord(t[2])) == '11') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x2A = 129']) - assert(eeprom_class.switchaddrrange(eeprom_new).rstrip('\0') == '129') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x2B = Nvidia']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2B) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'Nvidia') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x28 = x86_64-nvidia_x86-r0']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x28) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'x86_64-nvidia_x86-r0') - - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x29 = 2022.05-5.2.0004-115200']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x29) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == '2022.05-5.2.0004-115200') - - # Test adding none-existing fields - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x27) - assert(not is_valid) - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x27 = B2']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x27) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'B2') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2F) - assert(not is_valid) - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x2F = service_tag']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2F) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'service_tag') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2C) - assert(not is_valid) - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x2C = CN']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2C) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'CN') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2D) - assert(not is_valid) - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x2D = NVDIA']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2D) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'NVDIA') - - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2E) - assert(not is_valid) - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x2E = A2']) - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x2E) - assert(is_valid and t[2].decode("ascii").rstrip('\0') == 'A2') - - # Test adding invalid field - (is_valid, t) = eeprom_class.get_tlv_field(eeprom_new, 0x20) - assert(not is_valid) - with mock.patch('builtins.exit') as exit_mock: - eeprom_new = eeprom_class.set_eeprom(eeprom, ['0x20 = Invalid']) - assert exit_mock.called - - def test_eeprom_tlvinfo_update_eeprom_db(self): - # Test updating eeprom to DB by mocking redis hmset - eeprom_class = eeprom_tlvinfo.TlvInfoDecoder(EEPROM_SYMLINK_FULL_PATH, 0, '', True) - eeprom = eeprom_class.read_eeprom() - eeprom_class.redis_client.hmset = mock.MagicMock(return_value = True) - assert(0 == eeprom_class.update_eeprom_db(eeprom)) - - def test_eeprom_tlvinfo_read_eeprom_db(self): - # Test reading from DB by mocking redis hget - eeprom_class = eeprom_tlvinfo.TlvInfoDecoder(EEPROM_SYMLINK_FULL_PATH, 0, '', True) - eeprom_class.redis_client.hget = mock.MagicMock(return_value = b'1') - assert(0 == eeprom_class.read_eeprom_db()) diff --git a/tests/mock_periph.py b/tests/mock_periph.py new file mode 100644 index 000000000..3d54d7ffe --- /dev/null +++ b/tests/mock_periph.py @@ -0,0 +1,18 @@ +class MockDevice: + def __init__(self): + self.name = None + self.presence = True + self.model = 'Module Model' + self.serial = 'Module Serial' + + def get_name(self): + return self.name + + def get_presence(self): + return self.presence + + def get_model(self): + return self.model + + def get_serial(self): + return self.serial \ No newline at end of file diff --git a/tests/pcie_common_test.py b/tests/pcie_common_test.py deleted file mode 100644 index 9334584b9..000000000 --- a/tests/pcie_common_test.py +++ /dev/null @@ -1,214 +0,0 @@ -import os -import sys -import yaml -from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil - -if sys.version_info.major == 3: - from unittest import mock - BUILTINS = 'builtins' -else: - import mock - BUILTINS = '__builtin__' - -tests_dir = os.path.dirname(os.path.abspath(__file__)) -pcie_config_file = os.path.join(tests_dir, 'pcie.yaml') - -lspci_output = '''\ -00:01.0 PCI A -00:02.0 PCI B -00:02.1 PCI C -01:00.0 PCI D -''' - -lspci_ID_output = '''\ -00:01.0 0001: 0000:000a -00:02.0 0002: 0000:000b -00:02.1 0003: 0000:000c -01:00.0 0004: 0000:000d -''' - -pci_sysfs_paths = [ - '/sys/bus/pci/devices/0000:00:01.0', - '/sys/bus/pci/devices/0000:00:02.0', - '/sys/bus/pci/devices/0000:00:02.1', - '/sys/bus/pci/devices/0000:01:00.0' -] - -pcie_device_list = [ - {'bus': '00', 'dev': '01', 'fn': '0', 'id': '000a', 'name': 'PCI A'}, - {'bus': '00', 'dev': '02', 'fn': '0', 'id': '000b', 'name': 'PCI B'}, - {'bus': '00', 'dev': '02', 'fn': '1', 'id': '000c', 'name': 'PCI C'}, - {'bus': '01', 'dev': '00', 'fn': '0', 'id': '000d', 'name': 'PCI D'}, -] - -pcie_check_output = [ - {'bus': '00', 'dev': '01', 'fn': '0', 'id': '000a', 'name': 'PCI A', 'result': 'Passed'}, - {'bus': '00', 'dev': '02', 'fn': '0', 'id': '000b', 'name': 'PCI B', 'result': 'Passed'}, - {'bus': '00', 'dev': '02', 'fn': '1', 'id': '000c', 'name': 'PCI C', 'result': 'Passed'}, - {'bus': '01', 'dev': '00', 'fn': '0', 'id': '000d', 'name': 'PCI D', 'result': 'Passed'} -] - -pcie_aer_correctable_content = '''\ -RxErr 0 -BadTLP 1 -BadDLLP 2 -Rollover 3 -Timeout 4 -NonFatalErr 5 -CorrIntErr 6 -HeaderOF 7 -TOTAL_ERR_COR 28 -''' - -pcie_aer_fatal_content = '''\ -Undefined 0 -DLP 1 -SDES 2 -TLP 3 -FCP 4 -CmpltTO 5 -CmpltAbrt 6 -UnxCmplt 7 -RxOF 8 -MalfTLP 9 -ECRC 0 -UnsupReq 1 -ACSViol 2 -UncorrIntErr 3 -BlockedTLP 4 -AtomicOpBlocked 5 -TLPBlockedErr 6 -TOTAL_ERR_FATAL 66 -''' - -pcie_aer_nonfatal_content = '''\ -Undefined 0 -DLP 1 -SDES 2 -TLP 3 -FCP 4 -CmpltTO 5 -CmpltAbrt 6 -UnxCmplt 7 -RxOF 8 -MalfTLP 9 -ECRC 0 -UnsupReq 1 -ACSViol 2 -UncorrIntErr 3 -BlockedTLP 4 -AtomicOpBlocked 5 -TLPBlockedErr 6 -TOTAL_ERR_NONFATAL 66 -''' - -pcie_aer_stats = { - 'correctable': { - 'RxErr': '0', 'BadTLP': '1', 'BadDLLP': '2', 'Rollover': '3', - 'Timeout': '4', 'NonFatalErr': '5', 'CorrIntErr': '6', 'HeaderOF': '7', - 'TOTAL_ERR_COR': '28' - }, - 'fatal': { - 'Undefined': '0', 'DLP': '1', 'SDES': '2', 'TLP': '3', 'FCP': '4', - 'CmpltTO': '5', 'CmpltAbrt': '6', 'UnxCmplt': '7', 'RxOF': '8', - 'MalfTLP': '9', 'ECRC': '0', 'UnsupReq': '1', 'ACSViol': '2', - 'UncorrIntErr': '3', 'BlockedTLP': '4', 'AtomicOpBlocked': '5', - 'TLPBlockedErr': '6', 'TOTAL_ERR_FATAL': '66' - }, - 'non_fatal': { - 'Undefined': '0', 'DLP': '1', 'SDES': '2', 'TLP': '3', 'FCP': '4', - 'CmpltTO': '5', 'CmpltAbrt': '6', 'UnxCmplt': '7', 'RxOF': '8', - 'MalfTLP': '9', 'ECRC': '0', 'UnsupReq': '1', 'ACSViol': '2', - 'UncorrIntErr': '3', 'BlockedTLP': '4', 'AtomicOpBlocked': '5', - 'TLPBlockedErr': '6', 'TOTAL_ERR_NONFATAL': '66' - }, -} - - -class TestPcieCommon: - - @mock.patch('subprocess.Popen') - def test_get_pcie_devices(self, subprocess_popen_mock): - - def subprocess_popen_side_effect(*args, **kwargs): - if args[0] == ['sudo', 'lspci']: - output = lspci_output.splitlines() - elif args[0] == ['sudo', 'lspci', '-n']: - output = lspci_ID_output.splitlines() - - popen_mock = mock.Mock() - popen_attributes = { - 'returncode': 0, - 'communicate.return_value': ('', ''), - 'stdout.readlines.return_value': output - } - popen_mock.configure_mock(**popen_attributes) - return popen_mock - - subprocess_popen_mock.side_effect = subprocess_popen_side_effect - pcieutil = PcieUtil(tests_dir) - result = pcieutil.get_pcie_device() - assert result == pcie_device_list - - @mock.patch('os.path.exists') - def test_get_pcie_check(self, os_path_exists_mock): - - def os_path_exists_side_effect(*args): - return bool(args[0] in pci_sysfs_paths) - - os_path_exists_mock.side_effect = os_path_exists_side_effect - pcieutil = PcieUtil(tests_dir) - sample_pcie_config = yaml.dump(pcie_device_list) - - open_mock = mock.mock_open(read_data=sample_pcie_config) - with mock.patch('{}.open'.format(BUILTINS), open_mock): - result = pcieutil.get_pcie_check() - open_mock.assert_called_once_with(pcie_config_file) - assert result == pcie_check_output - - @mock.patch('os.path.isfile', mock.MagicMock(return_value=True)) - @mock.patch('{}.open'.format(BUILTINS)) - def test_get_pcie_aer_stats(self, open_mock): - - def open_mock_side_effect(*args): - file_content = '' - if os.path.dirname(args[0]) == pci_sysfs_paths[0]: - file_name = os.path.basename(args[0]) - if file_name == 'aer_dev_correctable': - file_content = pcie_aer_correctable_content - elif file_name == 'aer_dev_fatal': - file_content = pcie_aer_fatal_content - elif file_name == 'aer_dev_nonfatal': - file_content = pcie_aer_nonfatal_content - - return mock.mock_open(read_data=file_content).return_value - - open_mock.side_effect = open_mock_side_effect - pcieutil = PcieUtil(tests_dir) - test_device = pcie_device_list[0] - result = pcieutil.get_pcie_aer_stats(bus=int(test_device['bus']), - dev=int(test_device['dev']), - func=int(test_device['fn'])) - assert result == pcie_aer_stats - - @mock.patch('sonic_platform_base.sonic_pcie.pcie_common.PcieUtil.get_pcie_device', mock.MagicMock(return_value=pcie_device_list)) - def test_dump_conf_yaml(self): - pcieutil = PcieUtil(tests_dir) - - # Verify pcie config path before writing to file - open_mock = mock.mock_open() - with mock.patch('{}.open'.format(BUILTINS), open_mock): - pcieutil.dump_conf_yaml() - open_mock.assert_called_once_with(pcie_config_file, 'w') - - pcieutil.dump_conf_yaml() - with open(pcie_config_file) as fd: - result = yaml.safe_load(fd) - - assert result == pcie_device_list - - @classmethod - def teardown_class(cls): - # Cleanup generated config - if os.path.isfile(pcie_config_file): - os.remove(pcie_config_file) diff --git a/tests/platform_json/hwsku.json b/tests/platform_json/hwsku.json deleted file mode 100644 index 58bb6f1de..000000000 --- a/tests/platform_json/hwsku.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "interfaces": { - "Ethernet0": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet4": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet8": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet12": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet16": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet20": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet24": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet28": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet32": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet36": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet40": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet44": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet48": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - }, - "Ethernet52": { - "default_brkout_mode": "1x200G[100G,50G,40G,25G,10G,1G]" - } - } -} diff --git a/tests/platform_json/platform.json b/tests/platform_json/platform.json deleted file mode 100644 index 8f436859a..000000000 --- a/tests/platform_json/platform.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "chassis": { - "name": "", - "components": [], - "fans": [], - "fan_drawers": [], - "psus": [], - "thermals": [], - "sfps": [] - }, - "interfaces": { - "Ethernet0": { - "index": "1,1,1,1", - "lanes": "29,30,31,32", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp1"], - "2x100G[50G,25G,10G,1G]": ["etp1a", "etp1b"] - } - }, - "Ethernet4": { - "index": "2,2,2,2", - "lanes": "25,26,27,28", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp2"], - "2x100G[50G,25G,10G,1G]": ["etp2a", "etp2b"] - } - }, - "Ethernet8": { - "index": "3,3,3,3", - "lanes": "37,38,39,40", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp3"], - "2x100G[50G,25G,10G,1G]": ["etp3a", "etp3b"] - } - }, - "Ethernet12": { - "index": "4,4,4,4", - "lanes": "33,34,35,36", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp4"], - "2x100G[50G,25G,10G,1G]": ["etp4a", "etp4b"] - } - }, - "Ethernet16": { - "index": "5,5,5,5", - "lanes": "41,42,43,44", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp5"], - "2x100G[50G,25G,10G,1G]": ["etp5a", "etp5b"] - } - }, - "Ethernet20": { - "index": "6,6,6,6", - "lanes": "44,46,47,48", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp6"], - "2x100G[50G,25G,10G,1G]": ["etp6a", "etp6b"] - } - }, - "Ethernet24": { - "index": "7,7,7,7", - "lanes": "5,6,7,8", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp7"], - "2x100G[50G,25G,10G,1G]": ["etp7a", "etp7b"] - } - }, - "Ethernet28": { - "index": "8,8,8,8", - "lanes": "1,2,3,4", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp8"], - "2x100G[50G,25G,10G,1G]": ["etp8a", "etp8b"] - } - }, - "Ethernet32": { - "index": "9,9,9,9", - "lanes": "9,10,11,12", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp9"], - "2x100G[50G,25G,10G,1G]": ["etp9a", "etp9b"] - } - }, - "Ethernet36": { - "index": "10,10,10,10", - "lanes": "13,14,15,16", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp10"], - "2x100G[50G,25G,10G,1G]": ["etp10a", "etp10b"] - } - }, - "Ethernet40": { - "index": "11,11,11,11", - "lanes": "21,22,23,24", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp11"], - "2x100G[50G,25G,10G,1G]": ["etp11a", "etp11b"] - } - }, - "Ethernet44": { - "index": "12,12,12,12", - "lanes": "17,18,19,20", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp12"], - "2x100G[50G,25G,10G,1G]": ["etp12a", "etp12b"] - } - }, - "Ethernet48": { - "index": "13,13,13,13", - "lanes": "49,50,51,51", - "breakout_modes": { - "1x200G[100G,50G,40G,25G,10G,1G]": ["etp13"], - "2x100G[50G,25G,10G,1G]": ["etp13a", "etp13b"] - } - } - } -} diff --git a/tests/port_config.ini b/tests/port_config.ini deleted file mode 100644 index 923cab7cf..000000000 --- a/tests/port_config.ini +++ /dev/null @@ -1,14 +0,0 @@ -# name lanes alias index -Ethernet0 29,30,31,32 fortyGigE0/0 1 -Ethernet4 25,26,27,28 fortyGigE0/4 2 -Ethernet8 37,38,39,40 fortyGigE0/8 3 -Ethernet12 33,34,35,36 fortyGigE0/12 4 -Ethernet16 41,42,43,44 fortyGigE0/16 5 -Ethernet20 45,46,47,48 fortyGigE0/20 6 -Ethernet24 5,6,7,8 fortyGigE0/24 7 -Ethernet28 1,2,3,4 fortyGigE0/28 8 -Ethernet32 9,10,11,12 fortyGigE0/32 9 -Ethernet36 13,14,15,16 fortyGigE0/36 10 -Ethernet40 21,22,23,24 fortyGigE0/40 11 -Ethernet44 17,18,19,20 fortyGigE0/44 12 -Ethernet48 49,50,51,52 fortyGigE0/48 13 diff --git a/tests/psu_base_test.py b/tests/psu_base_test.py deleted file mode 100644 index 6c1e079eb..000000000 --- a/tests/psu_base_test.py +++ /dev/null @@ -1,29 +0,0 @@ -from sonic_platform_base.psu_base import PsuBase - -class TestPsuBase: - - def test_psu_base(self): - psu = PsuBase() - not_implemented_methods = [ - psu.get_voltage, - psu.get_current, - psu.get_power, - psu.get_powergood_status, - psu.get_temperature, - psu.get_temperature_high_threshold, - psu.get_voltage_high_threshold, - psu.get_voltage_low_threshold, - psu.get_maximum_supplied_power, - psu.get_psu_power_warning_suppress_threshold, - psu.get_psu_power_critical_threshold, - psu.get_input_voltage, - psu.get_input_current] - - for method in not_implemented_methods: - exception_raised = False - try: - method() - except NotImplementedError: - exception_raised = True - - assert exception_raised diff --git a/tests/sfputilhelper_test.py b/tests/sfputilhelper_test.py deleted file mode 100644 index e81280912..000000000 --- a/tests/sfputilhelper_test.py +++ /dev/null @@ -1,117 +0,0 @@ -import os -import sys - -import pytest - -from sonic_platform_base.sonic_sfp import sfputilhelper -from unittest import mock - -PORT_LIST = [ - "Ethernet0", - "Ethernet4", - "Ethernet8", - "Ethernet12", - "Ethernet16", - "Ethernet20", - "Ethernet24", - "Ethernet28", - "Ethernet32", - "Ethernet36", - "Ethernet40", - "Ethernet44", - "Ethernet48" -] - -LOGICAL_TO_PHYSICAL ={ - 'Ethernet0': [1], - 'Ethernet4': [2], - 'Ethernet8': [3], - 'Ethernet12': [4], - 'Ethernet16': [5], - 'Ethernet20': [6], - 'Ethernet24': [7], - 'Ethernet28': [8], - 'Ethernet32': [9], - 'Ethernet36': [10], - 'Ethernet40': [11], - 'Ethernet44': [12], - 'Ethernet48': [13] -} - -PHYSICAL_TO_LOGICAL = { - 1: ['Ethernet0'], - 2: ['Ethernet4'], - 3: ['Ethernet8'], - 4: ['Ethernet12'], - 5: ['Ethernet16'], - 6: ['Ethernet20'], - 7: ['Ethernet24'], - 8: ['Ethernet28'], - 9: ['Ethernet32'], - 10: ['Ethernet36'], - 11: ['Ethernet40'], - 12: ['Ethernet44'], - 13: ['Ethernet48'] -} - -test_dir = os.path.dirname(os.path.realpath(__file__)) -hwsku_json_file = os.path.join(test_dir, 'platform_json', 'hwsku.json') - -@pytest.fixture(scope="class") -def setup_class(request): - # Configure the setup - request.cls.port_config_file = os.path.join(test_dir, 'port_config.ini') - request.cls.platform_dir = os.path.dirname(os.path.realpath(__file__)) - request.cls.platform_json_dir = os.path.join(test_dir, 'platform_json') - - -@pytest.mark.usefixtures("setup_class") -class TestSfpUtilHelper(object): - - port_config_file = None - platform_dir = None - platform_json_dir = None - - def test_read_port_mappings(self): - - sfputil_helper = sfputilhelper.SfpUtilHelper() - sfputil_helper.read_porttab_mappings(self.port_config_file, 0) - - logical_port_list = sfputil_helper.logical - assert len(logical_port_list) == len(PORT_LIST) - - for logical_port_name in logical_port_list: - assert logical_port_name in PORT_LIST - - - @mock.patch('portconfig.get_hwsku_file_name', mock.MagicMock(return_value=hwsku_json_file)) - def test_read_all_port_mappings(self): - - sfputil_helper = sfputilhelper.SfpUtilHelper() - sfputil_helper.logical = [] - sfputil_helper.logical_to_physical = {} - sfputil_helper.physical_to_logica = {} - sfputil_helper.read_all_porttab_mappings(self.platform_dir, 2) - logical_port_list = sfputil_helper.logical - - assert len(logical_port_list) == len(PORT_LIST) - for logical_port_name in logical_port_list: - assert logical_port_name in PORT_LIST - assert sfputil_helper.logical_to_physical == LOGICAL_TO_PHYSICAL - assert sfputil_helper.physical_to_logical == PHYSICAL_TO_LOGICAL - - # test platform.json case - - sfputil_helper.logical = [] - sfputil_helper.logical_to_physical = {} - sfputil_helper.physical_to_logica = {} - sfputil_helper.read_all_porttab_mappings(self.platform_json_dir, 2) - logical_port_list = sfputil_helper.logical - - assert len(logical_port_list) == len(PORT_LIST) - - for logical_port_name in logical_port_list: - assert logical_port_name in PORT_LIST - - assert sfputil_helper.logical_to_physical == LOGICAL_TO_PHYSICAL - assert sfputil_helper.physical_to_logical == PHYSICAL_TO_LOGICAL diff --git a/tests/sonic_xcvr/__init__.py b/tests/sonic_xcvr/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/sonic_xcvr/test_ccmis.py b/tests/sonic_xcvr/test_ccmis.py deleted file mode 100644 index 8b2eb7b7e..000000000 --- a/tests/sonic_xcvr/test_ccmis.py +++ /dev/null @@ -1,626 +0,0 @@ -from mock import MagicMock -from mock import patch -import pytest -from sonic_platform_base.sonic_xcvr.api.public.c_cmis import CCmisApi -from sonic_platform_base.sonic_xcvr.mem_maps.public.c_cmis import CCmisMemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.codes.public.cmis import CmisCodes - -class TestCCmis(object): - codes = CmisCodes - mem_map = CCmisMemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = CCmisApi(eeprom) - - @pytest.mark.parametrize("mock_response, expected", [ - (7, 75), - (6, 33), - (5, 100), - (4, 50), - (3, 25), - (2, 12.5), - (1, 6.25), - (0, 3.125), - (None, None) - ]) - def test_get_freq_grid(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_freq_grid() - assert result == expected - - - @pytest.mark.parametrize("mock_response1, mock_response2, expected", [ - (75, 12, 193400), - (75, -30, 192350), - (100, 10, 194100), - ]) - def test_get_laser_config_freq(self, mock_response1, mock_response2, expected): - self.api.get_freq_grid = MagicMock() - self.api.get_freq_grid.return_value = mock_response1 - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response2 - result = self.api.get_laser_config_freq() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (193100, 193100) - ]) - def test_get_current_laser_freq(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_current_laser_freq() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (0, False) - ]) - def test_get_tuning_in_progress(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_tuning_in_progress() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (0, False) - ]) - def test_get_wavelength_unlocked(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_wavelength_unlocked() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, ['TuningComplete']), - (62, ['TargetOutputPowerOOR', 'FineTuningOutOfRange', 'TuningNotAccepted', - 'InvalidChannel', 'WavelengthUnlocked']), - ]) - def test_get_laser_tuning_summary(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_laser_tuning_summary() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([190, -72, 120], (190, -72, 120, 191300, 196100)) - ]) - def test_get_supported_freq_config(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_supported_freq_config() - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response",[ - ((193100,75), (0xff, -72, 120, 191300, 196100)), - ((195950,100), (0xff, -72, 120, 191300, 196100)), - ]) - def test_set_laser_freq(self, input_param, mock_response): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - self.api.get_lpmode_support = MagicMock() - self.api.get_lpmode_support.return_value = False - self.api.get_supported_freq_config = MagicMock() - self.api.get_supported_freq_config.return_value = mock_response - self.api.set_laser_freq(input_param[0], input_param[1]) - - @pytest.mark.parametrize("input_param, mock_response",[ - (-10, (-14, -9)), - (-8, (-12, -8)), - ]) - def test_set_tx_power(self, input_param, mock_response): - self.api.get_supported_power_config = MagicMock() - self.api.get_supported_power_config.return_value = mock_response - self.api.set_tx_power(input_param) - - @pytest.mark.parametrize("mock_response, expected", [ - ( - [ - 1000000, 10000, 1000, 8, 12, # preFEC_BER - 10000, 100, 0, 0, 0, # uncorr_frame - 1400, 1300, 1500, # CD - 7.0, 5.5, 9.2, # DGD - 40, 20, 60, # SOPMD - 1.0, 0.8, 1.2, # PDL - 28, 26, 30, # OSNR - 17, 15, 18, # ESNR - 200, 150, 250, # CFO - 15, 13, 18, # EVM - -10, -9.5, -10.5, # TX power - -8, -7, -9, # RX total power - -8, -7, -9, # RX channel power - 5, 3, 8, # SOPROc - 0, 0, 0, # MER - ], - { - 'preFEC_BER_avg': 0.001, 'preFEC_BER_min': 0.0008, 'preFEC_BER_max': 0.0012, - 'preFEC_uncorr_frame_ratio_avg': 0, 'preFEC_uncorr_frame_ratio_min': 0, 'preFEC_uncorr_frame_ratio_max': 0, - 'rx_cd_avg': 1400, 'rx_cd_min': 1300, 'rx_cd_max': 1500, - 'rx_dgd_avg': 7.0, 'rx_dgd_min': 5.5, 'rx_dgd_max': 9.2, - 'rx_sopmd_avg': 40, 'rx_sopmd_min': 20, 'rx_sopmd_max': 60, - 'rx_pdl_avg': 1.0, 'rx_pdl_min': 0.8, 'rx_pdl_max': 1.2, - 'rx_osnr_avg': 28, 'rx_osnr_min': 26, 'rx_osnr_max': 30, - 'rx_esnr_avg': 17, 'rx_esnr_min': 15, 'rx_esnr_max': 18, - 'rx_cfo_avg': 200, 'rx_cfo_min': 150, 'rx_cfo_max': 250, - 'rx_evm_avg': 15, 'rx_evm_min': 13, 'rx_evm_max': 18, - 'tx_power_avg': -10, 'tx_power_min': -9.5, 'tx_power_max': -10.5, - 'rx_power_avg': -8, 'rx_power_min': -7, 'rx_power_max': -9, - 'rx_sigpwr_avg': -8, 'rx_sigpwr_min': -7, 'rx_sigpwr_max': -9, - 'rx_soproc_avg': 5, 'rx_soproc_min': 3, 'rx_soproc_max': 8, - 'rx_mer_avg': 0, 'rx_mer_min': 0, 'rx_mer_max': 0 - } - ) - ]) - def test_get_pm_all(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_pm_all() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ { - 'type': 'QSFP-DD Double Density 8X Pluggable Transceiver' - }, - (-20, 0), - (0xff, -72, 120, 191300, 196100) - ], - { - 'type': 'QSFP-DD Double Density 8X Pluggable Transceiver', - 'supported_min_laser_freq': 191300, - 'supported_max_laser_freq': 196100, - 'supported_max_tx_power': 0, - 'supported_min_tx_power': -20, - - } - ) - ]) - @patch("sonic_platform_base.sonic_xcvr.api.public.cmis.CmisApi.get_transceiver_info") - def test_get_transceiver_info(self, get_transceiver_info_func, mock_response, expected): - get_transceiver_info_func.return_value = mock_response[0] - self.api.get_supported_power_config = MagicMock() - self.api.get_supported_power_config.return_value = mock_response[1] - self.api.get_supported_freq_config = MagicMock() - self.api.get_supported_freq_config.return_value = mock_response[2] - result = self.api.get_transceiver_info() - assert result == expected - - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - { - 'temperature': 50, - 'voltage': 3.3, - 'txpower': 0.1, - 'rxpower': 0.09, - 'txbias': 70, - 'laser_temperature': 40, - 'prefec_ber': 0.001, - 'postfec_ber': 0, - }, - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - 'Modulator Bias X/I [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias X/Q [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias X_Phase [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y/I [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y/Q [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y_Phase [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'CD high granularity, short link [ps/nm]':{1:[1000, 2000, 0, 1800, 0, False, False, False, False]}, - 'CD low granularity, long link [ps/nm]':{1:[1000, 2000, 0, 1800, 0, False, False, False, False]}, - 'DGD [ps]':{1:[5, 30, 0, 25, 0, False, False, False, False]}, - 'SOPMD [ps^2]':{1:[5, 100, 0, 80, 0, False, False, False, False]}, - 'SOP ROC [krad/s]':{1: [0, 65535, 0, 65535, 0, False, False, False, False]}, - 'PDL [dB]':{1:[0.5, 3, 0, 2.5, 0, False, False, False, False]}, - 'OSNR [dB]':{1:[30, 100, 26, 80, 27, False, False, False, False]}, - 'eSNR [dB]':{1:[16, 100, 13, 80, 14, False, False, False, False]}, - 'CFO [MHz]':{1:[100, 5000, -5000, 4000, -4000, False, False, False, False]}, - 'Tx Power [dBm]':{1:[-10, 0, -18, -2, -16, False, False, False, False]}, - 'Rx Total Power [dBm]':{1:[-10, 3, -18, 0, -15, False, False, False, False]}, - 'Rx Signal Power [dBm]':{1:[-10, 3, -18, 0, -15, False, False, False, False]} - }, - 193100, 193100, -10 - ], - { - 'temperature': 50, - 'voltage': 3.3, - 'txpower': 0.1, - 'rxpower': 0.09, - 'txbias': 70, - 'laser_temperature': 40, - 'prefec_ber': 0.001, - 'postfec_ber': 0, - 'bias_xi': 50, - 'bias_xq': 50, - 'bias_xp': 50, - 'bias_yi': 50, - 'bias_yq': 50, - 'bias_yp': 50, - 'cd_shortlink': 1000, - 'cd_longlink': 1000, - 'dgd': 5, - 'sopmd': 5, - 'soproc': 0, - 'pdl': 0.5, - 'osnr': 30, - 'esnr': 16, - 'cfo': 100, - 'tx_curr_power': -10, - 'rx_tot_power': -10, - 'rx_sig_power': -10, - 'laser_config_freq': 193100, - 'laser_curr_freq': 193100, - 'tx_config_power': -10 - } - ) - ]) - @patch("sonic_platform_base.sonic_xcvr.api.public.cmis.CmisApi.get_transceiver_bulk_status") - def test_get_transceiver_bulk_status(self, get_transceiver_bulk_status_func, mock_response, expected): - get_transceiver_bulk_status_func.return_value = mock_response[0] - self.api.vdm_dict = mock_response[1] - self.api.get_laser_config_freq = MagicMock() - self.api.get_laser_config_freq.return_value = mock_response[2] - self.api.get_current_laser_freq = MagicMock() - self.api.get_current_laser_freq.return_value = mock_response[3] - self.api.get_tx_config_power = MagicMock() - self.api.get_tx_config_power.return_value = mock_response[4] - result = self.api.get_transceiver_bulk_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - { - 'temphighalarm': 80, 'templowalarm': 0, 'temphighwarning': 75, 'templowwarning': 10, - 'vcchighalarm': 3.5, 'vcclowalarm': 3.1, 'vcchighwarning': 3.45, 'vcclowwarning': 3.15, - 'txpowerhighalarm': 1.0, 'txpowerlowalarm': 0.01, 'txpowerhighwarning': 0.7, 'txpowerlowwarning': 0.02, - 'rxpowerhighalarm': 2.0, 'rxpowerlowalarm': 0.01, 'rxpowerhighwarning': 1.0, 'rxpowerlowwarning': 0.02, - 'txbiashighalarm': 90, 'txbiaslowalarm': 10, 'txbiashighwarning': 80, 'txbiaslowwarning': 20, - 'lasertemphighalarm': 80, 'lasertemplowalarm': 10, 'lasertemphighwarning': 75, 'lasertemplowwarning': 20, - 'prefecberhighalarm': 0.0125, 'prefecberlowalarm': 0, 'prefecberhighwarning': 0.01, 'prefecberlowwarning': 0, - 'postfecberhighalarm': 1, 'postfecberlowalarm': 0, 'postfecberhighwarning': 1, 'postfecberlowwarning': 0, - }, - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - 'Modulator Bias X/I [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias X/Q [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias X_Phase [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y/I [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y/Q [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y_Phase [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'CD high granularity, short link [ps/nm]':{1:[1000, 2000, 0, 1800, 0, False, False, False, False]}, - 'CD low granularity, long link [ps/nm]':{1:[1000, 2000, 0, 1800, 0, False, False, False, False]}, - 'DGD [ps]':{1:[5, 30, 0, 25, 0, False, False, False, False]}, - 'SOPMD [ps^2]':{1:[5, 100, 0, 80, 0, False, False, False, False]}, - 'PDL [dB]':{1:[0.5, 3, 0, 2.5, 0, False, False, False, False]}, - 'OSNR [dB]':{1:[30, 100, 26, 80, 27, False, False, False, False]}, - 'eSNR [dB]':{1:[16, 100, 13, 80, 14, False, False, False, False]}, - 'CFO [MHz]':{1:[100, 5000, -5000, 4000, -4000, False, False, False, False]}, - 'Tx Power [dBm]':{1:[-10, 0, -18, -2, -16, False, False, False, False]}, - 'Rx Total Power [dBm]':{1:[-10, 3, -18, 0, -15, False, False, False, False]}, - 'Rx Signal Power [dBm]':{1:[-10, 3, -18, 0, -15, False, False, False, False]} - } - ], - { - 'temphighalarm': 80, 'templowalarm': 0, 'temphighwarning': 75, 'templowwarning': 10, - 'vcchighalarm': 3.5, 'vcclowalarm': 3.1, 'vcchighwarning': 3.45, 'vcclowwarning': 3.15, - 'txpowerhighalarm': 1.0, 'txpowerlowalarm': 0.01, 'txpowerhighwarning': 0.7, 'txpowerlowwarning': 0.02, - 'rxpowerhighalarm': 2.0, 'rxpowerlowalarm': 0.01, 'rxpowerhighwarning': 1.0, 'rxpowerlowwarning': 0.02, - 'txbiashighalarm': 90, 'txbiaslowalarm': 10, 'txbiashighwarning': 80, 'txbiaslowwarning': 20, - 'lasertemphighalarm': 80, 'lasertemplowalarm': 10, 'lasertemphighwarning': 75, 'lasertemplowwarning': 20, - 'prefecberhighalarm': 0.0125, 'prefecberlowalarm': 0, 'prefecberhighwarning': 0.01, 'prefecberlowwarning': 0, - 'postfecberhighalarm': 1, 'postfecberlowalarm': 0, 'postfecberhighwarning': 1, 'postfecberlowwarning': 0, - 'biasxihighalarm': 90, 'biasxilowalarm': 10, 'biasxihighwarning': 85, 'biasxilowwarning': 15, - 'biasxqhighalarm': 90, 'biasxqlowalarm': 10, 'biasxqhighwarning': 85, 'biasxqlowwarning': 15, - 'biasxphighalarm': 90, 'biasxplowalarm': 10, 'biasxphighwarning': 85, 'biasxplowwarning': 15, - 'biasyihighalarm': 90, 'biasyilowalarm': 10, 'biasyihighwarning': 85, 'biasyilowwarning': 15, - 'biasyqhighalarm': 90, 'biasyqlowalarm': 10, 'biasyqhighwarning': 85, 'biasyqlowwarning': 15, - 'biasyphighalarm': 90, 'biasyplowalarm': 10, 'biasyphighwarning': 85, 'biasyplowwarning': 15, - 'cdshorthighalarm': 2000, 'cdshortlowalarm': 0, 'cdshorthighwarning': 1800, 'cdshortlowwarning': 0, - 'cdlonghighalarm': 2000, 'cdlonglowalarm': 0, 'cdlonghighwarning': 1800, 'cdlonglowwarning': 0, - 'dgdhighalarm': 30, 'dgdlowalarm': 0, 'dgdhighwarning': 25, 'dgdlowwarning': 0, - 'sopmdhighalarm': 100, 'sopmdlowalarm': 0, 'sopmdhighwarning': 80, 'sopmdlowwarning': 0, - 'pdlhighalarm': 3, 'pdllowalarm': 0, 'pdlhighwarning': 2.5, 'pdllowwarning': 0, - 'osnrhighalarm': 100, 'osnrlowalarm': 26, 'osnrhighwarning': 80, 'osnrlowwarning': 27, - 'esnrhighalarm': 100, 'esnrlowalarm': 13, 'esnrhighwarning': 80, 'esnrlowwarning': 14, - 'cfohighalarm': 5000, 'cfolowalarm': -5000, 'cfohighwarning': 4000, 'cfolowwarning': -4000, - 'txcurrpowerhighalarm': 0, 'txcurrpowerlowalarm': -18, 'txcurrpowerhighwarning': -2, 'txcurrpowerlowwarning': -16, - 'rxtotpowerhighalarm': 3, 'rxtotpowerlowalarm': -18, 'rxtotpowerhighwarning': 0, 'rxtotpowerlowwarning': -15, - 'rxsigpowerhighalarm': 3, 'rxsigpowerlowalarm': -18, 'rxsigpowerhighwarning': 0, 'rxsigpowerlowwarning': -15 - } - ) - ]) - @patch("sonic_platform_base.sonic_xcvr.api.public.cmis.CmisApi.get_transceiver_threshold_info") - def test_get_transceiver_threshold_info(self, get_transceiver_threshold_info_func, mock_response, expected): - get_transceiver_threshold_info_func.return_value = mock_response[0] - self.api.vdm_dict = mock_response[1] - result = self.api.get_transceiver_threshold_info() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - { - 'module_state': 'ModuleReady', - 'module_fault_cause': 'No Fault detected', - 'datapath_firmware_fault': False, - 'module_firmware_fault': False, - 'module_state_changed': True, - 'datapath_hostlane1': 'DataPathActivated', - 'datapath_hostlane2': 'DataPathActivated', - 'datapath_hostlane3': 'DataPathActivated', - 'datapath_hostlane4': 'DataPathActivated', - 'datapath_hostlane5': 'DataPathActivated', - 'datapath_hostlane6': 'DataPathActivated', - 'datapath_hostlane7': 'DataPathActivated', - 'datapath_hostlane8': 'DataPathActivated', - 'txoutput_status': True, - 'rxoutput_status_hostlane1': True, - 'rxoutput_status_hostlane2': True, - 'rxoutput_status_hostlane3': True, - 'rxoutput_status_hostlane4': True, - 'rxoutput_status_hostlane5': True, - 'rxoutput_status_hostlane6': True, - 'rxoutput_status_hostlane7': True, - 'rxoutput_status_hostlane8': True, - 'txfault': False, - 'txlos_hostlane1': False, - 'txlos_hostlane2': False, - 'txlos_hostlane3': False, - 'txlos_hostlane4': False, - 'txlos_hostlane5': False, - 'txlos_hostlane6': False, - 'txlos_hostlane7': False, - 'txlos_hostlane8': False, - 'txcdrlol_hostlane1': False, - 'txcdrlol_hostlane2': False, - 'txcdrlol_hostlane3': False, - 'txcdrlol_hostlane4': False, - 'txcdrlol_hostlane5': False, - 'txcdrlol_hostlane6': False, - 'txcdrlol_hostlane7': False, - 'txcdrlol_hostlane8': False, - 'rxlos': False, - 'rxcdrlol': False, - 'config_state_hostlane1': 'ConfigSuccess', - 'config_state_hostlane2': 'ConfigSuccess', - 'config_state_hostlane3': 'ConfigSuccess', - 'config_state_hostlane4': 'ConfigSuccess', - 'config_state_hostlane5': 'ConfigSuccess', - 'config_state_hostlane6': 'ConfigSuccess', - 'config_state_hostlane7': 'ConfigSuccess', - 'config_state_hostlane8': 'ConfigSuccess', - 'dpinit_pending_hostlane1': False, - 'dpinit_pending_hostlane2': False, - 'dpinit_pending_hostlane3': False, - 'dpinit_pending_hostlane4': False, - 'dpinit_pending_hostlane5': False, - 'dpinit_pending_hostlane6': False, - 'dpinit_pending_hostlane7': False, - 'dpinit_pending_hostlane8': False, - 'temphighalarm_flag': False, 'templowalarm_flag': False, - 'temphighwarning_flag': False, 'templowwarning_flag': False, - 'vcchighalarm_flag': False, 'vcclowalarm_flag': False, - 'vcchighwarning_flag': False, 'vcclowwarning_flag': False, - 'lasertemphighalarm_flag': False, 'lasertemplowalarm_flag': False, - 'lasertemphighwarning_flag': False, 'lasertemplowwarning_flag': False, - 'txpowerhighalarm_flag': False, 'txpowerlowalarm_flag': False, - 'txpowerhighwarning_flag': False, 'txpowerlowwarning_flag': False, - 'rxpowerhighalarm_flag': False, 'rxpowerlowalarm_flag': False, - 'rxpowerhighwarning_flag': False, 'rxpowerlowwarning_flag': False, - 'txbiashighalarm_flag': False, 'txbiaslowalarm_flag': False, - 'txbiashighwarning_flag': False, 'txbiaslowwarning_flag': False, - 'prefecberhighalarm_flag': False, 'prefecberlowalarm_flag': False, - 'prefecberhighwarning_flag': False, 'prefecberlowwarning_flag': False, - 'postfecberhighalarm_flag': False, 'postfecberlowalarm_flag': False, - 'postfecberhighwarning_flag': False, 'postfecberlowwarning_flag': False, - }, - False, False, ['TuningComplete'], - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - 'Modulator Bias X/I [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias X/Q [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias X_Phase [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y/I [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y/Q [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'Modulator Bias Y_Phase [%]':{1:[50, 90, 10, 85, 15, False, False, False, False]}, - 'CD high granularity, short link [ps/nm]':{1:[1000, 2000, 0, 1800, 0, False, False, False, False]}, - 'CD low granularity, long link [ps/nm]':{1:[1000, 2000, 0, 1800, 0, False, False, False, False]}, - 'DGD [ps]':{1:[5, 30, 0, 25, 0, False, False, False, False]}, - 'SOPMD [ps^2]':{1:[5, 100, 0, 80, 0, False, False, False, False]}, - 'PDL [dB]':{1:[0.5, 3, 0, 2.5, 0, False, False, False, False]}, - 'OSNR [dB]':{1:[30, 100, 26, 80, 27, False, False, False, False]}, - 'eSNR [dB]':{1:[16, 100, 13, 80, 14, False, False, False, False]}, - 'CFO [MHz]':{1:[100, 5000, -5000, 4000, -4000, False, False, False, False]}, - 'Tx Power [dBm]':{1:[-10, 0, -18, -2, -16, False, False, False, False]}, - 'Rx Total Power [dBm]':{1:[-10, 3, -18, 0, -15, False, False, False, False]}, - 'Rx Signal Power [dBm]':{1:[-10, 3, -18, 0, -15, False, False, False, False]} - } - ], - { - 'module_state': 'ModuleReady', - 'module_fault_cause': 'No Fault detected', - 'datapath_firmware_fault': False, - 'module_firmware_fault': False, - 'module_state_changed': True, - 'datapath_hostlane1': 'DataPathActivated', - 'datapath_hostlane2': 'DataPathActivated', - 'datapath_hostlane3': 'DataPathActivated', - 'datapath_hostlane4': 'DataPathActivated', - 'datapath_hostlane5': 'DataPathActivated', - 'datapath_hostlane6': 'DataPathActivated', - 'datapath_hostlane7': 'DataPathActivated', - 'datapath_hostlane8': 'DataPathActivated', - 'txoutput_status': True, - 'rxoutput_status_hostlane1': True, - 'rxoutput_status_hostlane2': True, - 'rxoutput_status_hostlane3': True, - 'rxoutput_status_hostlane4': True, - 'rxoutput_status_hostlane5': True, - 'rxoutput_status_hostlane6': True, - 'rxoutput_status_hostlane7': True, - 'rxoutput_status_hostlane8': True, - 'txfault': False, - 'txlos_hostlane1': False, - 'txlos_hostlane2': False, - 'txlos_hostlane3': False, - 'txlos_hostlane4': False, - 'txlos_hostlane5': False, - 'txlos_hostlane6': False, - 'txlos_hostlane7': False, - 'txlos_hostlane8': False, - 'txcdrlol_hostlane1': False, - 'txcdrlol_hostlane2': False, - 'txcdrlol_hostlane3': False, - 'txcdrlol_hostlane4': False, - 'txcdrlol_hostlane5': False, - 'txcdrlol_hostlane6': False, - 'txcdrlol_hostlane7': False, - 'txcdrlol_hostlane8': False, - 'rxlos': False, - 'rxcdrlol': False, - 'config_state_hostlane1': 'ConfigSuccess', - 'config_state_hostlane2': 'ConfigSuccess', - 'config_state_hostlane3': 'ConfigSuccess', - 'config_state_hostlane4': 'ConfigSuccess', - 'config_state_hostlane5': 'ConfigSuccess', - 'config_state_hostlane6': 'ConfigSuccess', - 'config_state_hostlane7': 'ConfigSuccess', - 'config_state_hostlane8': 'ConfigSuccess', - 'dpinit_pending_hostlane1': False, - 'dpinit_pending_hostlane2': False, - 'dpinit_pending_hostlane3': False, - 'dpinit_pending_hostlane4': False, - 'dpinit_pending_hostlane5': False, - 'dpinit_pending_hostlane6': False, - 'dpinit_pending_hostlane7': False, - 'dpinit_pending_hostlane8': False, - 'tuning_in_progress': False, - 'wavelength_unlock_status': False, - 'target_output_power_oor': False, - 'fine_tuning_oor': False, - 'tuning_not_accepted': False, - 'invalid_channel_num': False, - 'tuning_complete': True, - 'temphighalarm_flag': False, 'templowalarm_flag': False, - 'temphighwarning_flag': False, 'templowwarning_flag': False, - 'vcchighalarm_flag': False, 'vcclowalarm_flag': False, - 'vcchighwarning_flag': False, 'vcclowwarning_flag': False, - 'lasertemphighalarm_flag': False, 'lasertemplowalarm_flag': False, - 'lasertemphighwarning_flag': False, 'lasertemplowwarning_flag': False, - 'txpowerhighalarm_flag': False, 'txpowerlowalarm_flag': False, - 'txpowerhighwarning_flag': False, 'txpowerlowwarning_flag': False, - 'rxpowerhighalarm_flag': False, 'rxpowerlowalarm_flag': False, - 'rxpowerhighwarning_flag': False, 'rxpowerlowwarning_flag': False, - 'txbiashighalarm_flag': False, 'txbiaslowalarm_flag': False, - 'txbiashighwarning_flag': False, 'txbiaslowwarning_flag': False, - 'prefecberhighalarm_flag': False, 'prefecberlowalarm_flag': False, - 'prefecberhighwarning_flag': False, 'prefecberlowwarning_flag': False, - 'postfecberhighalarm_flag': False, 'postfecberlowalarm_flag': False, - 'postfecberhighwarning_flag': False, 'postfecberlowwarning_flag': False, - 'biasxihighalarm_flag': False, 'biasxilowalarm_flag': False, - 'biasxihighwarning_flag': False, 'biasxilowwarning_flag': False, - 'biasxqhighalarm_flag': False, 'biasxqlowalarm_flag': False, - 'biasxqhighwarning_flag': False, 'biasxqlowwarning_flag': False, - 'biasxphighalarm_flag': False, 'biasxplowalarm_flag': False, - 'biasxphighwarning_flag': False, 'biasxplowwarning_flag': False, - 'biasyihighalarm_flag': False, 'biasyilowalarm_flag': False, - 'biasyihighwarning_flag': False, 'biasyilowwarning_flag': False, - 'biasyqhighalarm_flag': False, 'biasyqlowalarm_flag': False, - 'biasyqhighwarning_flag': False, 'biasyqlowwarning_flag': False, - 'biasyphighalarm_flag': False, 'biasyplowalarm_flag': False, - 'biasyphighwarning_flag': False, 'biasyplowwarning_flag': False, - 'cdshorthighalarm_flag': False, 'cdshortlowalarm_flag': False, - 'cdshorthighwarning_flag': False, 'cdshortlowwarning_flag': False, - 'cdlonghighalarm_flag': False, 'cdlonglowalarm_flag': False, - 'cdlonghighwarning_flag': False, 'cdlonglowwarning_flag': False, - 'dgdhighalarm_flag': False, 'dgdlowalarm_flag': False, - 'dgdhighwarning_flag': False, 'dgdlowwarning_flag': False, - 'sopmdhighalarm_flag': False, 'sopmdlowalarm_flag': False, - 'sopmdhighwarning_flag': False, 'sopmdlowwarning_flag': False, - 'pdlhighalarm_flag': False, 'pdllowalarm_flag': False, - 'pdlhighwarning_flag': False, 'pdllowwarning_flag': False, - 'osnrhighalarm_flag': False, 'osnrlowalarm_flag': False, - 'osnrhighwarning_flag': False, 'osnrlowwarning_flag': False, - 'esnrhighalarm_flag': False, 'esnrlowalarm_flag': False, - 'esnrhighwarning_flag': False, 'esnrlowwarning_flag': False, - 'cfohighalarm_flag': False, 'cfolowalarm_flag': False, - 'cfohighwarning_flag': False, 'cfolowwarning_flag': False, - 'txcurrpowerhighalarm_flag': False, 'txcurrpowerlowalarm_flag': False, - 'txcurrpowerhighwarning_flag': False, 'txcurrpowerlowwarning_flag': False, - 'rxtotpowerhighalarm_flag': False, 'rxtotpowerlowalarm_flag': False, - 'rxtotpowerhighwarning_flag': False, 'rxtotpowerlowwarning_flag': False, - 'rxsigpowerhighalarm_flag': False, 'rxsigpowerlowalarm_flag': False, - 'rxsigpowerhighwarning_flag': False, 'rxsigpowerlowwarning_flag': False, - - } - ) - ]) - @patch("sonic_platform_base.sonic_xcvr.api.public.cmis.CmisApi.get_transceiver_status") - def test_get_transceiver_status(self, get_transceiver_status_func, mock_response, expected): - get_transceiver_status_func.return_value = dict(mock_response[0]) - self.api.get_tuning_in_progress = MagicMock() - self.api.get_tuning_in_progress.return_value = mock_response[1] - self.api.get_wavelength_unlocked = MagicMock() - self.api.get_wavelength_unlocked.return_value = mock_response[2] - self.api.get_laser_tuning_summary = MagicMock() - self.api.get_laser_tuning_summary.return_value = mock_response[3] - self.api.vdm_dict = mock_response[4] - result = self.api.get_transceiver_status() - assert result == expected - - # For the case of 'Rx Signal Power [dBm]' not present: - get_transceiver_status_func.return_value = dict(mock_response[0]) - del self.api.vdm_dict['Rx Signal Power [dBm]'] - for k in ['rxsigpowerhighalarm_flag', 'rxsigpowerlowalarm_flag', - 'rxsigpowerhighwarning_flag', 'rxsigpowerlowwarning_flag']: - del expected[k] - result = self.api.get_transceiver_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ( - { - 'preFEC_BER_avg': 0.001, 'preFEC_BER_min': 0.0008, 'preFEC_BER_max': 0.0012, - 'preFEC_uncorr_frame_ratio_avg': 0, 'preFEC_uncorr_frame_ratio_min': 0, 'preFEC_uncorr_frame_ratio_max': 0, - 'rx_cd_avg': 1400, 'rx_cd_min': 1300, 'rx_cd_max': 1500, - 'rx_dgd_avg': 7.0, 'rx_dgd_min': 5.5, 'rx_dgd_max': 9.2, - 'rx_sopmd_avg': 40, 'rx_sopmd_min': 20, 'rx_sopmd_max': 60, - 'rx_pdl_avg': 1.0, 'rx_pdl_min': 0.8, 'rx_pdl_max': 1.2, - 'rx_osnr_avg': 28, 'rx_osnr_min': 26, 'rx_osnr_max': 30, - 'rx_esnr_avg': 17, 'rx_esnr_min': 15, 'rx_esnr_max': 18, - 'rx_cfo_avg': 200, 'rx_cfo_min': 150, 'rx_cfo_max': 250, - 'rx_evm_avg': 15, 'rx_evm_min': 13, 'rx_evm_max': 18, - 'tx_power_avg': -10, 'tx_power_min': -9.5, 'tx_power_max': -10.5, - 'rx_power_avg': -8, 'rx_power_min': -7, 'rx_power_max': -9, - 'rx_sigpwr_avg': -8, 'rx_sigpwr_min': -7, 'rx_sigpwr_max': -9, - 'rx_soproc_avg': 5, 'rx_soproc_min': 3, 'rx_soproc_max': 8, - }, - { - 'prefec_ber_avg': 0.001, 'prefec_ber_min': 0.0008, 'prefec_ber_max': 0.0012, - 'uncorr_frames_avg': 0, 'uncorr_frames_min': 0, 'uncorr_frames_max': 0, - 'cd_avg': 1400, 'cd_min': 1300, 'cd_max': 1500, - 'dgd_avg': 7.0, 'dgd_min': 5.5, 'dgd_max': 9.2, - 'sopmd_avg': 40, 'sopmd_min': 20, 'sopmd_max': 60, - 'pdl_avg': 1.0, 'pdl_min': 0.8, 'pdl_max': 1.2, - 'osnr_avg': 28, 'osnr_min': 26, 'osnr_max': 30, - 'esnr_avg': 17, 'esnr_min': 15, 'esnr_max': 18, - 'cfo_avg': 200, 'cfo_min': 150, 'cfo_max': 250, - 'evm_avg': 15, 'evm_min': 13, 'evm_max': 18, - 'tx_power_avg': -10, 'tx_power_min': -9.5, 'tx_power_max': -10.5, - 'rx_tot_power_avg': -8, 'rx_tot_power_min': -7, 'rx_tot_power_max': -9, - 'rx_sig_power_avg': -8, 'rx_sig_power_min': -7, 'rx_sig_power_max': -9, - 'soproc_avg': 5, 'soproc_min': 3, 'soproc_max': 8, - } - ) - ]) - def test_get_transceiver_pm(self, mock_response, expected): - self.api.get_pm_all = MagicMock() - self.api.get_pm_all.return_value = mock_response - result = self.api.get_transceiver_pm() - assert result == expected diff --git a/tests/sonic_xcvr/test_cmis.py b/tests/sonic_xcvr/test_cmis.py deleted file mode 100644 index 4380f0852..000000000 --- a/tests/sonic_xcvr/test_cmis.py +++ /dev/null @@ -1,2112 +0,0 @@ -from mock import MagicMock -import pytest -from sonic_platform_base.sonic_xcvr.api.public.cmis import CmisApi -from sonic_platform_base.sonic_xcvr.mem_maps.public.cmis import CmisMemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.codes.public.cmis import CmisCodes -from sonic_platform_base.sonic_xcvr.codes.public.sff8024 import Sff8024 -from sonic_platform_base.sonic_xcvr.fields import consts - -class TestCmis(object): - codes = CmisCodes - mem_map = CmisMemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = CmisApi(eeprom) - - @pytest.mark.parametrize("mock_response, expected", [ - ("1234567890", "1234567890"), - ("ABCD", "ABCD") - ]) - def test_get_model(self, mock_response, expected): - """ - Verify all api access valid fields - """ - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_model() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ("0.0", "0.0"), - ("1.2", "1.2") - ]) - def test_get_vendor_rev(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_vendor_rev() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ("100000000", "100000000") - ]) - def test_get_serial(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_serial() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ( - 'QSFP-DD Double Density 8X Pluggable Transceiver', - 'QSFP-DD Double Density 8X Pluggable Transceiver' - ) - ]) - def test_get_module_type(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_module_type() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ("LC", "LC") - ]) - def test_get_connector_type(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_connector_type() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([0, 1], '0.1') - ]) - def test_get_module_hardware_revision(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - result = self.api.get_module_hardware_revision() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([5,0], '5.0') - ]) - def test_get_cmis_rev(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_cmis_rev() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ("ModuleReady", "ModuleReady") - ]) - def test_get_module_state(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_module_state() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ("No Fault detected", "No Fault detected") - ]) - def test_get_module_fault_cause(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_module_fault_cause() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([0, 1], '0.1') - ]) - def test_get_module_active_firmware(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - result = self.api.get_module_active_firmware() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([0, 1], '0.1') - ]) - def test_get_module_inactive_firmware(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_module_inactive_firmware() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, 55.0], 55.0), - ([False, 55.0], 'N/A'), - ([True, None], None), - ]) - def test_get_module_temperature(self, mock_response, expected): - self.api.get_temperature_support = MagicMock() - self.api.get_temperature_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_module_temperature() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, 3.0], 3.0), - ([False, 3.0], 'N/A'), - ([True, None], None), - ]) - def test_get_voltage(self, mock_response, expected): - self.api.get_voltage_support = MagicMock() - self.api.get_voltage_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_voltage() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (False, False) - ]) - def test_is_flat_memory(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.is_flat_memory() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (False, True) - ]) - def test_get_temperature_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response - result = self.api.get_temperature_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (False, True) - ]) - def test_get_voltage_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response - result = self.api.get_voltage_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_rx_los_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_rx_los_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_tx_cdr_lol_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_cdr_lol_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, {'TxCDRLOL1': 0}], [False]), - ([False, {'TxCDRLOL1': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None), - ([True, None], None) - ]) - def test_get_tx_cdr_lol(self, mock_response, expected): - self.api.get_tx_cdr_lol_support = MagicMock() - self.api.get_tx_cdr_lol_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_cdr_lol() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, {'RxLOS1': 0}], [False]), - ([False, {'RxLOS1': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None), - ([True, None], None) - ]) - def test_get_rx_los(self, mock_response, expected): - self.api.get_rx_los_support = MagicMock() - self.api.get_rx_los_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_rx_los() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_rx_cdr_lol_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_rx_cdr_lol_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, {'RxCDRLOL1': 0}], [False]), - ([False, {'RxCDRLOL1': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None), - ([True, None], None) - ]) - def test_get_rx_cdr_lol(self, mock_response, expected): - self.api.get_rx_cdr_lol_support = MagicMock() - self.api.get_rx_cdr_lol_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_rx_cdr_lol() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([{'TxPowerHighAlarmFlag1':0}, {'TxPowerLowAlarmFlag1':0}, {'TxPowerHighWarnFlag1':0}, {'TxPowerLowWarnFlag1':0}], - { - 'tx_power_high_alarm':{ - 'TxPowerHighAlarmFlag1': False - }, - 'tx_power_low_alarm':{ - 'TxPowerLowAlarmFlag1': False - }, - 'tx_power_high_warn':{ - 'TxPowerHighWarnFlag1': False, - }, - 'tx_power_low_warn':{ - 'TxPowerLowWarnFlag1': False - } - }), - ([None, None, None, None], None) - ]) - def test_get_tx_power_flag(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_tx_power_flag() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([{'TxBiasHighAlarmFlag1':0}, {'TxBiasLowAlarmFlag1':0}, {'TxBiasHighWarnFlag1':0}, {'TxBiasLowWarnFlag1':0}], - { - 'tx_bias_high_alarm':{ - 'TxBiasHighAlarmFlag1': False - }, - 'tx_bias_low_alarm':{ - 'TxBiasLowAlarmFlag1': False - }, - 'tx_bias_high_warn':{ - 'TxBiasHighWarnFlag1': False, - }, - 'tx_bias_low_warn':{ - 'TxBiasLowWarnFlag1': False - } - }), - ([None, None, None, None], None) - ]) - def test_get_tx_bias_flag(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_tx_bias_flag() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([{'RxPowerHighAlarmFlag1':0}, {'RxPowerLowAlarmFlag1':0}, {'RxPowerHighWarnFlag1':0}, {'RxPowerLowWarnFlag1':0}], - { - 'rx_power_high_alarm':{ - 'RxPowerHighAlarmFlag1': False - }, - 'rx_power_low_alarm':{ - 'RxPowerLowAlarmFlag1': False - }, - 'rx_power_high_warn':{ - 'RxPowerHighWarnFlag1': False, - }, - 'rx_power_low_warn':{ - 'RxPowerLowWarnFlag1': False - } - }), - ([None, None, None, None], None) - ]) - def test_get_rx_power_flag(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_rx_power_flag() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ({'TxOutputStatus1': 1}, {'TxOutputStatus1': True}), - (None, None), - ]) - def test_get_tx_output_status(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_tx_output_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ({'RxOutputStatus1': 1}, {'RxOutputStatus1': True}), - (None, None), - ]) - def test_get_rx_output_status(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_rx_output_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_tx_bias_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_bias_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, 2, {'LaserBiasTx1Field': 2, 'LaserBiasTx2Field': 2, 'LaserBiasTx3Field': 2, 'LaserBiasTx4Field': 2, 'LaserBiasTx5Field': 2, 'LaserBiasTx6Field': 2, 'LaserBiasTx7Field': 2, 'LaserBiasTx8Field': 2}], - [8, 8, 8, 8, 8, 8, 8, 8]), - ([True, 3, {'LaserBiasTx1Field': 2, 'LaserBiasTx2Field': 2, 'LaserBiasTx3Field': 2, 'LaserBiasTx4Field': 2, 'LaserBiasTx5Field': 2, 'LaserBiasTx6Field': 2, 'LaserBiasTx7Field': 2, 'LaserBiasTx8Field': 2}], - [2, 2, 2, 2, 2, 2, 2, 2]), - ([False, 0, {'LaserBiasTx1Field': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, 0, None], None) - ]) - def test_get_tx_bias(self, mock_response, expected): - self.api.get_tx_bias_support = MagicMock() - self.api.get_tx_bias_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response[1:] - result = self.api.get_tx_bias() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_tx_power_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_power_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ( - [ - True, - { - 'OpticalPowerTx1Field': 0, 'OpticalPowerTx2Field': 0, - 'OpticalPowerTx3Field': 0, 'OpticalPowerTx4Field': 0, - 'OpticalPowerTx5Field': 0, 'OpticalPowerTx6Field': 0, - 'OpticalPowerTx7Field': 0, 'OpticalPowerTx8Field': 0 - } - ], - [0, 0, 0, 0, 0, 0, 0, 0] - ), - ([False, {'OpticalPowerTx1Field': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None) - ]) - def test_get_tx_power(self, mock_response, expected): - self.api.get_tx_power_support = MagicMock() - self.api.get_tx_power_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_power() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_rx_power_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_rx_power_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ( - [ - True, - { - 'OpticalPowerRx1Field': 0, 'OpticalPowerRx2Field': 0, - 'OpticalPowerRx3Field': 0, 'OpticalPowerRx4Field': 0, - 'OpticalPowerRx5Field': 0, 'OpticalPowerRx6Field': 0, - 'OpticalPowerRx7Field': 0, 'OpticalPowerRx8Field': 0 - } - ], - [0, 0, 0, 0, 0, 0, 0, 0] - ), - ([False, {'OpticalPowerRx1Field': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None) - ]) - def test_get_rx_power(self, mock_response, expected): - self.api.get_rx_power_support = MagicMock() - self.api.get_rx_power_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_rx_power() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_tx_fault_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_fault_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, {'TxFault1': 0}], [False]), - ([False, {'TxFault1': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None), - ([True, None], None) - ]) - def test_get_tx_fault(self, mock_response, expected): - self.api.get_tx_fault_support = MagicMock() - self.api.get_tx_fault_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_fault() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_tx_los_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_los_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, {'TxLOS1': 0}], [False]), - ([False, {'TxLOS1': 0}], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None), - ([True, None], None) - ]) - def test_get_tx_los(self, mock_response, expected): - self.api.get_tx_los_support = MagicMock() - self.api.get_tx_los_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_los() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([False, True], True) - ]) - def test_get_tx_disable_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_disable_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, 0x00], [False, False, False, False, False, False, False, False]), - ([False, 0x00], ['N/A','N/A','N/A','N/A','N/A','N/A','N/A','N/A']), - ([None, None], None), - ([True, None], None) - ]) - def test_get_tx_disable(self, mock_response, expected): - self.api.get_tx_disable_support = MagicMock() - self.api.get_tx_disable_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_disable() - assert result == expected - - @pytest.mark.parametrize("input_param",[ - (True), (False) - ]) - def test_tx_disable(self,input_param): - self.api.tx_disable(input_param) - - @pytest.mark.parametrize("mock_response, expected", [ - ([True, 0x00], 0), - ([False, 0x00], 'N/A'), - ([None, None], None) - ]) - def test_get_tx_disable_channel(self, mock_response, expected): - self.api.get_tx_disable_support = MagicMock() - self.api.get_tx_disable_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_tx_disable_channel() - assert result == expected - - @pytest.mark.parametrize("mock_response, input_param",[ - (0, (0xff, True)), - (0, (0, True)), - (None, (0, False)) - ]) - def test_tx_disable_channel(self, mock_response, input_param): - self.api.get_tx_disable_channel = MagicMock() - self.api.get_tx_disable_channel.return_value = mock_response - self.api.tx_disable_channel(*input_param) - - def test_get_power_override(self): - self.api.get_power_override() - - def test_set_power_override(self): - self.api.set_power_override(None, None) - @pytest.mark.parametrize("mock_response, expected", [ - (False, True) - ]) - def test_get_transceiver_thresholds_support(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response - result = self.api.get_transceiver_thresholds_support() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (None, False), - ('Power Class 1', False), - ('Power Class 8', True), - ]) - def test_get_lpmode_support(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_lpmode_support() - assert result == expected - - def test_get_power_override_support(self, ): - result = self.api.get_power_override_support() - assert result == False - - @pytest.mark.parametrize("mock_response, expected", [ - ("sm_media_interface", "sm_media_interface") - ]) - def test_get_module_media_type(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_module_media_type() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ("400GAUI-8 C2M (Annex 120E)", "400GAUI-8 C2M (Annex 120E)") - ]) - def test_get_host_electrical_interface(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_host_electrical_interface() - assert result == expected - - @pytest.mark.parametrize("mock_response1, mock_response2, expected", [ - ("sm_media_interface", "400ZR", "400ZR"), - ("nm_850_media_interface", "100GE BiDi", "100GE BiDi"), - ("passive_copper_media_interface", "Copper cable", "Copper cable"), - ("active_cable_media_interface", "Active Loopback module", "Active Loopback module"), - ("base_t_media_interface", "1000BASE-T (Clause 40)", "1000BASE-T (Clause 40)"), - ("ABCD", "ABCD", "Unknown media interface") - ]) - def test_get_module_media_interface(self, mock_response1, mock_response2, expected): - self.api.get_module_media_type = MagicMock() - self.api.get_module_media_type.return_value = mock_response1 - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response2 - result = self.api.get_module_media_interface() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ('Copper cable', False), - ('400ZR', True), - ]) - def test_is_coherent_module(self, mock_response, expected): - self.api.get_module_media_interface = MagicMock() - self.api.get_module_media_interface.return_value = mock_response - result = self.api.is_coherent_module() - assert result == expected - - @pytest.mark.parametrize("mock_response1, mock_response2, expected", [ - (True, '1', 0 ), - (False, None, 0), - (False, '5', 5.0), - (False, '60000', 60000.0), - ]) - def test_get_datapath_init_duration(self, mock_response1, mock_response2, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response1 - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response2 - result = self.api.get_datapath_init_duration() - assert result == expected - - @pytest.mark.parametrize("mock_response1, mock_response2, expected", [ - (True, '10', 0 ), - (False, None, 0), - (False, '50', 50.0), - (False, '6000000', 6000000.0), - ]) - def test_get_datapath_deinit_duration(self, mock_response1, mock_response2, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response1 - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response2 - result = self.api.get_datapath_deinit_duration() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (8, 8) - ]) - def test_get_host_lane_count(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_host_lane_count() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1) - ]) - def test_get_media_lane_count(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_media_lane_count() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ('C-band tunable laser', 'C-band tunable laser') - ]) - def test_get_media_interface_technology(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_media_interface_technology() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1) - ]) - def test_get_host_lane_assignment_option(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_host_lane_assignment_option() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1) - ]) - def test_get_media_lane_assignment_option(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_media_lane_assignment_option() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ({'ActiveAppSelLane1': 1}, - {'ActiveAppSelLane1': 1}) - ]) - def test_get_active_apsel_hostlane(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_active_apsel_hostlane() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (-10, -10) - ]) - def test_get_tx_config_power(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_tx_config_power() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, True), - (None, None), - ]) - def test_get_media_output_loopback(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_media_output_loopback() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, True), - (None, None), - ]) - def test_get_media_input_loopback(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_media_input_loopback() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (0x00, [False, False, False, False, False, False, False, False]), - (None, None), - ]) - def test_get_host_output_loopback(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_host_output_loopback() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (0x00, [False, False, False, False, False, False, False, False]), - (None, None), - ]) - def test_get_host_input_loopback(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_host_input_loopback() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (0xc2, (0,1,0)), - (None, None) - ]) - def test_get_aux_mon_type(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_aux_mon_type() - assert result == expected - - @pytest.mark.parametrize("mock_response1, mock_response2, expected", [ - ( - [0,1,0], - [11520, 20480, -2560, 19200, 0], - {'monitor value': 45, 'high alarm': 80, 'low alarm': -10, 'high warn': 75, 'low warn': 0} - ), - ( - [0,0,0], - [11520, 20480, -2560, 19200, 0], - {'monitor value': 45, 'high alarm': 80, 'low alarm': -10, 'high warn': 75, 'low warn': 0} - ), - ( - [0,1,1], - [11520, 20480, -2560, 19200, 0], - {'monitor value': 'N/A', 'high alarm': 'N/A', 'low alarm': 'N/A', 'high warn': 'N/A', 'low warn': 'N/A'} - ), - ]) - def test_get_laser_temperature(self, mock_response1, mock_response2, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - self.api.get_aux_mon_type = MagicMock() - self.api.get_aux_mon_type.return_value = mock_response1 - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response2 - result = self.api.get_laser_temperature() - assert result == expected - - @pytest.mark.parametrize("mock_response1, mock_response2, expected", [ - ( - [0,1,0], - [32767, 65534, 0, 49150.5, 0], - {'monitor value': 1, 'high alarm': 2, 'low alarm': 0, 'high warn': 1.5, 'low warn': 0} - ), - ( - [1,0,0], - [32767, 65534, 0, 49150.5, 0], - {'monitor value': 1, 'high alarm': 2, 'low alarm': 0, 'high warn': 1.5, 'low warn': 0} - ), - ( - [0,0,0], - [32767, 65534, 0, 49150.5, 0], - None - ), - ]) - def test_get_laser_TEC_current(self, mock_response1, mock_response2, expected): - self.api.get_aux_mon_type = MagicMock() - self.api.get_aux_mon_type.return_value = mock_response1 - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response2 - result = self.api.get_laser_TEC_current() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ({'ConfigStatusLane1': 'ConfigSuccess'}, - {'ConfigStatusLane1': 'ConfigSuccess'}) - ]) - def test_get_config_datapath_hostlane_status(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_config_datapath_hostlane_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ({'DP1State': 'DataPathActivated'}, - {'DP1State': 'DataPathActivated'}) - ]) - def test_get_datapath_state(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_datapath_state() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ({'DPInitPending1': 0}, {'DPInitPending1': False}), - (None, None) - ]) - def test_get_dpinit_pending(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_dpinit_pending() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([-20, 0], (-20,0)) - ]) - def test_get_supported_power_config(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_supported_power_config() - assert result == expected - - def test_reset_module(self): - self.api.reset_module(True) - - def test_reset(self): - self.api.xcvr_eeprom.write = MagicMock() - self.api.get_module_state = MagicMock() - self.api.get_module_state.return_value = 'ModuleReady' - result = self.api.reset() - assert result - assert self.api.xcvr_eeprom.write.call_count == 1 - kall = self.api.xcvr_eeprom.write.call_args - assert kall is not None - assert kall[0] == (consts.MODULE_LEVEL_CONTROL, 0x8) - - @pytest.mark.parametrize("lpmode", [ - ([True], [False]) - ]) - def test_set_low_power(self, lpmode): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = True - self.api.xcvr_eeprom.write = MagicMock() - self.api.xcvr_eeprom.write.return_value = True - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - self.api.get_lpmode_support = MagicMock() - self.api.get_lpmode_support.return_value = True - self.api.get_module_state = MagicMock() - self.api.get_module_state.return_value = "ModuleReady" - self.api.set_lpmode(lpmode) - - @pytest.mark.parametrize("mock_response, expected", [ - ( - - [False, 127], - { - 'simultaneous_host_media_loopback_supported': True, - 'per_lane_media_loopback_supported': True, - 'per_lane_host_loopback_supported': True, - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - } - ), - ([True, 0], None), - ([False, None], None) - ]) - def test_get_loopback_capability(self, mock_response, expected): - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[1] - result = self.api.get_loopback_capability() - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response",[ - ('none', { - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('host-side-input', { - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('host-side-output', { - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('media-side-input', { - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ('media-side-output', { - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }), - ( - 'none', None - ) - ]) - def test_set_loopback_mode(self, input_param, mock_response): - self.api.get_loopback_capability = MagicMock() - self.api.get_loopback_capability.return_value = mock_response - self.api.set_loopback_mode(input_param) - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - True, - {'Pre-FEC BER Average Media Input': {1: [0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}}, - ], - {'Pre-FEC BER Average Media Input': {1: [0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}} - ), - ( - [False, {}], {} - ) - ]) - def test_get_vdm(self, mock_response, expected): - self.api.get_vdm_support = MagicMock() - self.api.get_vdm_support.return_value = mock_response[0] - self.api.vdm = MagicMock() - self.api.vdm.get_vdm_allpage = MagicMock() - self.api.vdm.get_vdm_allpage.return_value = mock_response[1] - result = self.api.get_vdm() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, (False, False, True)) - ]) - def test_get_module_firmware_fault_state_changed(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.get_module_firmware_fault_state_changed() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([0, 0, 0], - { - 'voltage_flags': { - 'voltage_high_alarm_flag': False, - 'voltage_low_alarm_flag': False, - 'voltage_high_warn_flag': False, - 'voltage_low_warn_flag': False - }, - 'case_temp_flags': { - 'case_temp_high_alarm_flag': False, - 'case_temp_low_alarm_flag': False, - 'case_temp_high_warn_flag': False, - 'case_temp_low_warn_flag': False - }, - 'aux1_flags': { - 'aux1_high_alarm_flag': False, - 'aux1_low_alarm_flag': False, - 'aux1_high_warn_flag': False, - 'aux1_low_warn_flag': False - }, - 'aux2_flags': { - 'aux2_high_alarm_flag': False, - 'aux2_low_alarm_flag': False, - 'aux2_high_warn_flag': False, - 'aux2_low_warn_flag': False - }, - 'aux3_flags': { - 'aux3_high_alarm_flag': False, - 'aux3_low_alarm_flag': False, - 'aux3_high_warn_flag': False, - 'aux3_low_warn_flag': False - }, - 'custom_mon_flags': { - 'custom_mon_high_alarm_flag': False, - 'custom_mon_low_alarm_flag': False, - 'custom_mon_high_warn_flag': False, - 'custom_mon_low_warn_flag': False - } - }), - ([None, None, None], None) - ]) - def test_get_module_level_flag(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.get_module_level_flag() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ((128, 1, [0] * 128), {'status': True, 'info': "", 'result': 0}), - ((None, 1, [0] * 128), {'status': False, 'info': "", 'result': 0}), - ((128, None, [0] * 128), {'status': False, 'info': "", 'result': 0}), - ((128, 0, [0] * 128), {'status': False, 'info': "", 'result': None}), - ]) - def test_get_module_fw_info(self, mock_response, expected): - self.api.cdb = MagicMock() - self.api.cdb.cdb_chkcode = MagicMock() - self.api.cdb.cdb_chkcode.return_value = 1 - self.api.get_module_active_firmware = MagicMock() - self.api.get_module_active_firmware.return_value = "1.0" - self.api.get_module_inactive_firmware = MagicMock() - self.api.get_module_inactive_firmware.return_value = "1.1" - self.api.cdb.get_fw_info = MagicMock() - self.api.cdb.get_fw_info.return_value = mock_response - result = self.api.get_module_fw_info() - if result['status'] == False: # Check 'result' when 'status' == False for distinguishing error type. - assert result['result'] == expected['result'] - assert result['status'] == expected['status'] - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - (1, 1, (True, 'Module FW run: Success\n')), - (1, 64, (False, 'Module FW run: Fail\nFW_run_status 64\n')), - ]) - def test_module_fw_run(self, input_param, mock_response, expected): - self.api.cdb = MagicMock() - self.api.cdb.run_fw_image = MagicMock() - self.api.cdb.run_fw_image.return_value = mock_response - result = self.api.module_fw_run(input_param) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, (True, 'Module FW commit: Success\n')), - (64, (False, 'Module FW commit: Fail\nFW_commit_status 64\n')), - ]) - def test_module_fw_commit(self, mock_response, expected): - self.api.cdb = MagicMock() - self.api.cdb.commit_fw_image = MagicMock() - self.api.cdb.commit_fw_image.return_value = mock_response - result = self.api.module_fw_commit() - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ( - 'abc', - [{'status': True, 'info': '', 'result': ('a', 1, 1, 0, 'b', 0, 0, 0)}, {'status': True, 'info': '', 'result': (112, 2048, True, True, 2048)}, (True, ''), (True, '')], - (True, '') - ), - ( - 'abc', - [{'status': False, 'info': '', 'result': None}, {'status': True, 'info': '', 'result': (112, 2048, True, True, 2048)}, (True, ''), (True, '')], - (False, '') - ), - ( - 'abc', - [{'status': True, 'info': '', 'result': ('a', 1, 1, 0, 'b', 0, 0, 0)}, {'status': False, 'info': '', 'result': None}, (True, ''), (True, '')], - (False, '') - ), - ( - 'abc', - [{'status': True, 'info': '', 'result': ('a', 1, 1, 0, 'b', 0, 0, 0)}, {'status': True, 'info': '', 'result': (112, 2048, True, True, 2048)}, (False, ''), (True, '')], - (False, '') - ), - ]) - def test_module_fw_upgrade(self, input_param, mock_response, expected): - self.api.get_module_fw_info = MagicMock() - self.api.get_module_fw_info.return_value = mock_response[0] - self.api.get_module_fw_mgmt_feature = MagicMock() - self.api.get_module_fw_mgmt_feature.return_value = mock_response[1] - self.api.module_fw_download = MagicMock() - self.api.module_fw_download.return_value = mock_response[2] - self.api.module_fw_switch = MagicMock() - self.api.module_fw_switch.return_value = mock_response[3] - result = self.api.module_fw_upgrade(input_param) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ([None, None, None, None, None, None, None, None, None, None, None, None, None, None], None), - ( - [ - { - 'Extended Identifier': {'Power Class': 'Power Class 8', 'MaxPower': 20.0}, - 'Identifier': 'QSFP-DD Double Density 8X Pluggable Transceiver', - 'Identifier Abbreviation': 'QSFP-DD', - 'ModuleHardwareMajorRevision': 0, - 'ModuleHardwareMinorRevision': 0, - 'VendorSN': '00000000', - 'VendorName': 'VENDOR_NAME', - 'VendorPN': 'ABCD', - 'Connector': 'LC', - 'Length Cable Assembly': 0.0, - 'ModuleMediaType': 'sm_media_interface', - 'VendorDate': '21010100', - 'VendorOUI': 'xx-xx-xx' - }, - '400GAUI-8 C2M (Annex 120E)', - '400ZR, DWDM, amplified', - 8, 1, 1, 1, - {'ActiveAppSelLane1': 1, 'ActiveAppSelLane2': 1, 'ActiveAppSelLane3': 1, 'ActiveAppSelLane4': 1, - 'ActiveAppSelLane5': 1, 'ActiveAppSelLane6': 1, 'ActiveAppSelLane7': 1, 'ActiveAppSelLane8': 1}, - '1550 nm DFB', - '0.0', - '5.0', - '0.1', - '0.0', - 'sm_media_interface' - ], - { 'type': 'QSFP-DD Double Density 8X Pluggable Transceiver', - 'type_abbrv_name': 'QSFP-DD', - 'model': 'ABCD', - 'encoding': 'N/A', - 'ext_identifier': 'Power Class 8 (20.0W Max)', - 'ext_rateselect_compliance': 'N/A', - 'cable_type': 'Length Cable Assembly(m)', - 'cable_length': 0.0, - 'nominal_bit_rate': 0, - 'specification_compliance': 'sm_media_interface', - 'application_advertisement': 'N/A', - 'active_firmware': '0.1', - 'media_lane_count': 1, - 'inactive_firmware': '0.0', - 'vendor_rev': '0.0', - 'host_electrical_interface': '400GAUI-8 C2M (Annex 120E)', - 'vendor_oui': 'xx-xx-xx', - 'manufacturer': 'VENDOR_NAME', - 'media_interface_technology': '1550 nm DFB', - 'media_interface_code': '400ZR, DWDM, amplified', - 'serial': '00000000', - 'host_lane_count': 8, - 'active_apsel_hostlane1': 1, - 'active_apsel_hostlane3': 1, - 'active_apsel_hostlane2': 1, - 'active_apsel_hostlane5': 1, - 'active_apsel_hostlane4': 1, - 'active_apsel_hostlane7': 1, - 'active_apsel_hostlane6': 1, - 'active_apsel_hostlane8': 1, - 'hardware_rev': '0.0', - 'cmis_rev': '5.0', - 'media_lane_assignment_option': 1, - 'connector': 'LC', - 'host_lane_assignment_option': 1, - 'vendor_date': '21010100' - } - ) - ]) - def test_get_transceiver_info(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[0] - self.api.get_host_electrical_interface = MagicMock() - self.api.get_host_electrical_interface.return_value = mock_response[1] - self.api.get_module_media_interface = MagicMock() - self.api.get_module_media_interface.return_value = mock_response[2] - self.api.get_host_lane_count = MagicMock() - self.api.get_host_lane_count.return_value = mock_response[3] - self.api.get_media_lane_count = MagicMock() - self.api.get_media_lane_count.return_value = mock_response[4] - self.api.get_host_lane_assignment_option = MagicMock() - self.api.get_host_lane_assignment_option.return_value = mock_response[5] - self.api.get_media_lane_assignment_option = MagicMock() - self.api.get_media_lane_assignment_option.return_value = mock_response[6] - self.api.get_active_apsel_hostlane = MagicMock() - self.api.get_active_apsel_hostlane.return_value = mock_response[7] - self.api.get_media_interface_technology = MagicMock() - self.api.get_media_interface_technology.return_value = mock_response[8] - self.api.get_vendor_rev = MagicMock() - self.api.get_vendor_rev.return_value = mock_response[9] - self.api.get_cmis_rev = MagicMock() - self.api.get_cmis_rev.return_value = mock_response[10] - self.api.get_module_active_firmware = MagicMock() - self.api.get_module_active_firmware.return_value = mock_response[11] - self.api.get_module_inactive_firmware = MagicMock() - self.api.get_module_inactive_firmware.return_value = mock_response[12] - self.api.get_module_media_type = MagicMock() - self.api.get_module_media_type.return_value = mock_response[13] - self.api.get_module_hardware_revision = MagicMock() - self.api.get_module_hardware_revision.return_value = '0.0' - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - result = self.api.get_transceiver_info() - assert result == expected - # Test negative path - self.api.get_cmis_rev.return_value = None - result = self.api.get_transceiver_info() - assert result == None - - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - 0, - 50, - 3.3, - [70, 70, 70, 70, 70, 70, 70, 70], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - True, True, True, True, True, True, - {'monitor value': 40}, - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Minimum Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - 'Errored Frames Maximum Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - 'Errored Frames Current Value Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - } - ], - { - 'temperature': 50, - 'voltage': 3.3, - 'tx1power': -10.0, 'tx2power': -10.0, 'tx3power': -10.0, 'tx4power': -10.0, - 'tx5power': -10.0, 'tx6power': -10.0, 'tx7power': -10.0, 'tx8power': -10.0, - 'rx1power': -10.0, 'rx2power': -10.0, 'rx3power': -10.0, 'rx4power': -10.0, - 'rx5power': -10.0, 'rx6power': -10.0, 'rx7power': -10.0, 'rx8power': -10.0, - 'tx1bias': 70, 'tx2bias': 70, 'tx3bias': 70, 'tx4bias': 70, - 'tx5bias': 70, 'tx6bias': 70, 'tx7bias': 70, 'tx8bias': 70, - 'rx_los': False, - 'tx_fault': False, - 'tx1disable': False, 'tx2disable': False, 'tx3disable': False, 'tx4disable': False, - 'tx5disable': False, 'tx6disable': False, 'tx7disable': False, 'tx8disable': False, - 'tx_disabled_channel': 0, - 'laser_temperature': 40, - 'prefec_ber': 0.001, - 'postfec_ber_min': 0, - 'postfec_ber_max': 0, - 'postfec_ber_avg': 0, - 'postfec_curr_val': 0, - } - ), - ( - [ - ['N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'], - ['N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'], - ['N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'], - 'N/A', - 50, 3.3, - ['N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'], - ['N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'], - ['N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A', 'N/A'], - False, False, False, False, False, False, - {'monitor value': 40}, - None, - ], - { - 'temperature': 50, - 'voltage': 3.3, - 'tx1power': 'N/A', 'tx2power': 'N/A', 'tx3power': 'N/A', 'tx4power': 'N/A', - 'tx5power': 'N/A', 'tx6power': 'N/A', 'tx7power': 'N/A', 'tx8power': 'N/A', - 'rx1power': 'N/A', 'rx2power': 'N/A', 'rx3power': 'N/A', 'rx4power': 'N/A', - 'rx5power': 'N/A', 'rx6power': 'N/A', 'rx7power': 'N/A', 'rx8power': 'N/A', - 'tx1bias': 'N/A', 'tx2bias': 'N/A', 'tx3bias': 'N/A', 'tx4bias': 'N/A', - 'tx5bias': 'N/A', 'tx6bias': 'N/A', 'tx7bias': 'N/A', 'tx8bias': 'N/A', - 'rx_los': 'N/A', - 'tx_fault': 'N/A', - 'tx1disable': 'N/A', 'tx2disable': 'N/A', 'tx3disable': 'N/A', 'tx4disable': 'N/A', - 'tx5disable': 'N/A', 'tx6disable': 'N/A', 'tx7disable': 'N/A', 'tx8disable': 'N/A', - 'tx_disabled_channel': 'N/A', - 'laser_temperature': 40 - } - ) - ]) - def test_get_transceiver_bulk_status(self, mock_response, expected): - self.api.get_rx_los = MagicMock() - self.api.get_rx_los.return_value = mock_response[0] - self.api.get_tx_fault = MagicMock() - self.api.get_tx_fault.return_value = mock_response[1] - self.api.get_tx_disable = MagicMock() - self.api.get_tx_disable.return_value = mock_response[2] - self.api.get_tx_disable_channel = MagicMock() - self.api.get_tx_disable_channel.return_value = mock_response[3] - self.api.get_module_temperature = MagicMock() - self.api.get_module_temperature.return_value = mock_response[4] - self.api.get_voltage = MagicMock() - self.api.get_voltage.return_value = mock_response[5] - self.api.get_tx_bias = MagicMock() - self.api.get_tx_bias.return_value = mock_response[6] - self.api.get_rx_power = MagicMock() - self.api.get_rx_power.return_value = mock_response[7] - self.api.get_tx_power = MagicMock() - self.api.get_tx_power.return_value = mock_response[8] - self.api.get_rx_los_support = MagicMock() - self.api.get_rx_los_support.return_value = mock_response[9] - self.api.get_tx_fault_support = MagicMock() - self.api.get_tx_fault_support.return_value = mock_response[10] - self.api.get_tx_disable_support = MagicMock() - self.api.get_tx_disable_support.return_value = mock_response[11] - self.api.get_tx_bias_support = MagicMock() - self.api.get_tx_bias_support.return_value = mock_response[12] - self.api.get_tx_power_support = MagicMock() - self.api.get_tx_power_support.return_value = mock_response[13] - self.api.get_rx_power_support = MagicMock() - self.api.get_rx_power_support.return_value = mock_response[14] - self.api.get_laser_temperature = MagicMock() - self.api.get_laser_temperature.return_value = mock_response[15] - self.api.get_vdm = MagicMock() - self.api.get_vdm.return_value = mock_response[16] - result = self.api.get_transceiver_bulk_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - True, - { - 'TempHighAlarm': 80, 'TempLowAlarm': 0, 'TempHighWarning': 75, 'TempLowWarning': 10, - 'VoltageHighAlarm': 3.5, 'VoltageLowAlarm': 3.1, 'VoltageHighWarning': 3.45, 'VoltageLowWarning': 3.15, - 'RxPowerHighAlarm': 1.0, 'RxPowerLowAlarm': 0.01, 'RxPowerHighWarning': 1.0, 'RxPowerLowWarning': 0.01, - 'TxPowerHighAlarm': 1.0, 'TxPowerLowAlarm': 0.01, 'TxPowerHighWarning': 1.0, 'TxPowerLowWarning': 0.01, - 'TxHighAlarm': 90, 'TxLowAlarm': 10, 'TxHighWarning': 80, 'TxLowWarning': 20, - }, - 1, - {'high alarm': 80, 'low alarm': 10, 'high warn': 75, 'low warn': 20}, - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - } - ], - { - 'temphighalarm': 80, 'templowalarm': 0, 'temphighwarning': 75, 'templowwarning': 10, - 'vcchighalarm': 3.5, 'vcclowalarm': 3.1, 'vcchighwarning': 3.45, 'vcclowwarning': 3.15, - 'txpowerhighalarm': 0.0, 'txpowerlowalarm': -20.0, 'txpowerhighwarning': 0.0, 'txpowerlowwarning': -20.0, - 'rxpowerhighalarm': 0.0, 'rxpowerlowalarm': -20.0, 'rxpowerhighwarning': 0.0, 'rxpowerlowwarning': -20.0, - 'txbiashighalarm': 180, 'txbiaslowalarm': 20, 'txbiashighwarning': 160, 'txbiaslowwarning': 40, - 'lasertemphighalarm': 80, 'lasertemplowalarm': 10, 'lasertemphighwarning': 75, 'lasertemplowwarning': 20, - 'prefecberhighalarm': 0.0125, 'prefecberlowalarm': 0, 'prefecberhighwarning': 0.01, 'prefecberlowwarning': 0, - 'postfecberhighalarm': 1, 'postfecberlowalarm': 0, 'postfecberhighwarning': 1, 'postfecberlowwarning': 0, - } - ), - ([None, None, None, None, None], None), - ( - [False, None, None, None, None], - { - 'temphighalarm': 'N/A', 'templowalarm': 'N/A', 'temphighwarning': 'N/A', 'templowwarning': 'N/A', - 'vcchighalarm': 'N/A', 'vcclowalarm': 'N/A', 'vcchighwarning': 'N/A', 'vcclowwarning': 'N/A', - 'txpowerhighalarm': 'N/A', 'txpowerlowalarm': 'N/A', 'txpowerhighwarning': 'N/A', 'txpowerlowwarning': 'N/A', - 'rxpowerhighalarm': 'N/A', 'rxpowerlowalarm': 'N/A', 'rxpowerhighwarning': 'N/A', 'rxpowerlowwarning': 'N/A', - 'txbiashighalarm': 'N/A', 'txbiaslowalarm': 'N/A', 'txbiashighwarning': 'N/A', 'txbiaslowwarning': 'N/A', - } - ), - ([True, None, None, None, None], None) - ]) - def test_get_transceiver_threshold_info(self, mock_response, expected): - self.api.get_transceiver_thresholds_support = MagicMock() - self.api.get_transceiver_thresholds_support.return_value = mock_response[0] - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response[1:3] - self.api.get_laser_temperature = MagicMock() - self.api.get_laser_temperature.return_value = mock_response[3] - self.api.get_vdm = MagicMock() - self.api.get_vdm.return_value = mock_response[4] - result = self.api.get_transceiver_threshold_info() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - 'ModuleReady', 'No Fault detected', (False, False, True), - { - 'case_temp_flags': { - 'case_temp_high_alarm_flag': False, - 'case_temp_low_alarm_flag': False, - 'case_temp_high_warn_flag': False, - 'case_temp_low_warn_flag': False, - }, - 'voltage_flags': { - 'voltage_high_alarm_flag': False, - 'voltage_low_alarm_flag': False, - 'voltage_high_warn_flag': False, - 'voltage_low_warn_flag': False, - }, - 'aux1_flags': { - 'aux1_high_alarm_flag': False, - 'aux1_low_alarm_flag': False, - 'aux1_high_warn_flag': False, - 'aux1_low_warn_flag': False, - }, - 'aux2_flags': { - 'aux2_high_alarm_flag': False, - 'aux2_low_alarm_flag': False, - 'aux2_high_warn_flag': False, - 'aux2_low_warn_flag': False, - }, - 'aux3_flags': { - 'aux3_high_alarm_flag': False, - 'aux3_low_alarm_flag': False, - 'aux3_high_warn_flag': False, - 'aux3_low_warn_flag': False, - } - }, - (0, 0, 0), False, - {'DP1State': 'DataPathActivated', 'DP2State': 'DataPathActivated', - 'DP3State': 'DataPathActivated', 'DP4State': 'DataPathActivated', - 'DP5State': 'DataPathActivated', 'DP6State': 'DataPathActivated', - 'DP7State': 'DataPathActivated', 'DP8State': 'DataPathActivated'}, - { - 'TxOutputStatus1': True, 'TxOutputStatus2': True, - 'TxOutputStatus3': True, 'TxOutputStatus4': True, - 'TxOutputStatus5': True, 'TxOutputStatus6': True, - 'TxOutputStatus7': True, 'TxOutputStatus8': True - }, - { - 'RxOutputStatus1': True, 'RxOutputStatus2': True, - 'RxOutputStatus3': True, 'RxOutputStatus4': True, - 'RxOutputStatus5': True, 'RxOutputStatus6': True, - 'RxOutputStatus7': True, 'RxOutputStatus8': True - }, - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - { - 'ConfigStatusLane1': 'ConfigSuccess', 'ConfigStatusLane2': 'ConfigSuccess', - 'ConfigStatusLane3': 'ConfigSuccess', 'ConfigStatusLane4': 'ConfigSuccess', - 'ConfigStatusLane5': 'ConfigSuccess', 'ConfigStatusLane6': 'ConfigSuccess', - 'ConfigStatusLane7': 'ConfigSuccess', 'ConfigStatusLane8': 'ConfigSuccess' - }, - { - 'DPInitPending1': False, 'DPInitPending2': False, - 'DPInitPending3': False, 'DPInitPending4': False, - 'DPInitPending5': False, 'DPInitPending6': False, - 'DPInitPending7': False, 'DPInitPending8': False - }, - - { - 'tx_power_high_alarm': { - 'TxPowerHighAlarmFlag1': False, 'TxPowerHighAlarmFlag2': False, - 'TxPowerHighAlarmFlag3': False, 'TxPowerHighAlarmFlag4': False, - 'TxPowerHighAlarmFlag5': False, 'TxPowerHighAlarmFlag6': False, - 'TxPowerHighAlarmFlag7': False, 'TxPowerHighAlarmFlag8': False, - }, - 'tx_power_low_alarm': { - 'TxPowerLowAlarmFlag1': False, 'TxPowerLowAlarmFlag2': False, - 'TxPowerLowAlarmFlag3': False, 'TxPowerLowAlarmFlag4': False, - 'TxPowerLowAlarmFlag5': False, 'TxPowerLowAlarmFlag6': False, - 'TxPowerLowAlarmFlag7': False, 'TxPowerLowAlarmFlag8': False, - }, - 'tx_power_high_warn': { - 'TxPowerHighWarnFlag1': False, 'TxPowerHighWarnFlag2': False, - 'TxPowerHighWarnFlag3': False, 'TxPowerHighWarnFlag4': False, - 'TxPowerHighWarnFlag5': False, 'TxPowerHighWarnFlag6': False, - 'TxPowerHighWarnFlag7': False, 'TxPowerHighWarnFlag8': False, - }, - 'tx_power_low_warn': { - 'TxPowerLowWarnFlag1': False, 'TxPowerLowWarnFlag2': False, - 'TxPowerLowWarnFlag3': False, 'TxPowerLowWarnFlag4': False, - 'TxPowerLowWarnFlag5': False, 'TxPowerLowWarnFlag6': False, - 'TxPowerLowWarnFlag7': False, 'TxPowerLowWarnFlag8': False, - }, - }, - { - 'rx_power_high_alarm': { - 'RxPowerHighAlarmFlag1': False, 'RxPowerHighAlarmFlag2': False, - 'RxPowerHighAlarmFlag3': False, 'RxPowerHighAlarmFlag4': False, - 'RxPowerHighAlarmFlag5': False, 'RxPowerHighAlarmFlag6': False, - 'RxPowerHighAlarmFlag7': False, 'RxPowerHighAlarmFlag8': False, - }, - 'rx_power_low_alarm': { - 'RxPowerLowAlarmFlag1': False, 'RxPowerLowAlarmFlag2': False, - 'RxPowerLowAlarmFlag3': False, 'RxPowerLowAlarmFlag4': False, - 'RxPowerLowAlarmFlag5': False, 'RxPowerLowAlarmFlag6': False, - 'RxPowerLowAlarmFlag7': False, 'RxPowerLowAlarmFlag8': False, - }, - 'rx_power_high_warn': { - 'RxPowerHighWarnFlag1': False, 'RxPowerHighWarnFlag2': False, - 'RxPowerHighWarnFlag3': False, 'RxPowerHighWarnFlag4': False, - 'RxPowerHighWarnFlag5': False, 'RxPowerHighWarnFlag6': False, - 'RxPowerHighWarnFlag7': False, 'RxPowerHighWarnFlag8': False, - }, - 'rx_power_low_warn': { - 'RxPowerLowWarnFlag1': False, 'RxPowerLowWarnFlag2': False, - 'RxPowerLowWarnFlag3': False, 'RxPowerLowWarnFlag4': False, - 'RxPowerLowWarnFlag5': False, 'RxPowerLowWarnFlag6': False, - 'RxPowerLowWarnFlag7': False, 'RxPowerLowWarnFlag8': False, - }, - }, - { - 'tx_bias_high_alarm': { - 'TxBiasHighAlarmFlag1': False, 'TxBiasHighAlarmFlag2': False, - 'TxBiasHighAlarmFlag3': False, 'TxBiasHighAlarmFlag4': False, - 'TxBiasHighAlarmFlag5': False, 'TxBiasHighAlarmFlag6': False, - 'TxBiasHighAlarmFlag7': False, 'TxBiasHighAlarmFlag8': False, - }, - 'tx_bias_low_alarm': { - 'TxBiasLowAlarmFlag1': False, 'TxBiasLowAlarmFlag2': False, - 'TxBiasLowAlarmFlag3': False, 'TxBiasLowAlarmFlag4': False, - 'TxBiasLowAlarmFlag5': False, 'TxBiasLowAlarmFlag6': False, - 'TxBiasLowAlarmFlag7': False, 'TxBiasLowAlarmFlag8': False, - }, - 'tx_bias_high_warn': { - 'TxBiasHighWarnFlag1': False, 'TxBiasHighWarnFlag2': False, - 'TxBiasHighWarnFlag3': False, 'TxBiasHighWarnFlag4': False, - 'TxBiasHighWarnFlag5': False, 'TxBiasHighWarnFlag6': False, - 'TxBiasHighWarnFlag7': False, 'TxBiasHighWarnFlag8': False, - }, - 'tx_bias_low_warn': { - 'TxBiasLowWarnFlag1': False, 'TxBiasLowWarnFlag2': False, - 'TxBiasLowWarnFlag3': False, 'TxBiasLowWarnFlag4': False, - 'TxBiasLowWarnFlag5': False, 'TxBiasLowWarnFlag6': False, - 'TxBiasLowWarnFlag7': False, 'TxBiasLowWarnFlag8': False, - }, - }, - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - } - ], - { - 'module_state': 'ModuleReady', - 'module_fault_cause': 'No Fault detected', - 'datapath_firmware_fault': False, - 'module_firmware_fault': False, - 'module_state_changed': True, - 'DP1State': 'DataPathActivated', - 'DP2State': 'DataPathActivated', - 'DP3State': 'DataPathActivated', - 'DP4State': 'DataPathActivated', - 'DP5State': 'DataPathActivated', - 'DP6State': 'DataPathActivated', - 'DP7State': 'DataPathActivated', - 'DP8State': 'DataPathActivated', - 'txoutput_status1': True, - 'txoutput_status2': True, - 'txoutput_status3': True, - 'txoutput_status4': True, - 'txoutput_status5': True, - 'txoutput_status6': True, - 'txoutput_status7': True, - 'txoutput_status8': True, - 'rxoutput_status_hostlane1': True, - 'rxoutput_status_hostlane2': True, - 'rxoutput_status_hostlane3': True, - 'rxoutput_status_hostlane4': True, - 'rxoutput_status_hostlane5': True, - 'rxoutput_status_hostlane6': True, - 'rxoutput_status_hostlane7': True, - 'rxoutput_status_hostlane8': True, - 'txfault1': False, - 'txfault2': False, - 'txfault3': False, - 'txfault4': False, - 'txfault5': False, - 'txfault6': False, - 'txfault7': False, - 'txfault8': False, - 'txlos_hostlane1': False, - 'txlos_hostlane2': False, - 'txlos_hostlane3': False, - 'txlos_hostlane4': False, - 'txlos_hostlane5': False, - 'txlos_hostlane6': False, - 'txlos_hostlane7': False, - 'txlos_hostlane8': False, - 'txcdrlol_hostlane1': False, - 'txcdrlol_hostlane2': False, - 'txcdrlol_hostlane3': False, - 'txcdrlol_hostlane4': False, - 'txcdrlol_hostlane5': False, - 'txcdrlol_hostlane6': False, - 'txcdrlol_hostlane7': False, - 'txcdrlol_hostlane8': False, - 'rxlos1': False, - 'rxlos2': False, - 'rxlos3': False, - 'rxlos4': False, - 'rxlos5': False, - 'rxlos6': False, - 'rxlos7': False, - 'rxlos8': False, - 'rxcdrlol1': False, - 'rxcdrlol2': False, - 'rxcdrlol3': False, - 'rxcdrlol4': False, - 'rxcdrlol5': False, - 'rxcdrlol6': False, - 'rxcdrlol7': False, - 'rxcdrlol8': False, - 'config_state_hostlane1': 'ConfigSuccess', - 'config_state_hostlane2': 'ConfigSuccess', - 'config_state_hostlane3': 'ConfigSuccess', - 'config_state_hostlane4': 'ConfigSuccess', - 'config_state_hostlane5': 'ConfigSuccess', - 'config_state_hostlane6': 'ConfigSuccess', - 'config_state_hostlane7': 'ConfigSuccess', - 'config_state_hostlane8': 'ConfigSuccess', - 'dpinit_pending_hostlane1': False, - 'dpinit_pending_hostlane2': False, - 'dpinit_pending_hostlane3': False, - 'dpinit_pending_hostlane4': False, - 'dpinit_pending_hostlane5': False, - 'dpinit_pending_hostlane6': False, - 'dpinit_pending_hostlane7': False, - 'dpinit_pending_hostlane8': False, - 'temphighalarm_flag': False, 'templowalarm_flag': False, - 'temphighwarning_flag': False, 'templowwarning_flag': False, - 'vcchighalarm_flag': False, 'vcclowalarm_flag': False, - 'vcchighwarning_flag': False, 'vcclowwarning_flag': False, - 'lasertemphighalarm_flag': False, 'lasertemplowalarm_flag': False, - 'lasertemphighwarning_flag': False, 'lasertemplowwarning_flag': False, - 'txpowerhighalarm_flag1': False, 'txpowerlowalarm_flag1': False, - 'txpowerhighwarning_flag1': False, 'txpowerlowwarning_flag1': False, - 'txpowerhighalarm_flag2': False, 'txpowerlowalarm_flag2': False, - 'txpowerhighwarning_flag2': False, 'txpowerlowwarning_flag2': False, - 'txpowerhighalarm_flag3': False, 'txpowerlowalarm_flag3': False, - 'txpowerhighwarning_flag3': False, 'txpowerlowwarning_flag3': False, - 'txpowerhighalarm_flag4': False, 'txpowerlowalarm_flag4': False, - 'txpowerhighwarning_flag4': False, 'txpowerlowwarning_flag4': False, - 'txpowerhighalarm_flag5': False, 'txpowerlowalarm_flag5': False, - 'txpowerhighwarning_flag5': False, 'txpowerlowwarning_flag5': False, - 'txpowerhighalarm_flag6': False, 'txpowerlowalarm_flag6': False, - 'txpowerhighwarning_flag6': False, 'txpowerlowwarning_flag6': False, - 'txpowerhighalarm_flag7': False, 'txpowerlowalarm_flag7': False, - 'txpowerhighwarning_flag7': False, 'txpowerlowwarning_flag7': False, - 'txpowerhighalarm_flag8': False, 'txpowerlowalarm_flag8': False, - 'txpowerhighwarning_flag8': False, 'txpowerlowwarning_flag8': False, - 'rxpowerhighalarm_flag1': False, 'rxpowerlowalarm_flag1': False, - 'rxpowerhighwarning_flag1': False, 'rxpowerlowwarning_flag1': False, - 'rxpowerhighalarm_flag2': False, 'rxpowerlowalarm_flag2': False, - 'rxpowerhighwarning_flag2': False, 'rxpowerlowwarning_flag2': False, - 'rxpowerhighalarm_flag3': False, 'rxpowerlowalarm_flag3': False, - 'rxpowerhighwarning_flag3': False, 'rxpowerlowwarning_flag3': False, - 'rxpowerhighalarm_flag4': False, 'rxpowerlowalarm_flag4': False, - 'rxpowerhighwarning_flag4': False, 'rxpowerlowwarning_flag4': False, - 'rxpowerhighalarm_flag5': False, 'rxpowerlowalarm_flag5': False, - 'rxpowerhighwarning_flag5': False, 'rxpowerlowwarning_flag5': False, - 'rxpowerhighalarm_flag6': False, 'rxpowerlowalarm_flag6': False, - 'rxpowerhighwarning_flag6': False, 'rxpowerlowwarning_flag6': False, - 'rxpowerhighalarm_flag7': False, 'rxpowerlowalarm_flag7': False, - 'rxpowerhighwarning_flag7': False, 'rxpowerlowwarning_flag7': False, - 'rxpowerhighalarm_flag8': False, 'rxpowerlowalarm_flag8': False, - 'rxpowerhighwarning_flag8': False, 'rxpowerlowwarning_flag8': False, - 'txbiashighalarm_flag1': False, 'txbiaslowalarm_flag1': False, - 'txbiashighwarning_flag1': False, 'txbiaslowwarning_flag1': False, - 'txbiashighalarm_flag2': False, 'txbiaslowalarm_flag2': False, - 'txbiashighwarning_flag2': False, 'txbiaslowwarning_flag2': False, - 'txbiashighalarm_flag3': False, 'txbiaslowalarm_flag3': False, - 'txbiashighwarning_flag3': False, 'txbiaslowwarning_flag3': False, - 'txbiashighalarm_flag4': False, 'txbiaslowalarm_flag4': False, - 'txbiashighwarning_flag4': False, 'txbiaslowwarning_flag4': False, - 'txbiashighalarm_flag5': False, 'txbiaslowalarm_flag5': False, - 'txbiashighwarning_flag5': False, 'txbiaslowwarning_flag5': False, - 'txbiashighalarm_flag6': False, 'txbiaslowalarm_flag6': False, - 'txbiashighwarning_flag6': False, 'txbiaslowwarning_flag6': False, - 'txbiashighalarm_flag7': False, 'txbiaslowalarm_flag7': False, - 'txbiashighwarning_flag7': False, 'txbiaslowwarning_flag7': False, - 'txbiashighalarm_flag8': False, 'txbiaslowalarm_flag8': False, - 'txbiashighwarning_flag8': False, 'txbiaslowwarning_flag8': False, - 'prefecberhighalarm_flag': False, 'prefecberlowalarm_flag': False, - 'prefecberhighwarning_flag': False, 'prefecberlowwarning_flag': False, - 'postfecberhighalarm_flag': False, 'postfecberlowalarm_flag': False, - 'postfecberhighwarning_flag': False, 'postfecberlowwarning_flag': False, - } - ), - ( - [ - 'ModuleReady', 'No Fault detected', (False, False, True), - { - 'case_temp_flags': { - 'case_temp_high_alarm_flag': False, - 'case_temp_low_alarm_flag': False, - 'case_temp_high_warn_flag': False, - 'case_temp_low_warn_flag': False, - }, - 'voltage_flags': { - 'voltage_high_alarm_flag': False, - 'voltage_low_alarm_flag': False, - 'voltage_high_warn_flag': False, - 'voltage_low_warn_flag': False, - }, - 'aux1_flags': { - 'aux1_high_alarm_flag': False, - 'aux1_low_alarm_flag': False, - 'aux1_high_warn_flag': False, - 'aux1_low_warn_flag': False, - }, - 'aux2_flags': { - 'aux2_high_alarm_flag': False, - 'aux2_low_alarm_flag': False, - 'aux2_high_warn_flag': False, - 'aux2_low_warn_flag': False, - }, - 'aux3_flags': { - 'aux3_high_alarm_flag': False, - 'aux3_low_alarm_flag': False, - 'aux3_high_warn_flag': False, - 'aux3_low_warn_flag': False, - } - }, - (0, 0, 0), True, - {'DP1State': 'DataPathActivated', 'DP2State': 'DataPathActivated', - 'DP3State': 'DataPathActivated', 'DP4State': 'DataPathActivated', - 'DP5State': 'DataPathActivated', 'DP6State': 'DataPathActivated', - 'DP7State': 'DataPathActivated', 'DP8State': 'DataPathActivated'}, - {'TxOutputStatus1': True}, - { - 'RxOutputStatus1': True, 'RxOutputStatus2': True, - 'RxOutputStatus3': True, 'RxOutputStatus4': True, - 'RxOutputStatus5': True, 'RxOutputStatus6': True, - 'RxOutputStatus7': True, 'RxOutputStatus8': True - }, - [False], - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False], - [False], - [False], - { - 'ConfigStatusLane1': 'ConfigSuccess', 'ConfigStatusLane2': 'ConfigSuccess', - 'ConfigStatusLane3': 'ConfigSuccess', 'ConfigStatusLane4': 'ConfigSuccess', - 'ConfigStatusLane5': 'ConfigSuccess', 'ConfigStatusLane6': 'ConfigSuccess', - 'ConfigStatusLane7': 'ConfigSuccess', 'ConfigStatusLane8': 'ConfigSuccess' - }, - { - 'DPInitPending1': False, 'DPInitPending2': False, - 'DPInitPending3': False, 'DPInitPending4': False, - 'DPInitPending5': False, 'DPInitPending6': False, - 'DPInitPending7': False, 'DPInitPending8': False - }, - - { - 'tx_power_high_alarm': {'TxPowerHighAlarmFlag1': False}, - 'tx_power_low_alarm': {'TxPowerLowAlarmFlag1': False}, - 'tx_power_high_warn': {'TxPowerHighWarnFlag1': False}, - 'tx_power_low_warn': {'TxPowerLowWarnFlag1': False}, - }, - { - 'rx_power_high_alarm': {'RxPowerHighAlarmFlag1': False}, - 'rx_power_low_alarm': {'RxPowerLowAlarmFlag1': False}, - 'rx_power_high_warn': {'RxPowerHighWarnFlag1': False}, - 'rx_power_low_warn': {'RxPowerLowWarnFlag1': False}, - }, - { - 'tx_bias_high_alarm': {'TxBiasHighAlarmFlag1': False}, - 'tx_bias_low_alarm': {'TxBiasLowAlarmFlag1': False}, - 'tx_bias_high_warn': {'TxBiasHighWarnFlag1': False}, - 'tx_bias_low_warn': {'TxBiasLowWarnFlag1': False}, - }, - { - 'Pre-FEC BER Average Media Input':{1:[0.001, 0.0125, 0, 0.01, 0, False, False, False, False]}, - 'Errored Frames Average Media Input':{1:[0, 1, 0, 1, 0, False, False, False, False]}, - } - ], - { - 'module_state': 'ModuleReady', - 'module_fault_cause': 'No Fault detected', - 'datapath_firmware_fault': False, - 'module_firmware_fault': False, - 'module_state_changed': True, - 'temphighalarm_flag': False, 'templowalarm_flag': False, - 'temphighwarning_flag': False, 'templowwarning_flag': False, - 'vcchighalarm_flag': False, 'vcclowalarm_flag': False, - 'vcchighwarning_flag': False, 'vcclowwarning_flag': False, - 'lasertemphighalarm_flag': False, 'lasertemplowalarm_flag': False, - 'lasertemphighwarning_flag': False, 'lasertemplowwarning_flag': False, - } - ) - ]) - def test_get_transceiver_status(self, mock_response, expected): - self.api.get_module_state = MagicMock() - self.api.get_module_state.return_value = mock_response[0] - self.api.get_module_fault_cause = MagicMock() - self.api.get_module_fault_cause.return_value = mock_response[1] - self.api.get_module_firmware_fault_state_changed = MagicMock() - self.api.get_module_firmware_fault_state_changed.return_value = mock_response[2] - self.api.get_module_level_flag = MagicMock() - self.api.get_module_level_flag.return_value = mock_response[3] - self.api.get_aux_mon_type = MagicMock() - self.api.get_aux_mon_type.return_value = mock_response[4] - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = mock_response[5] - self.api.get_datapath_state = MagicMock() - self.api.get_datapath_state.return_value = mock_response[6] - self.api.get_tx_output_status = MagicMock() - self.api.get_tx_output_status.return_value = mock_response[7] - self.api.get_rx_output_status = MagicMock() - self.api.get_rx_output_status.return_value = mock_response[8] - self.api.get_tx_fault = MagicMock() - self.api.get_tx_fault.return_value = mock_response[9] - self.api.get_tx_los = MagicMock() - self.api.get_tx_los.return_value = mock_response[10] - self.api.get_tx_cdr_lol = MagicMock() - self.api.get_tx_cdr_lol.return_value = mock_response[11] - self.api.get_rx_los = MagicMock() - self.api.get_rx_los.return_value = mock_response[12] - self.api.get_rx_cdr_lol = MagicMock() - self.api.get_rx_cdr_lol.return_value = mock_response[13] - self.api.get_config_datapath_hostlane_status = MagicMock() - self.api.get_config_datapath_hostlane_status.return_value = mock_response[14] - self.api.get_dpinit_pending = MagicMock() - self.api.get_dpinit_pending.return_value = mock_response[15] - - self.api.get_tx_power_flag = MagicMock() - self.api.get_tx_power_flag.return_value = mock_response[16] - self.api.get_rx_power_flag = MagicMock() - self.api.get_rx_power_flag.return_value = mock_response[17] - self.api.get_tx_bias_flag = MagicMock() - self.api.get_tx_bias_flag.return_value = mock_response[18] - self.api.get_vdm = MagicMock() - self.api.get_vdm.return_value = mock_response[19] - result = self.api.get_transceiver_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected",[ - ( - [ - { - 'simultaneous_host_media_loopback_supported': True, - 'per_lane_media_loopback_supported': True, - 'per_lane_host_loopback_supported': True, - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True - }, - False, - False, - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False] - ], - { - 'simultaneous_host_media_loopback_supported': True, - 'per_lane_media_loopback_supported': True, - 'per_lane_host_loopback_supported': True, - 'host_side_input_loopback_supported': True, - 'host_side_output_loopback_supported': True, - 'media_side_input_loopback_supported': True, - 'media_side_output_loopback_supported': True, - 'media_output_loopback': False, - 'media_input_loopback': False, - 'host_output_loopback_lane1': False, - 'host_output_loopback_lane2': False, - 'host_output_loopback_lane3': False, - 'host_output_loopback_lane4': False, - 'host_output_loopback_lane5': False, - 'host_output_loopback_lane6': False, - 'host_output_loopback_lane7': False, - 'host_output_loopback_lane8': False, - 'host_input_loopback_lane1': False, - 'host_input_loopback_lane2': False, - 'host_input_loopback_lane3': False, - 'host_input_loopback_lane4': False, - 'host_input_loopback_lane5': False, - 'host_input_loopback_lane6': False, - 'host_input_loopback_lane7': False, - 'host_input_loopback_lane8': False - } - ), - ( - [None, None, None, None, None], - { - 'simultaneous_host_media_loopback_supported': 'N/A', - 'per_lane_media_loopback_supported': 'N/A', - 'per_lane_host_loopback_supported': 'N/A', - 'host_side_input_loopback_supported': 'N/A', - 'host_side_output_loopback_supported': 'N/A', - 'media_side_input_loopback_supported': 'N/A', - 'media_side_output_loopback_supported': 'N/A', - 'media_output_loopback': 'N/A', - 'media_input_loopback': 'N/A', - 'host_output_loopback_lane1': 'N/A', - 'host_output_loopback_lane2': 'N/A', - 'host_output_loopback_lane3': 'N/A', - 'host_output_loopback_lane4': 'N/A', - 'host_output_loopback_lane5': 'N/A', - 'host_output_loopback_lane6': 'N/A', - 'host_output_loopback_lane7': 'N/A', - 'host_output_loopback_lane8': 'N/A', - 'host_input_loopback_lane1': 'N/A', - 'host_input_loopback_lane2': 'N/A', - 'host_input_loopback_lane3': 'N/A', - 'host_input_loopback_lane4': 'N/A', - 'host_input_loopback_lane5': 'N/A', - 'host_input_loopback_lane6': 'N/A', - 'host_input_loopback_lane7': 'N/A', - 'host_input_loopback_lane8': 'N/A' - } - ), - ( - [ - { - 'simultaneous_host_media_loopback_supported': False, - 'per_lane_media_loopback_supported': False, - 'per_lane_host_loopback_supported': False, - 'host_side_input_loopback_supported': False, - 'host_side_output_loopback_supported': False, - 'media_side_input_loopback_supported': False, - 'media_side_output_loopback_supported': False - }, - False, - False, - [False, False, False, False, False, False, False, False], - [False, False, False, False, False, False, False, False] - ], - { - 'simultaneous_host_media_loopback_supported': False, - 'per_lane_media_loopback_supported': False, - 'per_lane_host_loopback_supported': False, - 'host_side_input_loopback_supported': False, - 'host_side_output_loopback_supported': False, - 'media_side_input_loopback_supported': False, - 'media_side_output_loopback_supported': False, - 'media_output_loopback': 'N/A', - 'media_input_loopback': 'N/A', - 'host_output_loopback_lane1': 'N/A', - 'host_output_loopback_lane2': 'N/A', - 'host_output_loopback_lane3': 'N/A', - 'host_output_loopback_lane4': 'N/A', - 'host_output_loopback_lane5': 'N/A', - 'host_output_loopback_lane6': 'N/A', - 'host_output_loopback_lane7': 'N/A', - 'host_output_loopback_lane8': 'N/A', - 'host_input_loopback_lane1': 'N/A', - 'host_input_loopback_lane2': 'N/A', - 'host_input_loopback_lane3': 'N/A', - 'host_input_loopback_lane4': 'N/A', - 'host_input_loopback_lane5': 'N/A', - 'host_input_loopback_lane6': 'N/A', - 'host_input_loopback_lane7': 'N/A', - 'host_input_loopback_lane8': 'N/A' - } - ) - ]) - def test_get_transceiver_loopback(self, mock_response, expected): - self.api.get_loopback_capability = MagicMock() - self.api.get_loopback_capability.return_value = mock_response[0] - self.api.get_media_output_loopback = MagicMock() - self.api.get_media_output_loopback.return_value = mock_response[1] - self.api.get_media_input_loopback = MagicMock() - self.api.get_media_input_loopback.return_value = mock_response[2] - self.api.get_host_output_loopback = MagicMock() - self.api.get_host_output_loopback.return_value = mock_response[3] - self.api.get_host_input_loopback = MagicMock() - self.api.get_host_input_loopback.return_value = mock_response[4] - result = self.api.get_transceiver_loopback() - assert result == expected - - def test_cable_len(self): - cable_len_field = self.mem_map.get_field(consts.LENGTH_ASSEMBLY_FIELD) - data = bytearray([0xFF]) - dep = {consts.LEN_MULT_FIELD: 0b11} - decoded = cable_len_field.decode(data, **dep) - assert decoded == 6300 - - def test_set_datapath_init(self): - self.api.xcvr_eeprom.write = MagicMock() - self.api.xcvr_eeprom.read = MagicMock() - - self.api.xcvr_eeprom.read.side_effect = [0x3, 0x00] - self.api.set_datapath_init(0xff) - kall = self.api.xcvr_eeprom.write.call_args - assert kall is not None - assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0xff) - - self.api.xcvr_eeprom.read.side_effect = [0x4, 0x00] - self.api.set_datapath_init(0xff) - kall = self.api.xcvr_eeprom.write.call_args - assert kall is not None - assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0x00) - - def test_set_datapath_deinit(self): - self.api.xcvr_eeprom.write = MagicMock() - self.api.xcvr_eeprom.read = MagicMock() - - self.api.xcvr_eeprom.read.side_effect = [0x3, 0x00] - self.api.set_datapath_deinit(0xff) - kall = self.api.xcvr_eeprom.write.call_args - assert kall is not None - assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0x00) - - self.api.xcvr_eeprom.read.side_effect = [0x4, 0x00] - self.api.set_datapath_deinit(0xff) - kall = self.api.xcvr_eeprom.write.call_args - assert kall is not None - assert kall[0] == (consts.DATAPATH_DEINIT_FIELD, 0xff) - - def test_get_application_advertisement(self): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = [ - { - consts.HOST_ELECTRICAL_INTERFACE + "_1": "400GAUI-8 C2M (Annex 120E)", - consts.MODULE_MEDIA_INTERFACE_SM + "_1": "400GBASE-DR4 (Cl 124)", - consts.MEDIA_LANE_COUNT + "_1": 4, - consts.HOST_LANE_COUNT + "_1": 8, - consts.HOST_LANE_ASSIGNMENT_OPTION + "_1": 0x01, - consts.MEDIA_LANE_ASSIGNMENT_OPTION + "_1": 0x02 - }, - Sff8024.MODULE_MEDIA_TYPE[2] - ] - result = self.api.get_application_advertisement() - - assert len(result) == 1 - assert result[1]['host_electrical_interface_id'] == '400GAUI-8 C2M (Annex 120E)' - assert result[1]['module_media_interface_id'] == '400GBASE-DR4 (Cl 124)' - assert result[1]['host_lane_count'] == 8 - assert result[1]['media_lane_count'] == 4 - assert result[1]['host_lane_assignment_options'] == 0x01 - assert result[1]['media_lane_assignment_options'] == 0x02 - - def test_get_application_advertisement_non_support(self): - self.api.xcvr_eeprom.read = MagicMock(return_value = None) - self.api.is_flat_memory = MagicMock(return_value = False) - result = self.api.get_application_advertisement() - assert result == {} - - def test_get_application(self): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = 0x20 - - self.api.is_flat_memory = MagicMock() - self.api.is_flat_memory.return_value = False - appl = self.api.get_application(0) - assert appl == 2 - - appl = self.api.get_application(2) - assert appl == 2 - - appl = self.api.get_application(self.api.NUM_CHANNELS) - assert appl == 0 - - self.api.is_flat_memory.return_value = True - appl = self.api.get_application(0) - assert appl == 0 - - appl = self.api.get_application(2) - assert appl == 0 - - appl = self.api.get_application(self.api.NUM_CHANNELS) - assert appl == 0 - - def test_set_application(self): - self.api.xcvr_eeprom.write = MagicMock() - - self.api.xcvr_eeprom.write.call_count = 0 - self.api.set_application(0x00, 1) - assert self.api.xcvr_eeprom.write.call_count == 1 - - self.api.xcvr_eeprom.write.call_count = 0 - self.api.set_application(0x01, 1) - assert self.api.xcvr_eeprom.write.call_count == 1 + 1 - - self.api.xcvr_eeprom.write.call_count = 0 - self.api.set_application(0x0f, 1) - assert self.api.xcvr_eeprom.write.call_count == 4 + 1 - - self.api.xcvr_eeprom.write.call_count = 0 - self.api.set_application(0xff, 1) - assert self.api.xcvr_eeprom.write.call_count == 8 + 1 - - self.api.xcvr_eeprom.write.call_count = 0 - self.api.set_application(0x7fffffff, 1) - assert self.api.xcvr_eeprom.write.call_count == self.api.NUM_CHANNELS + 1 - - def test_get_error_description(self): - self.api.get_module_state = MagicMock() - self.api.get_module_state.return_value = 'ModuleReady' - self.api.get_datapath_state = MagicMock() - self.api.get_datapath_state.return_value = { - 'DP1State': 'DataPathActivated', - 'DP2State': 'DataPathActivated', - 'DP3State': 'DataPathActivated', - 'DP4State': 'DataPathActivated', - 'DP5State': 'DataPathActivated', - 'DP6State': 'DataPathActivated', - 'DP7State': 'DataPathActivated', - 'DP8State': 'DataPathActivated' - } - self.api.get_config_datapath_hostlane_status = MagicMock() - self.api.get_config_datapath_hostlane_status.return_value = { - 'ConfigStatusLane1': 'ConfigSuccess', - 'ConfigStatusLane2': 'ConfigSuccess', - 'ConfigStatusLane3': 'ConfigSuccess', - 'ConfigStatusLane4': 'ConfigSuccess', - 'ConfigStatusLane5': 'ConfigSuccess', - 'ConfigStatusLane6': 'ConfigSuccess', - 'ConfigStatusLane7': 'ConfigSuccess', - 'ConfigStatusLane8': 'ConfigSuccess' - } - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = 0x10 - - result = self.api.get_error_description() - assert result is None diff --git a/tests/sonic_xcvr/test_cmisCDB.py b/tests/sonic_xcvr/test_cmisCDB.py deleted file mode 100644 index 6973e0245..000000000 --- a/tests/sonic_xcvr/test_cmisCDB.py +++ /dev/null @@ -1,213 +0,0 @@ -from mock import MagicMock -import pytest -from sonic_platform_base.sonic_xcvr.api.public.cmis import CmisApi -from sonic_platform_base.sonic_xcvr.api.public.cmisCDB import CmisCdbApi -from sonic_platform_base.sonic_xcvr.mem_maps.public.cmis import CmisMemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.codes.public.cmis import CmisCodes - -class TestCDB(object): - codes = CmisCodes - mem_map = CmisMemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = CmisCdbApi(eeprom) - - def test_cdb_is_none(self): - api = CmisApi(self.eeprom) - api.cdb = None - print(api) - print(api.get_module_fw_mgmt_feature()) - assert False == api.get_module_fw_mgmt_feature()['status'] - assert False == api.get_module_fw_info()['status'] - assert False == api.module_fw_run()[0] - assert False == api.module_fw_commit()[0] - assert False == api.module_fw_download(None, None, None, None, None, None)[0] - - - @pytest.mark.parametrize("mock_response, expected", [ - (64, False), - (0, True) - ]) - def test_cdb1_chkflags(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response - result = self.api.cdb1_chkflags() - assert result == expected - - - @pytest.mark.parametrize("input_param, expected", [ - (bytearray(b'\x00'), 255) - ]) - def test_cdb_chkcode(self, input_param, expected): - result = self.api.cdb_chkcode(input_param) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([1], 1), - ([128,128,1], 1) - ]) - def test_cdb1_chkstatus(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response - result = self.api.cdb1_chkstatus() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ( - [18, 35, (0, 7, 112, 255, 255, 16, 0, 0, 19, 136, 0, 100, 3, 232, 19, 136, 58, 152)], - (18, 35, (0, 7, 112, 255, 255, 16, 0, 0, 19, 136, 0, 100, 3, 232, 19, 136, 58, 152)) - ) - ]) - def test_read_cdb(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.side_effect = mock_response[0:2] - self.api.xcvr_eeprom.read_raw = MagicMock() - self.api.xcvr_eeprom.read_raw.return_value = mock_response[2] - result = self.api.read_cdb() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([1, (None, None, None)], (None, None, None)), - ([64, (None, None, None)], (None, None, None)), - ([128, (None, None, None)], (None, None, None)), - ]) - def test_query_cdb_status(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response[0] - self.api.read_cdb = MagicMock() - self.api.read_cdb.return_value = mock_response[1] - result = self.api.query_cdb_status() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1), - (64, 64), - (128, 128), - ]) - def test_module_enter_password(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.module_enter_password() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([1, (None, None, None)], (None, None, None)), - ([64, (None, None, None)], (None, None, None)), - ([128, (None, None, None)], (None, None, None)), - ]) - def test_get_module_feature(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response[0] - self.api.read_cdb = MagicMock() - self.api.read_cdb.return_value = mock_response[1] - result = self.api.get_module_feature() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([1, (None, None, None)], (None, None, None)), - ([64, (None, None, None)], (None, None, None)), - ([128, (None, None, None)], (None, None, None)), - ]) - def test_get_fw_management_features(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response[0] - self.api.read_cdb = MagicMock() - self.api.read_cdb.return_value = mock_response[1] - result = self.api.get_fw_management_features() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ([1, (None, None, None)], (None, None, None)), - ([64, (None, None, None)], (None, None, None)), - ([128, (None, None, None)], (None, None, None)), - ]) - def test_get_fw_info(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response[0] - self.api.read_cdb = MagicMock() - self.api.read_cdb.return_value = mock_response[1] - result = self.api.get_fw_info() - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ([3, bytearray(b'\x00\x00\x00'), 1000000], 1, 1), - ([3, bytearray(b'\x00\x00\x00'), 1000000], 64, 64), - ([3, bytearray(b'\x00\x00\x00'), 1000000], 128, 128), - ]) - def test_start_fw_download(self, input_param, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.start_fw_download(*input_param) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1), - (64, 64), - (128, 128), - ]) - def test_abort_fw_download(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.abort_fw_download() - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ([100, bytearray(116)], 1, 1), - ([100, bytearray(116)], 64, 64), - ([100, bytearray(116)], 128, 128), - ]) - def test_block_write_lpl(self, input_param, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.block_write_lpl(*input_param) - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ([100, bytearray(2048), True, 100], 1, 1), - ([100, bytearray(2047), False, 100], 64, 64), - ([100, bytearray(2047), False, 100], 128, 128), - ]) - def test_block_write_epl(self, input_param, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.block_write_epl(*input_param) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1), - (64, 64), - (128, 128), - ]) - def test_validate_fw_image(self, mock_response, expected): - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.validate_fw_image() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1), - (64, 64), - (128, 128), - ]) - def test_run_fw_image(self, mock_response, expected): - self.api.module_enter_password = MagicMock() - self.api.module_enter_password.return_value = 1 - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.run_fw_image() - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (1, 1), - (64, 64), - (128, 128), - ]) - def test_commit_fw_image(self, mock_response, expected): - self.api.module_enter_password = MagicMock() - self.api.module_enter_password.return_value = 1 - self.api.cdb1_chkstatus = MagicMock() - self.api.cdb1_chkstatus.return_value = mock_response - result = self.api.commit_fw_image() - assert result == expected diff --git a/tests/sonic_xcvr/test_cmisVDM.py b/tests/sonic_xcvr/test_cmisVDM.py deleted file mode 100644 index a71f9a593..000000000 --- a/tests/sonic_xcvr/test_cmisVDM.py +++ /dev/null @@ -1,154 +0,0 @@ -from mock import MagicMock -import pytest -from sonic_platform_base.sonic_xcvr.api.public.cmisVDM import CmisVdmApi -from sonic_platform_base.sonic_xcvr.mem_maps.public.cmis import CmisMemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.codes.public.cmis import CmisCodes - -class TestVDM(object): - codes = CmisCodes - mem_map = CmisMemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = CmisVdmApi(eeprom) - - @pytest.mark.parametrize("input_param, expected", [ - (0x9200, 0.000512) - ]) - def test_get_F16(self, input_param, expected): - result = self.api.get_F16(input_param) - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ( - [0x20, [0]*128], # input_param - [ # mock_response - ( - 16, 9, 16, 11, 16, 13, 16, 15, 32, 10, 33, 10, 0, 0, 0, 0, - 80,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 160,143,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ), - - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), bytearray(b'\x00\x00'), - ], - { - 'Pre-FEC BER Minimum Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Maximum Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Average Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Current Value Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Minimum Host Input': { - 1: [0, 0, 0, 0, 0, False, False, False, False], - 2: [0, 0, 0, 0, 0, False, False, False, False], - }, - 'Modulator Bias X/I [%]': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Tx Power [dBm]': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - } - ) - ]) - def test_get_vdm_page(self, input_param, mock_response, expected): - self.api.xcvr_eeprom.read_raw = MagicMock() - self.api.xcvr_eeprom.read_raw.side_effect = mock_response - result = self.api.get_vdm_page(*input_param) - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ( - [0x20, [0]*128], # input_param - [ # mock_response - ( - 16, 9, 16, 11, 16, 13, 16, 15, 32, 10, 33, 10, 0, 0, 0, 0, - 80,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 160,143,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ), - - None, - None, - None, - None, - None, - None, - None, - None, - ], - {} - ) - ]) - def test_get_vdm_page_none_vdm_value_raw(self, input_param, mock_response, expected): - self.api.xcvr_eeprom.read_raw = MagicMock() - self.api.xcvr_eeprom.read_raw.side_effect = mock_response - result = self.api.get_vdm_page(*input_param) - assert result == expected - - @pytest.mark.parametrize("input_param, mock_response, expected", [ - ( - [0x20, [0]*128], # input_param - [ # mock_response - None, - ], - {} - ) - ]) - def test_get_vdm_page_none_vdm_descriptor(self, input_param, mock_response, expected): - self.api.xcvr_eeprom.read_raw = MagicMock() - self.api.xcvr_eeprom.read_raw.side_effect = mock_response - result = self.api.get_vdm_page(*input_param) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - ( - [ # mock_response - 0, # vdm_page_supported_raw - ( # VDM_flag_page - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ), - { # VDM_current_page - 'Pre-FEC BER Minimum Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Maximum Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Average Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Current Value Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - } - ], - { # VDM_current_page - 'Pre-FEC BER Minimum Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Maximum Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Average Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - 'Pre-FEC BER Current Value Media Input': {1: [0, 0, 0, 0, 0, False, False, False, False]}, - } - - ) - ]) - def test_get_vdm_allpage(self, mock_response, expected): - self.api.xcvr_eeprom.read = MagicMock() - self.api.xcvr_eeprom.read.return_value = mock_response[0] - self.api.xcvr_eeprom.read_raw = MagicMock() - self.api.xcvr_eeprom.read_raw.return_value = mock_response[1] - # input_param = [0x20, mock_response[1]] - self.api.get_vdm_page = MagicMock() - self.api.get_vdm_page.side_effect = mock_response[2:] - result = self.api.get_vdm_allpage() - assert result == expected diff --git a/tests/sonic_xcvr/test_sff8436.py b/tests/sonic_xcvr/test_sff8436.py deleted file mode 100644 index 54d07f038..000000000 --- a/tests/sonic_xcvr/test_sff8436.py +++ /dev/null @@ -1,106 +0,0 @@ -from mock import MagicMock, patch -import pytest - - -from sonic_platform_base.sonic_xcvr.api.public.sff8436 import Sff8436Api -from sonic_platform_base.sonic_xcvr.codes.public.sff8436 import Sff8436Codes -from sonic_platform_base.sonic_xcvr.mem_maps.public.sff8436 import Sff8436MemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.fields import consts - -class TestSff8436(object): - codes = Sff8436Codes - mem_map = Sff8436MemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = Sff8436Api(eeprom) - - def test_api(self): - """ - Verify all api access valid fields - """ - self.api.get_model() - self.api.get_serial() - self.api.get_transceiver_info() - self.api.get_transceiver_bulk_status() - self.api.get_transceiver_threshold_info() - self.api.get_rx_los() - self.api.get_tx_fault() - self.api.get_tx_disable() - self.api.get_tx_disable_channel() - self.api.get_module_temperature() - self.api.get_voltage() - self.api.get_tx_bias() - self.api.get_tx_power() - self.api.get_rx_power() - self.api.tx_disable(True) - self.api.tx_disable_channel(0x5, True) - self.api.get_power_override() - self.api.get_power_set() - self.reader.return_value = bytearray([0xFF]) - self.api.set_power_override(True, True) - self.reader.return_value = None - self.api.is_flat_memory() - self.api.get_tx_power_support() - self.api.get_rx_power_support() - self.api.is_copper() - self.api.get_temperature_support() - self.api.get_voltage_support() - self.api.get_rx_los_support() - self.api.get_tx_bias_support() - self.api.get_tx_fault_support() - self.api.get_tx_disable_support() - self.api.get_transceiver_thresholds_support() - self.api.get_lpmode_support() - self.api.get_power_override_support() - - @pytest.mark.parametrize("mock_response, expected", [ - (bytearray([0x0]), "Power Class 1 Module (1.5W max. Power consumption)"), - (bytearray([0x40]), "Power Class 2 Module (2.0W max. Power consumption)"), - (bytearray([0x80]), "Power Class 3 Module (2.5W max. Power consumption)"), - (bytearray([0xC0]), "Power Class 4 Module (3.5W max. Power consumption)") - ]) - def test_power_class(self, mock_response, expected): - self.api.xcvr_eeprom.reader = MagicMock() - self.api.xcvr_eeprom.reader.return_value = mock_response - result = self.api.xcvr_eeprom.read(consts.POWER_CLASS_FIELD) - assert result == expected - - - @pytest.mark.parametrize("mock_response, expected", [ - (bytearray([0x02, 0x0]), "Longwave laser (LC)"), - (bytearray([0x01, 0x0]), "Electrical inter-enclosure (EN)"), - (bytearray([0x0, 0x80]), "Electrical intra-enclosure"), - (bytearray([0x0, 0x40]), "Shortwave laser w/o OFC (SN)"), - (bytearray([0x0, 0x20]), "Shortwave laser w OFC (SL)"), - (bytearray([0x0, 0x10]), "Longwave Laser (LL)") - ]) - def test_fiber_channel_transmitter_tech(self, mock_response, expected): - self.api.xcvr_eeprom.reader = MagicMock() - self.api.xcvr_eeprom.reader.return_value = mock_response - result = self.api.xcvr_eeprom.read(consts.FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD) - assert result == expected - - def test_is_copper(self): - with patch.object(self.api, 'xcvr_eeprom') as mock_eeprom: - mock_eeprom.read = MagicMock() - mock_eeprom.read.return_value = None - assert self.api.is_copper() is None - mock_eeprom.read.return_value = '40GBASE-CR4' - assert self.api.is_copper() - self.api._is_copper = None - mock_eeprom.read.return_value = 'SR' - assert not self.api.is_copper() - - def test_simulate_copper(self): - with patch.object(self.api, 'is_copper', return_value=True): - assert self.api.get_rx_power() == ['N/A'] * self.api.NUM_CHANNELS - assert self.api.get_module_temperature() == 'N/A' - assert self.api.get_voltage() == 'N/A' - assert not self.api.get_tx_power_support() - assert not self.api.get_rx_power_support() - assert not self.api.get_rx_power_support() - assert not self.api.get_temperature_support() - assert not self.api.get_voltage_support() - diff --git a/tests/sonic_xcvr/test_sff8472.py b/tests/sonic_xcvr/test_sff8472.py deleted file mode 100644 index add287f0a..000000000 --- a/tests/sonic_xcvr/test_sff8472.py +++ /dev/null @@ -1,188 +0,0 @@ -from mock import MagicMock -import sys -import pytest - -from sonic_platform_base.sonic_xcvr.api.public.sff8472 import Sff8472Api -from sonic_platform_base.sonic_xcvr.codes.public.sff8472 import Sff8472Codes -from sonic_platform_base.sonic_xcvr.fields.public.sff8472 import VoltageField -from sonic_platform_base.sonic_xcvr.mem_maps.public.sff8472 import Sff8472MemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.fields import consts - -class TestSff8472(object): - codes = Sff8472Codes - mem_map = Sff8472MemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = Sff8472Api(eeprom) - is_py2 = sys.version_info < (3,) - - def test_api(self): - """ - Verify all api access valid fields - """ - self.api.get_model() - self.api.get_serial() - self.api.get_transceiver_info() - self.api.get_transceiver_bulk_status() - self.api.get_transceiver_threshold_info() - self.api.get_rx_los() - self.api.get_tx_fault() - self.api.get_tx_disable() - self.api.get_tx_disable_channel() - self.api.get_module_temperature() - self.api.get_voltage() - self.api.get_tx_bias() - self.api.get_tx_power() - self.api.get_rx_power() - self.reader.return_value = bytearray([0xFF]) - self.api.tx_disable(True) - self.reader.return_value = None - self.api.tx_disable_channel(0x5, True) - self.api.is_flat_memory() - self.api.get_temperature_support() - self.api.get_voltage_support() - self.api.get_tx_power_support() - self.api.get_rx_power_support() - self.api.get_rx_los_support() - self.api.get_tx_bias_support() - self.api.get_tx_fault_support() - self.api.get_tx_disable_support() - self.api.get_transceiver_thresholds_support() - self.api.get_lpmode_support() - self.api.get_power_override_support() - - def test_temp(self): - temp_field = self.mem_map.get_field(consts.TEMPERATURE_FIELD) - data = bytearray([0x80, 0x00]) - deps = { - consts.INT_CAL_FIELD: True, - consts.EXT_CAL_FIELD: False, - consts.T_SLOPE_FIELD: 1, - consts.T_OFFSET_FIELD: 0, - } - decoded = temp_field.decode(data, **deps) - assert decoded == -128 - - data = bytearray([0x0F, 0xFF]) - deps = { - consts.INT_CAL_FIELD: False, - consts.EXT_CAL_FIELD: True, - consts.T_SLOPE_FIELD: 2, - consts.T_OFFSET_FIELD: 10, - } - decoded = temp_field.decode(data, **deps) - assert decoded == 32 if self.is_py2 else 32.03125 - - def test_voltage(self): - voltage_field = self.mem_map.get_field(consts.VOLTAGE_FIELD) - data = bytearray([0xFF, 0xFF]) - deps = { - consts.INT_CAL_FIELD: True, - consts.EXT_CAL_FIELD: False, - consts.T_SLOPE_FIELD: 1, - consts.T_OFFSET_FIELD: 0, - } - decoded = voltage_field.decode(data, **deps) - expected = 6 if self.is_py2 else 6.5535 - assert decoded == expected - - data = bytearray([0x7F, 0xFF]) - deps = { - consts.INT_CAL_FIELD: False, - consts.EXT_CAL_FIELD: True, - consts.V_SLOPE_FIELD: 2, - consts.V_OFFSET_FIELD: 10, - } - decoded = voltage_field.decode(data, **deps) - assert decoded == 6 if self.is_py2 else 6.5544 - - def test_tx_bias(self): - tx_bias_field = self.mem_map.get_field(consts.TX_BIAS_FIELD) - data = bytearray([0xFF, 0xFF]) - deps = { - consts.INT_CAL_FIELD: True, - consts.EXT_CAL_FIELD: False, - consts.TX_I_SLOPE_FIELD: 1, - consts.TX_I_OFFSET_FIELD: 0, - } - decoded = tx_bias_field.decode(data, **deps) - expected = 131 if self.is_py2 else 131.07 - assert decoded == expected - - data = bytearray([0x7F, 0xFF]) - deps = { - consts.INT_CAL_FIELD: False, - consts.EXT_CAL_FIELD: True, - consts.TX_I_SLOPE_FIELD: 2, - consts.TX_I_OFFSET_FIELD: 10, - } - decoded = tx_bias_field.decode(data, **deps) - assert decoded == 131 if self.is_py2 else 131.088 - - def test_tx_power(self): - tx_power_field = self.mem_map.get_field(consts.TX_POWER_FIELD) - data = bytearray([0xFF, 0xFF]) - deps = { - consts.INT_CAL_FIELD: True, - consts.EXT_CAL_FIELD: False, - consts.TX_PWR_SLOPE_FIELD: 1, - consts.TX_PWR_OFFSET_FIELD: 0, - } - decoded = tx_power_field.decode(data, **deps) - expected = 6 if self.is_py2 else 6.5535 - assert decoded == expected - - data = bytearray([0x7F, 0xFF]) - deps = { - consts.INT_CAL_FIELD: False, - consts.EXT_CAL_FIELD: True, - consts.TX_PWR_SLOPE_FIELD: 2, - consts.TX_PWR_OFFSET_FIELD: 10, - } - decoded = tx_power_field.decode(data, **deps) - assert decoded == 6 if self.is_py2 else 6.5544 - - def test_rx_power(self): - rx_power_field = self.mem_map.get_field(consts.RX_POWER_FIELD) - data = bytearray([0xFF, 0xFF]) - deps = { - consts.INT_CAL_FIELD: True, - consts.EXT_CAL_FIELD: False, - consts.RX_PWR_0_FIELD: 0, - consts.RX_PWR_1_FIELD: 1, - consts.RX_PWR_2_FIELD: 0, - consts.RX_PWR_3_FIELD: 0, - consts.RX_PWR_4_FIELD: 0, - } - decoded = rx_power_field.decode(data, **deps) - expected = 6 if self.is_py2 else 6.5535 - assert decoded == expected - - deps = { - consts.INT_CAL_FIELD: False, - consts.EXT_CAL_FIELD: True, - consts.RX_PWR_0_FIELD: 10, - consts.RX_PWR_1_FIELD: 2, - consts.RX_PWR_2_FIELD: 0.1, - consts.RX_PWR_3_FIELD: 0.01, - consts.RX_PWR_4_FIELD: 0.001, - } - decoded = rx_power_field.decode(data, **deps) - assert decoded == 209.713 - - @pytest.mark.parametrize("mock_response, expected", [ - (bytearray([0x04, 0x0]), "Shortwave laser, linear RX (SA)"), - (bytearray([0x02, 0x0]), "Longwave laser (LC)"), - (bytearray([0x01, 0x0]), "Electrical inter-enclosure (EL)"), - (bytearray([0x0, 0x80]), "Electrical intra-enclosure (EL)"), - (bytearray([0x0, 0x40]), "Shortwave laser w/o OFC (SN)"), - (bytearray([0x0, 0x20]), "Shortwave laser w OFC (SL)"), - (bytearray([0x0, 0x10]), "Longwave Laser (LL)") - ]) - def test_fiber_channel_transmitter_tech(self, mock_response, expected): - self.api.xcvr_eeprom.reader = MagicMock() - self.api.xcvr_eeprom.reader.return_value = mock_response - result = self.api.xcvr_eeprom.read(consts.FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD) - assert result == expected diff --git a/tests/sonic_xcvr/test_sff8636.py b/tests/sonic_xcvr/test_sff8636.py deleted file mode 100644 index 82ea1a7f2..000000000 --- a/tests/sonic_xcvr/test_sff8636.py +++ /dev/null @@ -1,107 +0,0 @@ -from mock import MagicMock, patch -import pytest - - -from sonic_platform_base.sonic_xcvr.api.public.sff8636 import Sff8636Api -from sonic_platform_base.sonic_xcvr.codes.public.sff8636 import Sff8636Codes -from sonic_platform_base.sonic_xcvr.mem_maps.public.sff8636 import Sff8636MemMap -from sonic_platform_base.sonic_xcvr.xcvr_eeprom import XcvrEeprom -from sonic_platform_base.sonic_xcvr.fields import consts - -class TestSff8636(object): - codes = Sff8636Codes - mem_map = Sff8636MemMap(codes) - reader = MagicMock(return_value=None) - writer = MagicMock() - eeprom = XcvrEeprom(reader, writer, mem_map) - api = Sff8636Api(eeprom) - - def test_api(self): - """ - Verify all api access valid fields - """ - self.api.get_model() - self.api.get_serial() - self.api.get_transceiver_info() - self.api.get_transceiver_bulk_status() - self.api.get_transceiver_threshold_info() - self.api.get_rx_los() - self.api.get_tx_fault() - self.api.get_tx_disable() - self.api.get_tx_disable_channel() - self.api.get_module_temperature() - self.api.get_voltage() - self.api.get_tx_bias() - self.api.get_tx_power() - self.api.get_rx_power() - self.api.tx_disable(True) - self.api.tx_disable_channel(0x5, True) - self.api.get_power_override() - self.api.get_power_set() - self.reader.return_value = bytearray([0xFF]) - self.api.set_power_override(True, True) - self.reader.return_value = None - self.api.is_flat_memory() - self.api.get_tx_power_support() - self.api.get_rx_power_support() - self.api.is_copper() - self.api.get_temperature_support() - self.api.get_voltage_support() - self.api.get_rx_los_support() - self.api.get_tx_bias_support() - self.api.get_tx_fault_support() - self.api.get_tx_disable_support() - self.api.get_transceiver_thresholds_support() - self.api.get_lpmode_support() - self.api.get_power_override_support() - - @pytest.mark.parametrize("mock_response, expected", [ - (bytearray([0x0]), "Power Class 1 Module (1.5W max.)"), - (bytearray([0x40]), "Power Class 2 Module (2.0W max.)"), - (bytearray([0x80]), "Power Class 3 Module (2.5W max.)"), - (bytearray([0xC0]), "Power Class 4 Module (3.5W max.)"), - (bytearray([0xC1]), "Power Class 5 Module (4.0W max.)"), - (bytearray([0xC2]), "Power Class 6 Module (4.5W max.)"), - (bytearray([0xC3]), "Power Class 7 Module (5.0W max.)"), - (bytearray([0x20]), "Power Class 8 Module") - ]) - def test_power_class(self, mock_response, expected): - self.api.xcvr_eeprom.reader = MagicMock() - self.api.xcvr_eeprom.reader.return_value = mock_response - result = self.api.xcvr_eeprom.read(consts.POWER_CLASS_FIELD) - assert result == expected - - @pytest.mark.parametrize("mock_response, expected", [ - (bytearray([0x02, 0x0]), "Longwave laser (LC)"), - (bytearray([0x01, 0x0]), "Electrical inter-enclosure (EN)"), - (bytearray([0x0, 0x80]), "Electrical intra-enclosure"), - (bytearray([0x0, 0x40]), "Shortwave laser w/o OFC (SN)"), - (bytearray([0x0, 0x20]), "Shortwave laser w OFC (SL)"), - (bytearray([0x0, 0x10]), "Longwave Laser (LL)") - ]) - def test_fiber_channel_transmitter_tech(self, mock_response, expected): - self.api.xcvr_eeprom.reader = MagicMock() - self.api.xcvr_eeprom.reader.return_value = mock_response - result = self.api.xcvr_eeprom.read(consts.FIBRE_CHANNEL_TRANSMITTER_TECH_FIELD) - assert result == expected - - def test_is_copper(self): - with patch.object(self.api, 'xcvr_eeprom') as mock_eeprom: - mock_eeprom.read = MagicMock() - mock_eeprom.read.return_value = None - assert self.api.is_copper() is None - mock_eeprom.read.return_value = '40GBASE-CR4' - assert self.api.is_copper() - self.api._is_copper = None - mock_eeprom.read.return_value = 'SR' - assert not self.api.is_copper() - - def test_simulate_copper(self): - with patch.object(self.api, 'is_copper', return_value=True): - assert self.api.get_rx_power() == ['N/A'] * self.api.NUM_CHANNELS - assert not self.api.get_tx_power_support() - assert not self.api.get_rx_power_support() - assert not self.api.get_rx_power_support() - assert not self.api.get_temperature_support() - assert not self.api.get_voltage_support() - diff --git a/tests/sonic_xcvr/test_xcvr_field.py b/tests/sonic_xcvr/test_xcvr_field.py deleted file mode 100644 index d137413b3..000000000 --- a/tests/sonic_xcvr/test_xcvr_field.py +++ /dev/null @@ -1,303 +0,0 @@ -from sonic_platform_base.sonic_xcvr.fields.xcvr_field import ( - CodeRegField, - DateField, - FixedNumberRegField, - HexRegField, - NumberRegField, - RegBitField, - RegGroupField, - StringRegField, -) -from sonic_platform_base.sonic_xcvr.codes.xcvr_codes import XcvrCodes -from sonic_platform_base.sonic_xcvr.mem_maps.xcvr_mem_map import XcvrMemMap - -class MockXcvrCodes(XcvrCodes): - CODE_DICT = { - 0: "Code0", - 1: "Code1" - - } - - SHIFTED_CODE_DICT = { - 0: "Code0", - 1: "Code1", - 2: "Code2", - 3: "Code3", - } - - DATAPATH_STATE = { - 1: 'DataPathDeactivated', - 2: 'DataPathInit', - 3: 'DataPathDeinit', - 4: 'DataPathActivated', - 5: 'DataPathTxTurnOn', - 6: 'DataPathTxTurnOff', - 7: 'DataPathInitialized', - } - -class MockXcvrMemMap(XcvrMemMap): - def __init__(self, codes): - super(MockXcvrMemMap, self).__init__(codes) - - self.CODE_REG = CodeRegField("CodeReg", 5, self.codes.CODE_DICT) - self.SHIFTED_CODE_REG = CodeRegField("ShiftedCodeReg", 50, self.codes.SHIFTED_CODE_DICT, - RegBitField("CodeBit7", bitpos=7), - RegBitField("CodeBit8", bitpos=8), - size=2, format=">H") - self.NUM_REG = NumberRegField("NumReg", 100, format=">Q", size=8, ro=False) - self.SCALE_NUM_REG = NumberRegField("ScaleNumReg", 120, format=">i", size=4, scale=100, ro=False) - self.FIXED_NUM_REG = FixedNumberRegField("FixedNumReg", 130, 8, format=">f", size=4, ro=False) - self.NUM_REG_WITH_BIT = NumberRegField("NumRegWithBit", 140, - RegBitField("NumRegBit", bitpos=20, ro=False), - format="