From e7cb18a8e6b1452a0c8f2512f0026830994c18ca Mon Sep 17 00:00:00 2001 From: vaibhav-dahiya Date: Mon, 28 Jun 2021 19:26:36 +0000 Subject: [PATCH 01/33] [Y-Cable][Credo] Credo implementation of YCable class which inherits from YCableBase required for Y-Cable API's in sonic-platform-daemons Signed-off-by: vaibhav-dahiya --- sonic_y_cable/credo/y_cable_credo.py | 2036 +++++++++++++++++++++++ sonic_y_cable/y_cable_vendor_mapping.py | 5 + 2 files changed, 2041 insertions(+) create mode 100644 sonic_y_cable/credo/y_cable_credo.py create mode 100644 sonic_y_cable/y_cable_vendor_mapping.py diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py new file mode 100644 index 000000000..223b7b32f --- /dev/null +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -0,0 +1,2036 @@ +""" + y_cable_credo.py + + Implementation of Credo Y-Cable +""" + +import math +import time +import struct +from ctypes import c_int8 +from sonic_y_cable.y_cable_base import YCableBase +from sonic_py_common import logger +try: + import sonic_platform.platform +except ImportError as e: + pass + + +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_IDENTFIER_LOWER_PAGE = 0 + OFFSET_INTERNAL_TEMPERATURE = 22 + OFFSET_INTERNAL_VOLTAGE = 26 + OFFSET_IDENTFIER_UPPER_PAGE = 128 + OFFSET_VENDOR_NAME = 148 + OFFSET_PART_NUMBER = 168 + 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_ENABLE_AUTO_SWITCH = 651 + OFFSET_AUTO_SWITCH_HYSTERESIS = 652 + 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_NIC_TEMPERATURE = 727 + OFFSET_NIC_VOLTAGE = 729 + 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_TARGET = 794 + OFFSET_ENABLE_LOOPBACK = 793 + + # 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_FWUPD = 0x80 + VSC_OPCODE_EVENTLOG = 0x81 + BER_TIMEOUT_SECS = 1 + EYE_TIMEOUT_SECS = 1 + + # error code of EEPROM + EEPROM_READ_DATA_INVALID = -1 + EEPROM_ERROR = -1 + EEPROM_TIMEOUT_ERROR = -1 + + # 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, logidentifier, logging_caller_name): + """ + Args: + port: + an Integer, the actual physical port connected to a Y cable + """ + YCableBase.__init__(self, port, "y_cable_credo_%d" % port) + + self.platform_chassis = None + + #self.helper_logger = logger.Logger("y_cable_credo_%d" % port) + self.helper_logger = logging_caller_name + + try: + self.platform_chassis = sonic_platform.platform.Platform().get_chassis() + self.helper_logger.log_info("chassis loaded {}".format(self.platform_chassis)) + except Exception as e: + self.helper_logger.log_warning("Failed to load chassis due to {}".format(repr(e))) + + def read_mmap(self, page, byte, len=1): + """ + This API specifically converts memory map page and offset to linar 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 addres, 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 == None: + self.helper_logger.log_error('Read Nack! page:%2X byte:%2X' % (page, byte)) + return 0xFF + else: + if len == 1: + try: + return ret[0] + except: + self.helper_logger.log_error('Unknown read_mmap error') + return 0xFF + else: + return ret + + def write_mmap(self, page, byte, value, len=1): + """ + This API specifically converts memory map page and offset to linar 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.helper_logger.log_error('Write Failed! page:%2X byte:%2X value:%2X' % (page, byte, value)) + + return ret + + def send_vsc_cmd(self, vsc_req_form, timeout=1200): + """ + This routine sends the vsc payload to MCU and returns the status code + + Args: + vsc_req_form: + a bytearray, command request form follow by vsc command structure + + timeout: + an Integer, number of 5ms delay time, default value is 1200 (6 seconds). + + Returns: + an Integer, status code of vsc command, find the 'MCU_ERROR_CODE_STRING' for the interpretation. + """ + + 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.helper_logger.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) + + return status + + 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: + result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") + return False + + 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: + result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") + return False + + 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: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to check read side") + return YCableBase.TARGET_UNKNOWN + + if result is not None: + if isinstance(result, bytearray): + if len(result) != 1: + self.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), self.port)) + return YCableBase.TARGET_UNKNOWN + else: + self.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), self.port)) + return YCableBase.TARGET_UNKNOWN + else: + self.helper_logger.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.helper_logger.log_info("Reading from TOR A") + return YCableBase.TARGET_TOR_A + elif ((regval_read[0] >> 1) & 0x01): + self.helper_logger.log_info("Reading from TOR B") + return YCableBase.TARGET_TOR_B + elif (regval_read[0] & 0x01): + self.helper_logger.log_info("Reading from NIC side") + return YCableBase.TARGET_NIC + else: + self.helper_logger.log_error("Error: unknown status for checking which side regval = {} ".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: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + else: + self.helper_logger.log_error( + "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") + return YCableBase.TARGET_UNKNOWN + + if result is not None: + if isinstance(result, bytearray): + if len(result) != 1: + self.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), self.port)) + return YCableBase.TARGET_UNKNOWN + else: + self.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), self.port)) + return YCableBase.TARGET_UNKNOWN + else: + self.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(self.port)) + return YCableBase.TARGET_UNKNOWN + + regval_read = struct.unpack(">B", result) + + if ((regval_read[0]) & 0x01): + self.helper_logger.log_info("mux pointing to TOR A") + return YCableBase.TARGET_TOR_A + elif regval_read[0] == 0: + self.helper_logger.log_info("mux pointing to TOR B") + return YCableBase.TARGET_TOR_B + else: + self.helper_logger.log_error("Error: unknown status for mux direction regval = {} ".format(result)) + return YCableBase.TARGET_UNKNOWN + + 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: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + else: + self.helper_logger.log_error( + "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") + return YCableBase.TARGET_UNKNOWN + + if result is not None: + if isinstance(result, bytearray): + if len(result) != 1: + self.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), self.port)) + return YCableBase.TARGET_UNKNOWN + else: + self.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), self.port)) + return YCableBase.TARGET_UNKNOWN + else: + self.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(self.port)) + return YCableBase.TARGET_UNKNOWN + + regval_read = struct.unpack(">B", result) + + if ((regval_read[0] >> 1) & 0x01): + self.helper_logger.log_info("TOR B active linked and actively routing") + return YCableBase.TARGET_TOR_B + elif ((regval_read[0]) & 0x01): + self.helper_logger.log_info("TOR A standby linked and actively routing") + return YCableBase.TARGET_TOR_A + elif regval_read[0] == 0: + self.helper_logger.log_info("Nothing linked for routing") + return YCableBase.TARGET_NIC + else: + self.helper_logger.log_error("Error: unknown status for active TOR regval = {} ".format(result)) + return YCableBase.TARGET_UNKNOWN + + 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: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + else: + self.helper_logger.log_error( + "platform_chassis is not loaded, failed to check if link is Active on target side") + return YCableBase.TARGET_UNKNOWN + + if result is not None: + if isinstance(result, bytearray): + if len(result) != 1: + self.helper_logger.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.helper_logger.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.helper_logger.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 YCableBase.TARGET_UNKNOWN + + regval_read = struct.unpack(">B", result) + + if (regval_read[0] & 0x01): + self.helper_logger.log_info("NIC link is up") + return True + elif ((regval_read[0] >> 2) & 0x01): + self.helper_logger.log_info("TOR A link is up") + return True + elif ((regval_read[0] >> 1) & 0x01): + self.helper_logger.log_info("TOR B link is up") + return True + 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: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + 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: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get Vendor name") + return -1 + + 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: + part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) + else: + self.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 + + 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 + """ + if switch_count_type == YCableBase.SWITCH_COUNT_MANUAL: + curr_offset = YCable.OFFSET_MANUAL_SWITCH_COUNT + elif switch_count_type == YCableBase.SWITCH_COUNT_AUTO: + curr_offset = YCable.OFFSET_AUTO_SWITCH_COUNT + else: + self.helper_logger.log_error("not a valid switch_count_type, failed to get switch count") + return -1 + + count = 0 + + if self.platform_chassis is not None: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to get manual switch count") + return -1 + + 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 + """ + + 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 + """ + curr_offset = YCable.OFFSET_NIC_CURSOR_VALUES + + result = [] + + if self.platform_chassis is not None: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") + return -1 + + 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: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") + return -1 + + 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 + + """ + 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_cmd(vsc_req_form) + + data = bytearray(YCable.FIRMWARE_INFO_PAYLOAD_SIZE) + + if self.platform_chassis is not None: + 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.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 * (YCable.FIRMWARE_INFO_PAYLOAD_SIZE / NUM_MCU_SIDE)) + rev_major_slot1 = struct.unpack_from('> 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_cmd(vsc_req_form) + + if status == YCable.MCU_EC_NO_ERROR: + chunk_idx += 1 + retry_count = 0 + else: + self.helper_logger.log_error('Firmware binary transfer error (error code:%04X)' % (status)) + + if retry_count == 3: + self.helper_logger.log_error('Retry Xfer Fw Bin Error, abort firmware update') + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE + retry_count += 1 + + ''' + Complete the local side firmware transferring + ''' + 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_cmd(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.helper_logger.log_error('Veriyf firmware binary error (error code:0x%04X)' % (status)) + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE + + ''' + transfer firmware image from local side MCU to the other two via UART + ''' + 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_cmd(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.helper_logger.log_error('Firmware binary UART transfer error (error code:0x%04X)' % (status)) + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE + + 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_cmd(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.helper_logger.log_error( + 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE + + busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) + percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) + percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) + percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) + + while busy != 0: + 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_cmd(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.helper_logger.log_error( + 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE + + time.sleep(0.2) + busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) + percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) + percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) + percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) + + 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 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 + """ + side = 0x7 + + 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 + status = self.send_vsc_cmd(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.helper_logger.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + 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 + vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless + status = self.send_vsc_cmd(vsc_req_form) + time.sleep(5) + if status != YCable.MCU_EC_NO_ERROR: + self.helper_logger.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + + return YCableBase.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 + """ + self.activate_firmware() + + return YCableBase.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. + """ + + if mode == YCableBase.SWITCHING_MODE_AUTO: + buffer = bytearray([1]) + elif mode == YCableBase.SWITCHING_MODE_MANUAL: + buffer = bytearray([0]) + else: + self.helper_logger.log_error( + "ERR: invalid mode provided for autoswitch feature, failed to do a switch") + return False + + curr_offset = YCable.OFFSET_ENABLE_AUTO_SWITCH + + if self.platform_chassis is not None: + result = self.platform_chassis.get_sfp( + self.port).write_eeprom(curr_offset, 1, buffer) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to do a switch target") + return False + + return result + + 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. + """ + curr_offset = YCable.OFFSET_ENABLE_AUTO_SWITCH + + if self.platform_chassis is not None: + result = self.platform_chassis.get_sfp( + self.port).read_eeprom(curr_offset, 1) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get the switch mode") + return -1 + + if result[0] == 1: + return YCableBase.SWITCHING_MODE_AUTO + else: + return YCableBase.SWITCHING_MODE_MANUAL + + 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 + """ + + curr_offset = YCable.OFFSET_NIC_TEMPERATURE + if self.platform_chassis is not None: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + temp = result[0] + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC temp") + return -1 + + return temp + + 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 + """ + + curr_offset = YCable.OFFSET_INTERNAL_TEMPERATURE + if self.platform_chassis is not None: + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + temp = result[0] + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get local temp") + return -1 + + return temp + + 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 + """ + + if self.platform_chassis is not None: + curr_offset = YCable.OFFSET_NIC_VOLTAGE + msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+1, 1) + voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC voltage") + return -1 + + return 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 + """ + + if self.platform_chassis is not None: + curr_offset = YCable.OFFSET_INTERNAL_VOLTAGE + msb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+1, 1) + voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get local voltage") + return -1 + + return 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 + """ + + 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_a=YCableBase.FEC_MODE_NONE, fec_mode_tor_b=YCableBase.FEC_MODE_NONE, + fec_mode_nic=YCableBase.FEC_MODE_NONE, anlt_tor_a=False, anlt_tor_b=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_a: + 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_tor_b: + One of the following predefined constants, the actual FEC mode for the ToR B 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: + 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_tor_b: + a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on ToR B + , False if auto-negotiation + link training (AN/LT) is not to be enabled on ToR B + + 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 + """ + + if (clear_on_read): + 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_cmd(vsc_req_form) + + last_read_id = -1 + result = [] + + 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', + } + + while (True): + 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_cmd(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.helper_logger.log_error("download event log error(error code:%04X)" % (status)) + return None + + 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(' 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 + """ + curr_offset = YCable.OFFSET_AUTO_SWITCH_HYSTERESIS + + buffer = bytearray([time]) + + if self.platform_chassis is not None: + self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC temp") + return -1 + + 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: + time = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) + else: + self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC temp") + return -1 + + return int(time[0]) + + def restart_anlt(self): + """ + 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=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: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + 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: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + 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_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 + """ + + buffer = bytearray([target]) + curr_offset = YCable.OFFSET_TARGET + + if self.platform_chassis is not None: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + 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: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + 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_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 + """ + + buffer = bytearray([target]) + curr_offset = YCable.OFFSET_TARGET + + ber_result = [] + + if self.platform_chassis is not None: + 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.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return ber_result + + def debug_dump_registers(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: + + 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 diff --git a/sonic_y_cable/y_cable_vendor_mapping.py b/sonic_y_cable/y_cable_vendor_mapping.py new file mode 100644 index 000000000..fef13d324 --- /dev/null +++ b/sonic_y_cable/y_cable_vendor_mapping.py @@ -0,0 +1,5 @@ +mapping = { + "Credo": { + "CACL2X321P2PA1MS": "credo.y_cable_credo" + } +} From b3aae8cad61155dbff050e2bce080a1356c31fce Mon Sep 17 00:00:00 2001 From: xinyu Date: Tue, 29 Jun 2021 22:45:36 +0800 Subject: [PATCH 02/33] [Y-Cable][Credo] fix LGTM alerts 4 for Unused local variable 4 for Variable defined multiple times 2 for Unreachable code 1 for Testing equality to None 1 for Except block handles 'BaseException' 1 for Unused import Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 32 +++++++++++----------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 223b7b32f..6a6c06335 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -9,7 +9,7 @@ import struct from ctypes import c_int8 from sonic_y_cable.y_cable_base import YCableBase -from sonic_py_common import logger + try: import sonic_platform.platform except ImportError as e: @@ -158,8 +158,6 @@ def __init__(self, port, logidentifier, logging_caller_name): YCableBase.__init__(self, port, "y_cable_credo_%d" % port) self.platform_chassis = None - - #self.helper_logger = logger.Logger("y_cable_credo_%d" % port) self.helper_logger = logging_caller_name try: @@ -193,14 +191,14 @@ def read_mmap(self, page, byte, len=1): ret = self.platform_chassis.get_sfp(self.port).read_eeprom(linear_addr, len) - if ret == None: + if ret is None: self.helper_logger.log_error('Read Nack! page:%2X byte:%2X' % (page, byte)) return 0xFF else: if len == 1: try: return ret[0] - except: + except Exception as e: self.helper_logger.log_error('Unknown read_mmap error') return 0xFF else: @@ -437,10 +435,8 @@ def get_mux_direction(self): elif regval_read[0] == 0: self.helper_logger.log_info("mux pointing to TOR B") return YCableBase.TARGET_TOR_B - else: - self.helper_logger.log_error("Error: unknown status for mux direction regval = {} ".format(result)) - return YCableBase.TARGET_UNKNOWN + self.helper_logger.log_error("Error: unknown status for mux direction regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN def get_active_linked_tor_side(self): @@ -495,10 +491,8 @@ def get_active_linked_tor_side(self): elif regval_read[0] == 0: self.helper_logger.log_info("Nothing linked for routing") return YCableBase.TARGET_NIC - else: - self.helper_logger.log_error("Error: unknown status for active TOR regval = {} ".format(result)) - return YCableBase.TARGET_UNKNOWN + self.helper_logger.log_error("Error: unknown status for active TOR regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN def is_link_active(self, target): @@ -866,7 +860,7 @@ def get_firmware_version(self, target): 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_cmd(vsc_req_form) + self.send_vsc_cmd(vsc_req_form) data = bytearray(YCable.FIRMWARE_INFO_PAYLOAD_SIZE) @@ -1031,9 +1025,9 @@ def download_firmware(self, fwfile): return YCableBase.FIRMWARE_DOWNLOAD_FAILURE busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) - percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) - percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) - percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) + self.read_mmap(YCable.MIS_PAGE_FC, 129) + self.read_mmap(YCable.MIS_PAGE_FC, 130) + self.read_mmap(YCable.MIS_PAGE_FC, 131) while busy != 0: vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) @@ -1047,9 +1041,9 @@ def download_firmware(self, fwfile): time.sleep(0.2) busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) - percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) - percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) - percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) + self.read_mmap(YCable.MIS_PAGE_FC, 129) + self.read_mmap(YCable.MIS_PAGE_FC, 130) + self.read_mmap(YCable.MIS_PAGE_FC, 131) return YCableBase.FIRMWARE_DOWNLOAD_SUCCESS @@ -1513,7 +1507,7 @@ def get_event_log(self, clear_on_read=False): 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_cmd(vsc_req_form) + self.send_vsc_cmd(vsc_req_form) last_read_id = -1 result = [] From 482da931b16e1a86b7a86e7a917bc43eb6301f68 Mon Sep 17 00:00:00 2001 From: vaibhav-dahiya Date: Wed, 30 Jun 2021 17:29:31 +0000 Subject: [PATCH 03/33] fix logging Signed-off-by: vaibhav-dahiya --- sonic_y_cable/credo/y_cable_credo.py | 170 ++++++++++++++------------- 1 file changed, 86 insertions(+), 84 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 6a6c06335..cea520989 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -9,7 +9,6 @@ import struct from ctypes import c_int8 from sonic_y_cable.y_cable_base import YCableBase - try: import sonic_platform.platform except ImportError as e: @@ -149,22 +148,21 @@ class YCable(YCableBase): MCU_EC_UNDEFINED_ERROR: 'Undefined Error', } - def __init__(self, port, logidentifier, logging_caller_name): + def __init__(self, port, main_logger): """ Args: port: an Integer, the actual physical port connected to a Y cable """ - YCableBase.__init__(self, port, "y_cable_credo_%d" % port) + YCableBase.__init__(self, port, main_logger) self.platform_chassis = None - self.helper_logger = logging_caller_name try: self.platform_chassis = sonic_platform.platform.Platform().get_chassis() - self.helper_logger.log_info("chassis loaded {}".format(self.platform_chassis)) + self.log_info("chassis loaded {}".format(self.platform_chassis)) except Exception as e: - self.helper_logger.log_warning("Failed to load chassis due to {}".format(repr(e))) + self.log_warning("Failed to load chassis due to {}".format(repr(e))) def read_mmap(self, page, byte, len=1): """ @@ -191,15 +189,15 @@ def read_mmap(self, page, byte, len=1): ret = self.platform_chassis.get_sfp(self.port).read_eeprom(linear_addr, len) - if ret is None: - self.helper_logger.log_error('Read Nack! page:%2X byte:%2X' % (page, byte)) + if ret == 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.helper_logger.log_error('Unknown read_mmap error') + except: + self.log_error('Unknown read_mmap error') return 0xFF else: return ret @@ -240,7 +238,7 @@ def write_mmap(self, page, byte, value, len=1): ret = self.platform_chassis.get_sfp(self.port).write_eeprom(linear_addr, len, ba) if (ret == False): - self.helper_logger.log_error('Write Failed! page:%2X byte:%2X value:%2X' % (page, byte, value)) + self.log_error('Write Failed! page:%2X byte:%2X value:%2X' % (page, byte, value)) return ret @@ -273,7 +271,7 @@ def send_vsc_cmd(self, vsc_req_form, timeout=1200): timeout -= 1 if timeout == 0: - self.helper_logger.log_error("wait vsc status value timeout") + 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) @@ -302,7 +300,7 @@ def toggle_mux_to_tor_a(self): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") + self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") return False return result @@ -327,7 +325,7 @@ def toggle_mux_to_tor_b(self): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") + self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") return False return result @@ -353,37 +351,37 @@ def get_read_side(self): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to check read side") + self.log_error("platform_chassis is not loaded, failed to check read side") return YCableBase.TARGET_UNKNOWN if result is not None: if isinstance(result, bytearray): if len(result) != 1: - self.helper_logger.log_error("Error: for checking mux_cable read side, eeprom read returned a size {} not equal to 1 for port {}".format( + 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.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( + 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.helper_logger.log_error( + 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.helper_logger.log_info("Reading from TOR A") + self.log_info("Reading from TOR A") return YCableBase.TARGET_TOR_A elif ((regval_read[0] >> 1) & 0x01): - self.helper_logger.log_info("Reading from TOR B") + self.log_info("Reading from TOR B") return YCableBase.TARGET_TOR_B elif (regval_read[0] & 0x01): - self.helper_logger.log_info("Reading from NIC side") + self.log_info("Reading from NIC side") return YCableBase.TARGET_NIC else: - self.helper_logger.log_error("Error: unknown status for checking which side regval = {} ".format(result)) + self.log_error("Error: unknown status for checking which side regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN @@ -408,35 +406,37 @@ def get_mux_direction(self): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: - self.helper_logger.log_error( + self.log_error( "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") return YCableBase.TARGET_UNKNOWN if result is not None: if isinstance(result, bytearray): if len(result) != 1: - self.helper_logger.log_error("Error: for checking mux_cable mux pointing side, eeprom read returned a size {} not equal to 1 for port {}".format( + 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.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( + 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.helper_logger.log_error( + 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.helper_logger.log_info("mux pointing to TOR A") + self.log_info("mux pointing to TOR A") return YCableBase.TARGET_TOR_A elif regval_read[0] == 0: - self.helper_logger.log_info("mux pointing to TOR B") + self.log_info("mux pointing to TOR B") return YCableBase.TARGET_TOR_B + else: + self.log_error("Error: unknown status for mux direction regval = {} ".format(result)) + return YCableBase.TARGET_UNKNOWN - self.helper_logger.log_error("Error: unknown status for mux direction regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN def get_active_linked_tor_side(self): @@ -461,38 +461,40 @@ def get_active_linked_tor_side(self): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: - self.helper_logger.log_error( + self.log_error( "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") return YCableBase.TARGET_UNKNOWN if result is not None: if isinstance(result, bytearray): if len(result) != 1: - self.helper_logger.log_error("Error: for checking mux_cable active linked side, eeprom read returned a size {} not equal to 1 for port {}".format( + 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.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( + 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.helper_logger.log_error( + 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.helper_logger.log_info("TOR B active linked and actively routing") + self.log_info("TOR B active linked and actively routing") return YCableBase.TARGET_TOR_B elif ((regval_read[0]) & 0x01): - self.helper_logger.log_info("TOR A standby linked and actively routing") + self.log_info("TOR A standby linked and actively routing") return YCableBase.TARGET_TOR_A elif regval_read[0] == 0: - self.helper_logger.log_info("Nothing linked for routing") + self.log_info("Nothing linked for routing") return YCableBase.TARGET_NIC + else: + self.log_error("Error: unknown status for active TOR regval = {} ".format(result)) + return YCableBase.TARGET_UNKNOWN - self.helper_logger.log_error("Error: unknown status for active TOR regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN def is_link_active(self, target): @@ -517,35 +519,35 @@ def is_link_active(self, target): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: - self.helper_logger.log_error( + self.log_error( "platform_chassis is not loaded, failed to check if link is Active on target side") return YCableBase.TARGET_UNKNOWN if result is not None: if isinstance(result, bytearray): if len(result) != 1: - self.helper_logger.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( + 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.helper_logger.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( + 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.helper_logger.log_error( + 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 YCableBase.TARGET_UNKNOWN regval_read = struct.unpack(">B", result) if (regval_read[0] & 0x01): - self.helper_logger.log_info("NIC link is up") + self.log_info("NIC link is up") return True elif ((regval_read[0] >> 2) & 0x01): - self.helper_logger.log_info("TOR A link is up") + self.log_info("TOR A link is up") return True elif ((regval_read[0] >> 1) & 0x01): - self.helper_logger.log_info("TOR B link is up") + self.log_info("TOR B link is up") return True else: return YCableBase.TARGET_UNKNOWN @@ -603,7 +605,7 @@ def get_eye_heights(self, target): eye_result.append(lane_result) idx += 2 else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") return YCable.EEPROM_ERROR return eye_result @@ -624,7 +626,7 @@ def get_vendor(self): if self.platform_chassis is not None: result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get Vendor name") + self.log_error("platform_chassis is not loaded, failed to get Vendor name") return -1 vendor_name = str(result.decode()) @@ -646,7 +648,7 @@ def get_part_number(self): if self.platform_chassis is not None: part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get part number") + self.log_error("platform_chassis is not loaded, failed to get part number") return -1 part_number = str(part_result.decode()) @@ -675,7 +677,7 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): elif switch_count_type == YCableBase.SWITCH_COUNT_AUTO: curr_offset = YCable.OFFSET_AUTO_SWITCH_COUNT else: - self.helper_logger.log_error("not a valid switch_count_type, failed to get switch count") + self.log_error("not a valid switch_count_type, failed to get switch count") return -1 count = 0 @@ -687,7 +689,7 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): 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.helper_logger.log_error("platform_chassis is not loaded, failed to get manual switch count") + self.log_error("platform_chassis is not loaded, failed to get manual switch count") return -1 return count @@ -794,7 +796,7 @@ def get_target_cursor_values(self, lane, target): 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.helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") + self.log_error("platform_chassis is not loaded, failed to get target cursor values") return -1 return result @@ -833,7 +835,7 @@ def set_target_cursor_values(self, lane, cursor_values, target): curr_offset + (target)*20 + (lane-1)*5 + idx, 1, buffer) idx += 1 else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") + self.log_error("platform_chassis is not loaded, failed to get target cursor values") return -1 return True @@ -860,7 +862,7 @@ def get_firmware_version(self, target): 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 - self.send_vsc_cmd(vsc_req_form) + status = self.send_vsc_cmd(vsc_req_form) data = bytearray(YCable.FIRMWARE_INFO_PAYLOAD_SIZE) @@ -870,7 +872,7 @@ def get_firmware_version(self, target): read_out = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) data[byte_idx] = read_out[0] else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC lanes active") + self.log_error("platform_chassis is not loaded, failed to get NIC lanes active") return -1 result = {} @@ -949,7 +951,7 @@ def download_firmware(self, fwfile): vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_START status = self.send_vsc_cmd(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE ''' @@ -986,10 +988,10 @@ def download_firmware(self, fwfile): chunk_idx += 1 retry_count = 0 else: - self.helper_logger.log_error('Firmware binary transfer error (error code:%04X)' % (status)) + self.log_error('Firmware binary transfer error (error code:%04X)' % (status)) if retry_count == 3: - self.helper_logger.log_error('Retry Xfer Fw Bin Error, abort firmware update') + self.log_error('Retry Xfer Fw Bin Error, abort firmware update') return YCableBase.FIRMWARE_DOWNLOAD_FAILURE retry_count += 1 @@ -1001,7 +1003,7 @@ def download_firmware(self, fwfile): vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_LOCAL_XFER_COMPLETE status = self.send_vsc_cmd(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error('Veriyf firmware binary error (error code:0x%04X)' % (status)) + self.log_error('Veriyf firmware binary error (error code:0x%04X)' % (status)) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE ''' @@ -1012,7 +1014,7 @@ def download_firmware(self, fwfile): vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_UART_XFER status = self.send_vsc_cmd(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error('Firmware binary UART transfer error (error code:0x%04X)' % (status)) + self.log_error('Firmware binary UART transfer error (error code:0x%04X)' % (status)) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) @@ -1020,14 +1022,14 @@ def download_firmware(self, fwfile): vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_UART_XFER_STATUS status = self.send_vsc_cmd(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error( + self.log_error( 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE 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) + percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) + percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) + percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) while busy != 0: vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) @@ -1035,15 +1037,15 @@ def download_firmware(self, fwfile): vsc_req_form[YCable.VSC_BYTE_OPTION] = YCable.FWUPD_OPTION_UART_XFER_STATUS status = self.send_vsc_cmd(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error( + self.log_error( 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE time.sleep(0.2) 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) + percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) + percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) + percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) return YCableBase.FIRMWARE_DOWNLOAD_SUCCESS @@ -1092,7 +1094,7 @@ def activate_firmware(self, fwfile=None, hitless=False): vsc_req_form[YCable.VSC_BYTE_ADDR0] = side status = self.send_vsc_cmd(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) return YCableBase.FIRMWARE_ACTIVATE_FAILURE vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) @@ -1103,7 +1105,7 @@ def activate_firmware(self, fwfile=None, hitless=False): status = self.send_vsc_cmd(vsc_req_form) time.sleep(5) if status != YCable.MCU_EC_NO_ERROR: - self.helper_logger.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) return YCableBase.FIRMWARE_ACTIVATE_FAILURE return YCableBase.FIRMWARE_ACTIVATE_SUCCESS @@ -1166,7 +1168,7 @@ def set_switching_mode(self, mode): elif mode == YCableBase.SWITCHING_MODE_MANUAL: buffer = bytearray([0]) else: - self.helper_logger.log_error( + self.log_error( "ERR: invalid mode provided for autoswitch feature, failed to do a switch") return False @@ -1176,7 +1178,7 @@ def set_switching_mode(self, mode): result = self.platform_chassis.get_sfp( self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to do a switch target") + self.log_error("platform_chassis is not loaded, failed to do a switch target") return False return result @@ -1199,7 +1201,7 @@ def get_switching_mode(self): result = self.platform_chassis.get_sfp( self.port).read_eeprom(curr_offset, 1) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get the switch mode") + self.log_error("platform_chassis is not loaded, failed to get the switch mode") return -1 if result[0] == 1: @@ -1223,7 +1225,7 @@ def get_nic_temperature(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) temp = result[0] else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC temp") + self.log_error("platform_chassis is not loaded, failed to get NIC temp") return -1 return temp @@ -1244,7 +1246,7 @@ def get_local_temperature(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) temp = result[0] else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get local temp") + self.log_error("platform_chassis is not loaded, failed to get local temp") return -1 return temp @@ -1266,7 +1268,7 @@ def get_nic_voltage(self): lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+1, 1) voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC voltage") + self.log_error("platform_chassis is not loaded, failed to get NIC voltage") return -1 return voltage @@ -1288,7 +1290,7 @@ def get_local_voltage(self): lsb_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset+1, 1) voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get local voltage") + self.log_error("platform_chassis is not loaded, failed to get local voltage") return -1 return voltage @@ -1507,7 +1509,7 @@ def get_event_log(self, clear_on_read=False): 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 - self.send_vsc_cmd(vsc_req_form) + status = self.send_vsc_cmd(vsc_req_form) last_read_id = -1 result = [] @@ -1542,7 +1544,7 @@ def get_event_log(self, clear_on_read=False): if (fetch_cnt == 0): break else: - self.helper_logger.log_error("download event log error(error code:%04X)" % (status)) + self.log_error("download event log error(error code:%04X)" % (status)) return None event_data = bytearray(YCable.EVENTLOG_PAYLOAD_SIZE * fetch_cnt) @@ -1633,7 +1635,7 @@ def set_autoswitch_hysteresis_timer(self, time): if self.platform_chassis is not None: self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC temp") + self.log_error("platform_chassis is not loaded, failed to get NIC temp") return -1 return True @@ -1655,7 +1657,7 @@ def get_autoswitch_hysteresis_timer(self): if self.platform_chassis is not None: time = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to get NIC temp") + self.log_error("platform_chassis is not loaded, failed to get NIC temp") return -1 return int(time[0]) @@ -1799,7 +1801,7 @@ def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.P self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") return -1 return result @@ -1841,7 +1843,7 @@ def disable_prbs_mode(self, target, direction): self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") return -1 return result @@ -1889,7 +1891,7 @@ def enable_loopback_mode(self, target, lane_mask, mode=YCableBase.LOOPBACK_MODE_ self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") return -1 return result @@ -1926,7 +1928,7 @@ def disable_loopback_mode(self, target): self.port).write_eeprom(curr_offset, 1, buffer) else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") return -1 return result @@ -2006,7 +2008,7 @@ def get_ber_info(self, target): ber_result.append(lane_result) idx += 2 else: - self.helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") return -1 return ber_result From 1962fc2fd657e5295bdebad64fc598d848067356 Mon Sep 17 00:00:00 2001 From: vaibhav-dahiya Date: Wed, 30 Jun 2021 17:58:50 +0000 Subject: [PATCH 04/33] fix LGTM Signed-off-by: vaibhav-dahiya --- sonic_y_cable/credo/y_cable_credo.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index cea520989..f9e149807 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -9,6 +9,7 @@ import struct from ctypes import c_int8 from sonic_y_cable.y_cable_base import YCableBase + try: import sonic_platform.platform except ImportError as e: @@ -189,14 +190,14 @@ def read_mmap(self, page, byte, len=1): ret = self.platform_chassis.get_sfp(self.port).read_eeprom(linear_addr, len) - if ret == None: + 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: + except Exception as e: self.log_error('Unknown read_mmap error') return 0xFF else: @@ -434,9 +435,8 @@ def get_mux_direction(self): self.log_info("mux pointing to TOR B") return YCableBase.TARGET_TOR_B else: - self.log_error("Error: unknown status for mux direction regval = {} ".format(result)) - return YCableBase.TARGET_UNKNOWN + self.log_error("Error: unknown status for mux direction regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN def get_active_linked_tor_side(self): @@ -491,10 +491,8 @@ def get_active_linked_tor_side(self): elif regval_read[0] == 0: self.log_info("Nothing linked for routing") return YCableBase.TARGET_NIC - else: - self.log_error("Error: unknown status for active TOR regval = {} ".format(result)) - return YCableBase.TARGET_UNKNOWN + self.log_error("Error: unknown status for active TOR regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN def is_link_active(self, target): @@ -862,7 +860,7 @@ def get_firmware_version(self, target): 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_cmd(vsc_req_form) + self.send_vsc_cmd(vsc_req_form) data = bytearray(YCable.FIRMWARE_INFO_PAYLOAD_SIZE) @@ -1027,9 +1025,9 @@ def download_firmware(self, fwfile): return YCableBase.FIRMWARE_DOWNLOAD_FAILURE busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) - percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) - percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) - percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) + self.read_mmap(YCable.MIS_PAGE_FC, 129) + self.read_mmap(YCable.MIS_PAGE_FC, 130) + self.read_mmap(YCable.MIS_PAGE_FC, 131) while busy != 0: vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) @@ -1043,9 +1041,9 @@ def download_firmware(self, fwfile): time.sleep(0.2) busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) - percentNIC = self.read_mmap(YCable.MIS_PAGE_FC, 129) - percentTOR1 = self.read_mmap(YCable.MIS_PAGE_FC, 130) - percentTOR2 = self.read_mmap(YCable.MIS_PAGE_FC, 131) + self.read_mmap(YCable.MIS_PAGE_FC, 129) + self.read_mmap(YCable.MIS_PAGE_FC, 130) + self.read_mmap(YCable.MIS_PAGE_FC, 131) return YCableBase.FIRMWARE_DOWNLOAD_SUCCESS @@ -1509,7 +1507,7 @@ def get_event_log(self, clear_on_read=False): 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_cmd(vsc_req_form) + self.send_vsc_cmd(vsc_req_form) last_read_id = -1 result = [] From 090862a382aebcaa3a181673c5caec1bf7d43cc3 Mon Sep 17 00:00:00 2001 From: vaibhav-dahiya Date: Wed, 30 Jun 2021 18:20:01 +0000 Subject: [PATCH 05/33] fix warning Signed-off-by: vaibhav-dahiya --- sonic_y_cable/credo/y_cable_credo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index f9e149807..0b2b14262 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -434,7 +434,6 @@ def get_mux_direction(self): elif regval_read[0] == 0: self.log_info("mux pointing to TOR B") return YCableBase.TARGET_TOR_B - else: self.log_error("Error: unknown status for mux direction regval = {} ".format(result)) return YCableBase.TARGET_UNKNOWN From 8bd5291761c5510ffc9228279719908a5c14ad13 Mon Sep 17 00:00:00 2001 From: xinyu Date: Thu, 1 Jul 2021 23:15:10 +0800 Subject: [PATCH 06/33] [Y-Cable][Credo] update vendor mapping table Signed-off-by: xinyu --- sonic_y_cable/y_cable_vendor_mapping.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/y_cable_vendor_mapping.py b/sonic_y_cable/y_cable_vendor_mapping.py index fef13d324..f758661ba 100644 --- a/sonic_y_cable/y_cable_vendor_mapping.py +++ b/sonic_y_cable/y_cable_vendor_mapping.py @@ -1,5 +1,14 @@ mapping = { "Credo": { - "CACL2X321P2PA1MS": "credo.y_cable_credo" + "CAC125321P2PA0MS": "credo.y_cable_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" } } From c2417dd8f3ef00a34c41e29e842a6100c8e60c4e Mon Sep 17 00:00:00 2001 From: xinyu Date: Fri, 2 Jul 2021 00:06:53 +0800 Subject: [PATCH 07/33] [Y_cable][Credo] implement get switch count functions Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 114 +++++++++++++++++---------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 0b2b14262..697b31944 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -20,35 +20,36 @@ 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_IDENTFIER_LOWER_PAGE = 0 - OFFSET_INTERNAL_TEMPERATURE = 22 - OFFSET_INTERNAL_VOLTAGE = 26 - OFFSET_IDENTFIER_UPPER_PAGE = 128 - OFFSET_VENDOR_NAME = 148 - OFFSET_PART_NUMBER = 168 + OFFSET_IDENTFIER_LOWER_PAGE = 0 + OFFSET_INTERNAL_TEMPERATURE = 22 + OFFSET_INTERNAL_VOLTAGE = 26 + OFFSET_IDENTFIER_UPPER_PAGE = 128 + OFFSET_VENDOR_NAME = 148 + OFFSET_PART_NUMBER = 168 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_ENABLE_AUTO_SWITCH = 651 - OFFSET_AUTO_SWITCH_HYSTERESIS = 652 - 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_NIC_TEMPERATURE = 727 - OFFSET_NIC_VOLTAGE = 729 - 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_TARGET = 794 - OFFSET_ENABLE_LOOPBACK = 793 + OFFSET_CHECK_LINK_ACTIVE = 641 + OFFSET_SWITCH_MUX_DIRECTION = 642 + OFFSET_MUX_DIRECTION = 644 + OFFSET_ACTIVE_TOR_INDICATOR = 645 + 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_LANE_ACTIVE = 721 + OFFSET_NIC_TEMPERATURE = 727 + OFFSET_NIC_VOLTAGE = 729 + OFFSET_MANUAL_SWITCH_COUNT_TOR_B = 737 + 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_TARGET = 794 + OFFSET_ENABLE_LOOPBACK = 793 # definition of VSC command byte VSC_BYTE_OPCODE = 128 @@ -669,24 +670,25 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): Returns: an integer, the number of times the Y-cable has been switched """ + + count = 0 + if switch_count_type == YCableBase.SWITCH_COUNT_MANUAL: - curr_offset = YCable.OFFSET_MANUAL_SWITCH_COUNT + 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 - else: - self.log_error("not a valid switch_count_type, failed to get switch count") - return -1 - count = 0 - - if self.platform_chassis is not None: - 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 self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get manual switch count") + return -1 else: - self.log_error("platform_chassis is not loaded, failed to get manual switch count") + self.log_error("not a valid switch_count_type, failed to get switch count") return -1 return count @@ -708,7 +710,20 @@ def get_switch_count_tor_a(self, clear_on_read=False): an integer, the number of times the Y-cable has been switched from ToR A """ - raise NotImplementedError + curr_offset = YCable.OFFSET_MANUAL_SWITCH_COUNT_TOR_A + count = 0 + + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get manual switch count") + return -1 + + return count def get_switch_count_tor_b(self, clear_on_read=False): """ @@ -727,7 +742,20 @@ def get_switch_count_tor_b(self, clear_on_read=False): an integer, the number of times the Y-cable has been switched from ToR B """ - raise NotImplementedError + curr_offset = YCable.OFFSET_MANUAL_SWITCH_COUNT_TOR_B + count = 0 + + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get manual switch count") + return -1 + + return count def get_switch_count_target(self, switch_count_type, target, clear_on_read=False): """ From 01b8be3886d029645a7e5804de6aa90ab3e64959 Mon Sep 17 00:00:00 2001 From: xinyu Date: Fri, 2 Jul 2021 18:19:52 +0800 Subject: [PATCH 08/33] [Y_cable[Credo] remove PT1 bulge cable PN Signed-off-by: xinyu --- sonic_y_cable/y_cable_vendor_mapping.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sonic_y_cable/y_cable_vendor_mapping.py b/sonic_y_cable/y_cable_vendor_mapping.py index f758661ba..98aa68ac9 100644 --- a/sonic_y_cable/y_cable_vendor_mapping.py +++ b/sonic_y_cable/y_cable_vendor_mapping.py @@ -1,11 +1,10 @@ mapping = { "Credo": { - "CAC125321P2PA0MS": "credo.y_cable_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", From 08cca5e2b85219668468262017c6c0a8d6378aaf Mon Sep 17 00:00:00 2001 From: xinyu Date: Fri, 2 Jul 2021 18:45:42 +0800 Subject: [PATCH 09/33] [Y_cable[Credo] update get_speed() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 697b31944..5a5a8f5b9 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -38,7 +38,7 @@ class YCable(YCableBase): OFFSET_NIC_CURSOR_VALUES = 661 OFFSET_TOR1_CURSOR_VALUES = 681 OFFSET_TOR2_CURSOR_VALUES = 701 - OFFSET_NIC_LANE_ACTIVE = 721 + OFFSET_NIC_MODE_CONFIGURATION = 721 OFFSET_NIC_TEMPERATURE = 727 OFFSET_NIC_VOLTAGE = 729 OFFSET_MANUAL_SWITCH_COUNT_TOR_B = 737 @@ -1424,7 +1424,23 @@ def get_speed(self): 100000 -> 100G """ - raise NotImplementedError + speed = 0 + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get NIC voltage") + return -1 + + return speed def set_fec_mode(self, fec_mode, target): """ From d7c4015b59aa1061b0834813ec7399c40ba9a4b1 Mon Sep 17 00:00:00 2001 From: xinyu Date: Sat, 3 Jul 2021 13:51:17 +0800 Subject: [PATCH 10/33] [Y_cable][Credo] implement get/set fec mode and AN/LT Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 213 ++++++++++++++++++--------- 1 file changed, 145 insertions(+), 68 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 5a5a8f5b9..b717e379e 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -52,31 +52,31 @@ class YCable(YCableBase): OFFSET_ENABLE_LOOPBACK = 793 # 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_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 + VSC_BYTE_OPTION = 140 # firmware upgrade command options - FWUPD_OPTION_GET_INFO = 0x01 - FWUPD_OPTION_START = 0x02 - FWUPD_OPTION_LOCAL_XFER = 0x03 + 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 + 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 @@ -108,46 +108,46 @@ class YCable(YCableBase): EEPROM_TIMEOUT_ERROR = -1 # 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_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_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_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', + 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): @@ -1437,7 +1437,7 @@ def get_speed(self): self.log_error("unsupported speed") return -1 else: - self.log_error("platform_chassis is not loaded, failed to get NIC voltage") + self.log_error("platform_chassis is not loaded, failed to get speed") return -1 return speed @@ -1465,7 +1465,28 @@ def set_fec_mode(self, fec_mode, target): , False if the FEC mode is not configured """ - raise NotImplementedError + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to set fec mode") + return False + + return True def get_fec_mode(self, target): """ @@ -1487,7 +1508,24 @@ def get_fec_mode(self, target): FEC_MODE_FC """ - raise NotImplementedError + fec_mode = YCableBase.FEC_MODE_NONE + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get fec mode") + return -1 + + return fec_mode def set_anlt(self, enable, target): """ @@ -1510,7 +1548,28 @@ def set_anlt(self, enable, target): , False if the auto-negotiation + link training (AN/LT) enable/disable specified is not configured """ - raise NotImplementedError + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to set anlt") + return False + + return True def get_anlt(self, target): """ @@ -1529,7 +1588,25 @@ def get_anlt(self, target): , False if auto-negotiation + link training (AN/LT) is not enabled """ - raise NotImplementedError + anlt_mode = False + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get anlt") + return -1 + + return anlt_mode def get_event_log(self, clear_on_read=False): """ @@ -1676,7 +1753,7 @@ def set_autoswitch_hysteresis_timer(self, time): if self.platform_chassis is not None: self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: - self.log_error("platform_chassis is not loaded, failed to get NIC temp") + self.log_error("platform_chassis is not loaded, failed to set autoswitch hysteresis timer") return -1 return True @@ -1698,7 +1775,7 @@ def get_autoswitch_hysteresis_timer(self): if self.platform_chassis is not None: time = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: - self.log_error("platform_chassis is not loaded, failed to get NIC temp") + self.log_error("platform_chassis is not loaded, failed to get autoswitch hysteresis timer") return -1 return int(time[0]) @@ -1842,7 +1919,7 @@ def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.P self.port).write_eeprom(curr_offset, 1, buffer) else: - self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to enable the PRBS mode") return -1 return result @@ -1884,7 +1961,7 @@ def disable_prbs_mode(self, target, direction): self.port).write_eeprom(curr_offset, 1, buffer) else: - self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to disable the PRBS mode") return -1 return result @@ -1932,7 +2009,7 @@ def enable_loopback_mode(self, target, lane_mask, mode=YCableBase.LOOPBACK_MODE_ self.port).write_eeprom(curr_offset, 1, buffer) else: - self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to enable the loopback mode") return -1 return result @@ -1969,7 +2046,7 @@ def disable_loopback_mode(self, target): self.port).write_eeprom(curr_offset, 1, buffer) else: - self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to disable the loopback mode") return -1 return result @@ -2049,7 +2126,7 @@ def get_ber_info(self, target): ber_result.append(lane_result) idx += 2 else: - self.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + self.log_error("platform_chassis is not loaded, failed to get ber info") return -1 return ber_result From e78bc68dbe34198c39567942f518590c4e18c0c9 Mon Sep 17 00:00:00 2001 From: xinyu Date: Sat, 3 Jul 2021 14:47:53 +0800 Subject: [PATCH 11/33] [Y_cable][Credo] implement reset() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index b717e379e..77cfb09d8 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1352,7 +1352,30 @@ def reset(self, target): , False if the cable target is not reset """ - raise NotImplementedError + ''' + use firmare_run cmd to emulate module reset + ''' + 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 + + 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_cmd(vsc_req_form) + + if target == YCableBase.TARGET_NIC: + time.sleep(4) + else: + time.sleep(2) + + if status != YCable.MCU_EC_NO_ERROR: + self.log_error("unable to reset the module") + return False + + return True def create_port(self, speed, fec_mode_tor_a=YCableBase.FEC_MODE_NONE, fec_mode_tor_b=YCableBase.FEC_MODE_NONE, fec_mode_nic=YCableBase.FEC_MODE_NONE, anlt_tor_a=False, anlt_tor_b=False, anlt_nic=False): From a3d976a0be3b1b0bb6c74a1385b1912b2f29503f Mon Sep 17 00:00:00 2001 From: xinyu Date: Sat, 3 Jul 2021 15:11:28 +0800 Subject: [PATCH 12/33] [Y_cable][Credo] enable_prbs_mode: need to disable prbe mode first then change the prbs pattern Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 77cfb09d8..4f5dca941 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1370,7 +1370,7 @@ def reset(self, target): time.sleep(4) else: time.sleep(2) - + if status != YCable.MCU_EC_NO_ERROR: self.log_error("unable to reset the module") return False @@ -1926,20 +1926,23 @@ def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.P curr_offset = YCable.OFFSET_TARGET if self.platform_chassis is not None: - result = self.platform_chassis.get_sfp( - self.port).write_eeprom(curr_offset, 1, buffer) + 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) + 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) + 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) + result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error("platform_chassis is not loaded, failed to enable the PRBS mode") From a4789a194aad28d61f5627ad7d1c670218a091de Mon Sep 17 00:00:00 2001 From: xinyu Date: Sat, 3 Jul 2021 18:16:02 +0800 Subject: [PATCH 13/33] fix warning Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 4f5dca941..8161ab0c5 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1933,6 +1933,8 @@ def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.P 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 From b4b39d9a5bdcd29d6c342d44946db16b0b6e7cb1 Mon Sep 17 00:00:00 2001 From: xinyu Date: Sat, 3 Jul 2021 22:20:13 +0800 Subject: [PATCH 14/33] [Y_cable][Credo] implement restart_anlt() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 109 ++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 8161ab0c5..55e50815e 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -20,10 +20,10 @@ 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_IDENTFIER_LOWER_PAGE = 0 + OFFSET_IDENTIFIER_LOWER_PAGE = 0 OFFSET_INTERNAL_TEMPERATURE = 22 OFFSET_INTERNAL_VOLTAGE = 26 - OFFSET_IDENTFIER_UPPER_PAGE = 128 + OFFSET_IDENTIFIER_UPPER_PAGE = 128 OFFSET_VENDOR_NAME = 148 OFFSET_PART_NUMBER = 168 OFFSET_DETERMINE_CABLE_READ_SIDE = 640 @@ -90,15 +90,20 @@ class YCable(YCableBase): # definition of MIS memorymap page MIS_PAGE_VSC = 0xFA - MIS_PAGE_FC = 0xFC + MIS_PAGE_FC = 0xFC # eventlog command option - EVENTLOG_OPTION_DUMP = 0x01 + EVENTLOG_OPTION_DUMP = 0x01 EVENTLOG_OPTION_CLEAR = 0x02 # VSC opcode - VSC_OPCODE_FWUPD = 0x80 - VSC_OPCODE_EVENTLOG = 0x81 + 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 + BER_TIMEOUT_SECS = 1 EYE_TIMEOUT_SECS = 1 @@ -168,7 +173,7 @@ def __init__(self, port, main_logger): def read_mmap(self, page, byte, len=1): """ - This API specifically converts memory map page and offset to linar address, then returns eeprom values + This API converts memory map page and offset to linar address, then returns eeprom values by calling read_eeprom() Args: @@ -206,7 +211,7 @@ def read_mmap(self, page, byte, len=1): def write_mmap(self, page, byte, value, len=1): """ - This API specifically converts memory map page and offset to linar address for calling write_eeprom() + This API converts memory map page and offset to linar address for calling write_eeprom() Args: page: @@ -246,7 +251,7 @@ def write_mmap(self, page, byte, value, len=1): def send_vsc_cmd(self, vsc_req_form, timeout=1200): """ - This routine sends the vsc payload to MCU and returns the status code + This API sends Credo vendor specific command to the MCU Args: vsc_req_form: @@ -280,6 +285,71 @@ def send_vsc_cmd(self, vsc_req_form, timeout=1200): 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_cmd(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_cmd(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 toggle_mux_to_tor_a(self): """ This API does a hard switch toggle of the Y cable's MUX regardless of link state to @@ -1803,7 +1873,7 @@ def get_autoswitch_hysteresis_timer(self): return int(time[0]) - def restart_anlt(self): + 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. @@ -1820,7 +1890,24 @@ def restart_anlt(self): , False if the restart is not successful """ - raise NotImplementedError + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to restart anlt") + return -1 + + return True def get_anlt_stats(self, target): """ From 358f1114726807a819e83374a6a71b8ffd135641 Mon Sep 17 00:00:00 2001 From: xinyu Date: Sat, 3 Jul 2021 22:46:53 +0800 Subject: [PATCH 15/33] [Y_cable][Credo] implement create_port() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 55e50815e..d284970b7 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1500,7 +1500,31 @@ def create_port(self, speed, fec_mode_tor_a=YCableBase.FEC_MODE_NONE, fec_mode_t , False if the port is not configured """ - raise NotImplementedError + if self.platform_chassis is not None: + 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_a else (0 << 1) + mode |= (1 << 3) if fec_mode_nic == YCableBase.FEC_MODE_RS else (0 << 3) + mode |= (1 << 4) if fec_mode_tor_a == 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("platform_chassis is not loaded, failed to create port") + return False + + return True def get_speed(self): """ From 1cc26f56f0da5a7fe5990055d3e3d6eb58c50e20 Mon Sep 17 00:00:00 2001 From: xinyu Date: Mon, 5 Jul 2021 21:37:07 +0800 Subject: [PATCH 16/33] [Y_cable][Credo] implement get_pcs_stats() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 95 +++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index d284970b7..232d260f4 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -350,6 +350,66 @@ def fw_cmd_ext(self, cmd, detail1, detail2): 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_cmd(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_cmd(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 toggle_mux_to_tor_a(self): """ This API does a hard switch toggle of the Y cable's MUX regardless of link state to @@ -1828,7 +1888,40 @@ def get_pcs_stats(self, target): a detailed format agreed upon by vendors """ - raise NotImplementedError + pcs_stats = {} + + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get pcs statisics") + return pcs_stats + + return pcs_stats def get_fec_stats(self, target): """ From 0bf5ab3c308826f99f169bfd6d17197dce582239 Mon Sep 17 00:00:00 2001 From: xinyu Date: Mon, 5 Jul 2021 21:46:55 +0800 Subject: [PATCH 17/33] [Y_cable][Credo] error exception for send_vsc() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 70 +++++++++++++++------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 232d260f4..21129a2b5 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -249,7 +249,7 @@ def write_mmap(self, page, byte, value, len=1): return ret - def send_vsc_cmd(self, vsc_req_form, timeout=1200): + def send_vsc(self, vsc_req_form, timeout=1200): """ This API sends Credo vendor specific command to the MCU @@ -258,30 +258,34 @@ def send_vsc_cmd(self, vsc_req_form, timeout=1200): a bytearray, command request form follow by vsc command structure timeout: - an Integer, number of 5ms delay time, default value is 1200 (6 seconds). + 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. """ - 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 + 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 + 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 + 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) + 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 @@ -306,7 +310,7 @@ def fw_cmd(self, cmd, detail1): 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_cmd(vsc_req_form) + 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)) @@ -340,7 +344,7 @@ def fw_cmd_ext(self, cmd, detail1, detail2): 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_cmd(vsc_req_form) + 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)) @@ -367,7 +371,7 @@ def tcm_read(self, addr): 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_cmd(vsc_req_form) + 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 @@ -403,7 +407,7 @@ def tcm_write(self, addr, data): vsc_req_form[136] = (data >> 16) & 0xFF vsc_req_form[137] = (data >> 24) & 0xFF - status = self.send_vsc_cmd(vsc_req_form) + 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 @@ -1017,7 +1021,7 @@ def get_firmware_version(self, target): 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 - self.send_vsc_cmd(vsc_req_form) + self.send_vsc(vsc_req_form) data = bytearray(YCable.FIRMWARE_INFO_PAYLOAD_SIZE) @@ -1104,7 +1108,7 @@ def download_firmware(self, fwfile): 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_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE @@ -1137,7 +1141,7 @@ def download_firmware(self, fwfile): 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_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if status == YCable.MCU_EC_NO_ERROR: chunk_idx += 1 @@ -1156,7 +1160,7 @@ def download_firmware(self, fwfile): 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_cmd(vsc_req_form) + 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)) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE @@ -1167,7 +1171,7 @@ def download_firmware(self, fwfile): 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_cmd(vsc_req_form) + 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)) return YCableBase.FIRMWARE_DOWNLOAD_FAILURE @@ -1175,7 +1179,7 @@ def download_firmware(self, fwfile): 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_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: self.log_error( 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) @@ -1190,7 +1194,7 @@ def download_firmware(self, fwfile): 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_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: self.log_error( 'Get firmware binary UART transfer status error (error code:0x%04X)' % (status)) @@ -1247,7 +1251,7 @@ def activate_firmware(self, fwfile=None, hitless=False): 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 - status = self.send_vsc_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) return YCableBase.FIRMWARE_ACTIVATE_FAILURE @@ -1257,7 +1261,7 @@ def activate_firmware(self, fwfile=None, hitless=False): vsc_req_form[YCable.VSC_BYTE_OPCODE] = YCable.VSC_OPCODE_FWUPD vsc_req_form[YCable.VSC_BYTE_ADDR0] = side vsc_req_form[YCable.VSC_BYTE_ADDR1] = hitless - status = self.send_vsc_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) time.sleep(5) if status != YCable.MCU_EC_NO_ERROR: self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) @@ -1494,7 +1498,7 @@ def reset(self, target): 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_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if target == YCableBase.TARGET_NIC: time.sleep(4) @@ -1804,7 +1808,7 @@ def get_event_log(self, clear_on_read=False): 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 - self.send_vsc_cmd(vsc_req_form) + self.send_vsc(vsc_req_form) last_read_id = -1 result = [] @@ -1832,7 +1836,7 @@ def get_event_log(self, clear_on_read=False): 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_cmd(vsc_req_form) + status = self.send_vsc(vsc_req_form) if status == YCable.MCU_EC_NO_ERROR: fetch_cnt = self.read_mmap(YCable.MIS_PAGE_VSC, 134) From c05e581d0c4fb50d0760084ef039670972b8d687 Mon Sep 17 00:00:00 2001 From: xinyu Date: Tue, 6 Jul 2021 00:03:02 +0800 Subject: [PATCH 18/33] [Y_cable][Credo] implement get_alive_status() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 21129a2b5..4d25bc009 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -41,6 +41,7 @@ class YCable(YCableBase): 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_CONFIGURE_PRBS_TYPE = 768 OFFSET_ENABLE_PRBS = 769 @@ -1466,7 +1467,20 @@ def get_alive_status(self): , False if the cable is not alive """ - raise NotImplementedError + if self.platform_chassis is not None: + curr_offset = YCable.OFFSET_NIC_SIGNAL_DETECTION + result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 6) + if result is False: + return result + + for idx in range(6): + if result[idx] == 0: + return False + else: + self.log_error("platform_chassis is not loaded, failed to get anlt") + return False + + return True def reset(self, target): """ From e2834d10d2bbe8de334f46d7761579cc7caf9c65 Mon Sep 17 00:00:00 2001 From: xinyu Date: Tue, 6 Jul 2021 20:49:20 +0800 Subject: [PATCH 19/33] [Y_cable][Credo] update error exception when platform_chassis is not loaded --- sonic_y_cable/credo/y_cable_credo.py | 234 +++++++++++++++------------ 1 file changed, 132 insertions(+), 102 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 4d25bc009..13f80f2f0 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1246,26 +1246,30 @@ def activate_firmware(self, fwfile=None, hitless=False): FIRMWARE_ACTIVATE_SUCCESS FIRMWARE_ACTIVATE_FAILURE """ - side = 0x7 + if self.platform_chassis is not None: + side = 0x7 - 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 - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) - return YCableBase.FIRMWARE_ACTIVATE_FAILURE + 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 + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + 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 - 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(YCable.MCU_ERROR_CODE_STRING[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] = side + 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(YCable.MCU_ERROR_CODE_STRING[status]) + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + else: + self.log_error("platform_chassis is not loaded, failed to activate firmware") return YCableBase.FIRMWARE_ACTIVATE_FAILURE return YCableBase.FIRMWARE_ACTIVATE_SUCCESS @@ -1298,7 +1302,15 @@ def rollback_firmware(self, fwfile=None): FIRMWARE_ROLLBACK_SUCCESS FIRMWARE_ROLLBACK_FAILURE """ - self.activate_firmware() + + if self.platform_chassis is not None: + if self.activate_firmware() == YCableBase.FIRMWARE_ACTIVATE_SUCCESS: + return YCableBase.FIRMWARE_ROLLBACK_SUCCESS + else: + return YCableBase.FIRMWARE_ROLLBACK_FAILURE + else: + self.log_error("platform_chassis is not loaded, failed to activate firmware") + return YCableBase.FIRMWARE_ROLLBACK_FAILURE return YCableBase.FIRMWARE_ROLLBACK_SUCCESS @@ -1503,24 +1515,28 @@ def reset(self, target): ''' use firmare_run cmd to emulate module reset ''' - 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 + 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 - 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) + 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 target == YCableBase.TARGET_NIC: - time.sleep(4) - else: - time.sleep(2) + if target == YCableBase.TARGET_NIC: + time.sleep(4) + else: + time.sleep(2) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error("unable to reset the module") + if status != YCable.MCU_EC_NO_ERROR: + self.log_error("unable to reset the module") + return False + else: + self.log_error("platform_chassis is not loaded, failed to reset") return False return True @@ -1818,75 +1834,81 @@ def get_event_log(self, clear_on_read=False): a list of strings which correspond to the event logs of the cable """ - if (clear_on_read): - 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 - self.send_vsc(vsc_req_form) - - last_read_id = -1 result = [] - 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', - } - - while (True): - 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 None - - 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('> 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 None + + 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(' TOR A EYE_PRBS_LOOPBACK_TARGET_TOR_B -> TOR B EYE_PRBS_LOOPBACK_TARGET_NIC -> NIC - mode_value: + mode: One of the following predefined constants, the mode to be run for loopback: LOOPBACK_MODE_NEAR_END LOOPBACK_MODE_FAR_END @@ -2381,7 +2403,7 @@ def get_ber_info(self, target): return ber_result - def debug_dump_registers(self): + 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. @@ -2390,6 +2412,14 @@ def debug_dump_registers(self): 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: From e9c582faeca65fd03b8722166aee3e03f720fa32 Mon Sep 17 00:00:00 2001 From: xinyu Date: Tue, 6 Jul 2021 22:55:44 +0800 Subject: [PATCH 20/33] fix warning Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 13f80f2f0..65c8ac26a 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1304,9 +1304,7 @@ def rollback_firmware(self, fwfile=None): """ if self.platform_chassis is not None: - if self.activate_firmware() == YCableBase.FIRMWARE_ACTIVATE_SUCCESS: - return YCableBase.FIRMWARE_ROLLBACK_SUCCESS - else: + if self.activate_firmware() == YCableBase.FIRMWARE_ACTIVATE_FAILURE: return YCableBase.FIRMWARE_ROLLBACK_FAILURE else: self.log_error("platform_chassis is not loaded, failed to activate firmware") From 2b8b399c07881a35a022cc9493cf7b454d3da3f1 Mon Sep 17 00:00:00 2001 From: xinyu Date: Tue, 6 Jul 2021 23:07:04 +0800 Subject: [PATCH 21/33] [Y_cable][Credo] add get_serial_number() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 65c8ac26a..a6fd5255a 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -26,6 +26,7 @@ class YCable(YCableBase): 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 @@ -788,6 +789,28 @@ def get_part_number(self): 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: + part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) + else: + self.log_error("platform_chassis is not loaded, failed to get part number") + return -1 + + 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 From e33a856bfdeeca6144b64550d402a3ff6ae54fed Mon Sep 17 00:00:00 2001 From: xinyu Date: Thu, 8 Jul 2021 18:20:29 +0800 Subject: [PATCH 22/33] [Y_cable][Credo] implement get_anlt_stats() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 81 +++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index a6fd5255a..129e4716e 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -105,6 +105,8 @@ class YCable(YCableBase): 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 @@ -416,6 +418,59 @@ def tcm_write(self, addr, data): 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 toggle_mux_to_tor_a(self): """ This API does a hard switch toggle of the Y cable's MUX regardless of link state to @@ -2104,7 +2159,31 @@ def get_anlt_stats(self, target): a detailed format agreed upon by vendors """ - raise NotImplementedError + anlt_stat = {} + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get anlt stats") + + return anlt_stat ############################################################################################# ### Debug Functionality ### From 635dc4fe7a0600e8b56d0fc75f91ab8f5b6f9155 Mon Sep 17 00:00:00 2001 From: xinyu Date: Mon, 12 Jul 2021 21:03:33 +0800 Subject: [PATCH 23/33] [Y_cable][Credo] update clean_on_read functions Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 86 +++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 129e4716e..40bc76575 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -44,6 +44,9 @@ class YCable(YCableBase): 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_CONFIGURE_PRBS_TYPE = 768 OFFSET_ENABLE_PRBS = 769 OFFSET_INITIATE_BER_MEASUREMENT = 770 @@ -110,6 +113,7 @@ class YCable(YCableBase): BER_TIMEOUT_SECS = 1 EYE_TIMEOUT_SECS = 1 + EXTEND_SWITCH_CNT_TIMEOUT_SECS = 1 # error code of EEPROM EEPROM_READ_DATA_INVALID = -1 @@ -904,6 +908,16 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): self.log_error("not a valid switch_count_type, failed to get switch count") return -1 + if clear_on_read: + if switch_count_type == YCableBase.SWITCH_COUNT_AUTO: + curr_offset = YCable.OFFSET_AUTO_SWITCH_COUNT + buffer = bytearray([6]) + 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 result + return count def get_switch_count_tor_a(self, clear_on_read=False): @@ -936,6 +950,14 @@ def get_switch_count_tor_a(self, clear_on_read=False): self.log_error("platform_chassis is not loaded, failed to get manual switch count") return -1 + 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 result + return count def get_switch_count_tor_b(self, clear_on_read=False): @@ -968,6 +990,14 @@ def get_switch_count_tor_b(self, clear_on_read=False): self.log_error("platform_chassis is not loaded, failed to get manual switch count") return -1 + 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 result + return count def get_switch_count_target(self, switch_count_type, target, clear_on_read=False): @@ -994,7 +1024,61 @@ def get_switch_count_target(self, switch_count_type, target, clear_on_read=False an integer, the number of times manually the Y-cable has been switched """ - raise NotImplementedError + 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 -1 + 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 -1 + else: + self.log_error("not a valid switch_count_type, failed to get switch count") + return -1 + + if self.platform_chassis is not None: + 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] & 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 result + else: + self.log_error("platform_chassis is not loaded, failed to get switch count target") + return -1 + + return count def get_target_cursor_values(self, lane, target): """ From 007d540aac79ecce3c0b7359c6392b43bc5a5215 Mon Sep 17 00:00:00 2001 From: xinyu Date: Mon, 12 Jul 2021 21:42:03 +0800 Subject: [PATCH 24/33] fix warning of variable defined multiple times Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 40bc76575..87eaf6dd5 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -912,7 +912,6 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): if switch_count_type == YCableBase.SWITCH_COUNT_AUTO: curr_offset = YCable.OFFSET_AUTO_SWITCH_COUNT buffer = bytearray([6]) - 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: From 98d1c676bc3e34d24da92d61b8a5f6f6c6a5d570 Mon Sep 17 00:00:00 2001 From: xinyu Date: Mon, 19 Jul 2021 23:05:09 +0800 Subject: [PATCH 25/33] [Y_cable][Credo] update debug_dump_registers() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 180 +++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 9 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 87eaf6dd5..f7265e01e 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -102,14 +102,17 @@ class YCable(YCableBase): EVENTLOG_OPTION_CLEAR = 0x02 # VSC opcode - 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 + VSC_OPCODE_UART_STAT = 0x1C + VSC_OPCODE_SERDES_INFO = 0x1D + VSC_OPCODE_DSP_LOADFW_STAT = 0x1F + 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 @@ -2609,5 +2612,164 @@ def debug_dump_registers(self, option=None): 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: + result = {} + 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_Dect() + + 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['eye'] = struct.unpack_from(' Date: Mon, 19 Jul 2021 23:18:10 +0800 Subject: [PATCH 26/33] [Y_cable][Credo] update debug_dump_registers() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index f7265e01e..dd09a8a1d 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -2626,15 +2626,25 @@ def debug_dump_registers(self, option=None): for ln in list(lanes): data = self.get_serdes_params(ln) serdes = {} - serdes['eye'] = struct.unpack_from(' Date: Tue, 20 Jul 2021 12:52:09 +0800 Subject: [PATCH 27/33] [Y_cable][Credo] update download_firmware_status in download_firmware() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 45 ++++++++++++++++------------ 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index dd09a8a1d..61710209b 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1232,6 +1232,13 @@ def get_firmware_version(self, target): result["empty_slot1"] = True if slot_status & 0x04 else False result["empty_slot2"] = True if slot_status & 0x40 else False + version_build_slot1 = version_slot1 + build_slot1 + version_build_slot2 = version_slot2 + build_slot2 + + result["version_active"] = version_build_slot1 if slot_status & 0x01 else version_build_slot2 + result["version_inactive"] = version_build_slot2 if slot_status & 0x01 else version_build_slot1 + result["version_next"] = version_build_slot1 if slot_status & 0x02 else version_build_slot2 + return result def download_firmware(self, fwfile): @@ -1267,6 +1274,8 @@ def download_firmware(self, fwfile): fwImage = bytearray(inFile.read()) inFile.close() + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS + ''' Firmware update start ''' @@ -1276,6 +1285,7 @@ def download_firmware(self, fwfile): status = self.send_vsc(vsc_req_form) if status != YCable.MCU_EC_NO_ERROR: self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED return YCableBase.FIRMWARE_DOWNLOAD_FAILURE ''' @@ -1316,6 +1326,7 @@ def download_firmware(self, fwfile): 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 @@ -1328,6 +1339,7 @@ def download_firmware(self, fwfile): 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 ''' @@ -1339,6 +1351,7 @@ def download_firmware(self, fwfile): 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 vsc_req_form = [None] * (YCable.VSC_CMD_ATTRIBUTE_LENGTH) @@ -1348,6 +1361,7 @@ def download_firmware(self, fwfile): if status != YCable.MCU_EC_NO_ERROR: 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 busy = self.read_mmap(YCable.MIS_PAGE_FC, 128) @@ -1363,6 +1377,8 @@ def download_firmware(self, fwfile): if status != YCable.MCU_EC_NO_ERROR: 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(0.2) @@ -1371,6 +1387,8 @@ def download_firmware(self, fwfile): self.read_mmap(YCable.MIS_PAGE_FC, 130) self.read_mmap(YCable.MIS_PAGE_FC, 131) + 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): @@ -1703,8 +1721,7 @@ def reset(self, target): return True - def create_port(self, speed, fec_mode_tor_a=YCableBase.FEC_MODE_NONE, fec_mode_tor_b=YCableBase.FEC_MODE_NONE, - fec_mode_nic=YCableBase.FEC_MODE_NONE, anlt_tor_a=False, anlt_tor_b=False, anlt_nic=False): + 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 @@ -1720,14 +1737,8 @@ def create_port(self, speed, fec_mode_tor_a=YCableBase.FEC_MODE_NONE, fec_mode_t 50000 -> 50G 100000 -> 100G - fec_mode_tor_a: - 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_tor_b: - One of the following predefined constants, the actual FEC mode for the ToR B to be configured: + 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 @@ -1738,13 +1749,9 @@ def create_port(self, speed, fec_mode_tor_a=YCableBase.FEC_MODE_NONE, fec_mode_t FEC_MODE_RS, FEC_MODE_FC - anlt_tor_a: - 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_tor_b: - a boolean, True if auto-negotiation + link training (AN/LT) is to be enabled on ToR B - , False if auto-negotiation + link training (AN/LT) is not to be enabled on ToR B + 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 @@ -1767,9 +1774,9 @@ def create_port(self, speed, fec_mode_tor_a=YCableBase.FEC_MODE_NONE, fec_mode_t return False mode |= (1 << 0) if anlt_nic else (0 << 0) - mode |= (1 << 1) if anlt_tor_a else (0 << 1) + 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_a == YCableBase.FEC_MODE_RS else (0 << 4) + mode |= (1 << 4) if fec_mode_tor == YCableBase.FEC_MODE_RS else (0 << 4) curr_offset = YCable.OFFSET_NIC_MODE_CONFIGURATION buffer = bytearray([mode]) From de29f2272c941e4e184bb62cb3280ae4c587e6b1 Mon Sep 17 00:00:00 2001 From: xinyu Date: Tue, 20 Jul 2021 15:59:26 +0800 Subject: [PATCH 28/33] [Y_cable][Credo] handle fwfwile in activated/rollback firmware functions Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 63 +++++++++++++++++++--------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 61710209b..383867d0f 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -1429,27 +1429,50 @@ def activate_firmware(self, fwfile=None, hitless=False): FIRMWARE_ACTIVATE_FAILURE """ if self.platform_chassis is not None: - side = 0x7 + if fwfile is None: + side = 0x7 - 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 - status = self.send_vsc(vsc_req_form) - if status != YCable.MCU_EC_NO_ERROR: - self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) - return YCableBase.FIRMWARE_ACTIVATE_FAILURE + 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 + status = self.send_vsc(vsc_req_form) + if status != YCable.MCU_EC_NO_ERROR: + self.log_error(YCable.MCU_ERROR_CODE_STRING[status]) + 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 - 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(YCable.MCU_ERROR_CODE_STRING[status]) - 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 + 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(YCable.MCU_ERROR_CODE_STRING[status]) + return YCableBase.FIRMWARE_ACTIVATE_FAILURE + else: + inFile = open(fwfile, 'rb') + fwImage = bytearray(inFile.read()) + inFile.close() + + build_msb = struct.unpack_from(' Date: Thu, 22 Jul 2021 12:47:40 +0800 Subject: [PATCH 29/33] [Y_cable][Credo] implement get_fec_stats() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 57 +++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 383867d0f..fb34affb4 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -2171,8 +2171,63 @@ def get_fec_stats(self, target): a dictionary: a detailed format agreed upon by vendors """ + fec_stats = {} - raise NotImplementedError + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get fec statisics") + return fec_stats + + return fec_stats def set_autoswitch_hysteresis_timer(self, time): """ From 0c60fa9bd917b77015be90ee0b12a2634595905f Mon Sep 17 00:00:00 2001 From: vaibhav-dahiya Date: Tue, 27 Jul 2021 19:28:06 +0000 Subject: [PATCH 30/33] put in lower cases for vendor Signed-off-by: vaibhav-dahiya --- sonic_y_cable/y_cable_vendor_mapping.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sonic_y_cable/y_cable_vendor_mapping.py b/sonic_y_cable/y_cable_vendor_mapping.py index 98aa68ac9..58ecd4834 100644 --- a/sonic_y_cable/y_cable_vendor_mapping.py +++ b/sonic_y_cable/y_cable_vendor_mapping.py @@ -1,13 +1,13 @@ mapping = { - "Credo": { - "CACL05321P2PA1MS": "credo.y_cable_credo", - "CACL1X321P2PA1MS": "credo.y_cable_credo", - "CACL15321P2PA1MS": "credo.y_cable_credo", - "CACL2X321P2PA1MS": "credo.y_cable_credo", + "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" + "cac105321p2pa2ms": "credo.y_cable_credo", + "cac11x321p2pa2ms": "credo.y_cable_credo", + "cac115321p2pa2ms": "credo.y_cable_credo", + "cac12x321p2pa2ms": "credo.y_cable_credo" } } From 1e3abc6bea7c3d1144431abcb367d87d689fa6be Mon Sep 17 00:00:00 2001 From: vaibhav-dahiya Date: Thu, 29 Jul 2021 02:03:28 +0000 Subject: [PATCH 31/33] dummy commit Signed-off-by: vaibhav-dahiya --- sonic_y_cable/credo/y_cable_credo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index fb34affb4..4e36613f7 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -122,6 +122,7 @@ class YCable(YCableBase): EEPROM_READ_DATA_INVALID = -1 EEPROM_ERROR = -1 EEPROM_TIMEOUT_ERROR = -1 + EEPROM_GENERIC_ERROR = -1 # MCU error code MCU_EC_NO_ERROR = 0 From f33c4d1e5d3a8a6dcd6f63d4a1dd672f782157f4 Mon Sep 17 00:00:00 2001 From: xinyu Date: Thu, 29 Jul 2021 10:15:05 +0800 Subject: [PATCH 32/33] [Y_cable][Credo] implement get_loopback_mode() Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 42 ++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 4e36613f7..7c7200d35 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -53,8 +53,10 @@ class YCable(YCableBase): OFFSET_LANE_1_BER_RESULT = 771 OFFSET_INITIATE_EYE_MEASUREMENT = 784 OFFSET_LANE_1_EYE_RESULT = 785 - OFFSET_TARGET = 794 OFFSET_ENABLE_LOOPBACK = 793 + OFFSET_TARGET = 794 + OFFSET_SYNC_DEBUG_MODE = 795 + # definition of VSC command byte VSC_BYTE_OPCODE = 128 @@ -116,6 +118,7 @@ class YCable(YCableBase): BER_TIMEOUT_SECS = 1 EYE_TIMEOUT_SECS = 1 + GET_DEBUG_MODE_TIMEOUT_SECS = 1 EXTEND_SWITCH_CNT_TIMEOUT_SECS = 1 # error code of EEPROM @@ -784,7 +787,6 @@ def get_eye_heights(self, target): 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: @@ -2612,11 +2614,44 @@ def get_loopback_mode(self, target): 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 + if self.platform_chassis is not None: + 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("platform_chassis is not loaded, failed to get loopback mode") + return -1 + + return YCableBase.LOOPBACK_MODE_NONE def get_ber_info(self, target): """ @@ -2709,6 +2744,7 @@ def debug_dump_registers(self, option=None): result['serdes_detect'] = self.get_dsp_link_Dect() 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 = {} From 4789d35ed7bb78d29d10e04c4486b35ba874988a Mon Sep 17 00:00:00 2001 From: xinyu Date: Wed, 4 Aug 2021 11:36:34 +0800 Subject: [PATCH 33/33] [Y_cable][Credo] return YCable.EEPROM_ERROR when platform chassis is not loaded Signed-off-by: xinyu --- sonic_y_cable/credo/y_cable_credo.py | 293 ++++++++++++++------------- 1 file changed, 150 insertions(+), 143 deletions(-) diff --git a/sonic_y_cable/credo/y_cable_credo.py b/sonic_y_cable/credo/y_cable_credo.py index 7c7200d35..3a888f727 100644 --- a/sonic_y_cable/credo/y_cable_credo.py +++ b/sonic_y_cable/credo/y_cable_credo.py @@ -505,7 +505,7 @@ def toggle_mux_to_tor_a(self): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR A") - return False + return YCable.EEPROM_ERROR return result @@ -530,7 +530,7 @@ def toggle_mux_to_tor_b(self): result = self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error("platform_chassis is not loaded, failed to toggle mux to TOR B") - return False + return YCable.EEPROM_ERROR return result @@ -556,7 +556,7 @@ def get_read_side(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error("platform_chassis is not loaded, failed to check read side") - return YCableBase.TARGET_UNKNOWN + return YCable.EEPROM_ERROR if result is not None: if isinstance(result, bytearray): @@ -612,7 +612,7 @@ def get_mux_direction(self): else: self.log_error( "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") - return YCableBase.TARGET_UNKNOWN + return YCable.EEPROM_ERROR if result is not None: if isinstance(result, bytearray): @@ -665,7 +665,7 @@ def get_active_linked_tor_side(self): else: self.log_error( "platform_chassis is not loaded, failed to check Active Linked and routing TOR side") - return YCableBase.TARGET_UNKNOWN + return YCable.EEPROM_ERROR if result is not None: if isinstance(result, bytearray): @@ -721,7 +721,7 @@ def is_link_active(self, target): else: self.log_error( "platform_chassis is not loaded, failed to check if link is Active on target side") - return YCableBase.TARGET_UNKNOWN + return YCable.EEPROM_ERROR if result is not None: if isinstance(result, bytearray): @@ -736,7 +736,7 @@ def is_link_active(self, target): 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 YCableBase.TARGET_UNKNOWN + return YCable.EEPROM_ERROR regval_read = struct.unpack(">B", result) @@ -826,7 +826,7 @@ def get_vendor(self): result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: self.log_error("platform_chassis is not loaded, failed to get Vendor name") - return -1 + return YCable.EEPROM_ERROR vendor_name = str(result.decode()) @@ -848,7 +848,7 @@ def get_part_number(self): part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: self.log_error("platform_chassis is not loaded, failed to get part number") - return -1 + return YCable.EEPROM_ERROR part_number = str(part_result.decode()) @@ -870,7 +870,7 @@ def get_serial_number(self): part_result = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 16) else: self.log_error("platform_chassis is not loaded, failed to get part number") - return -1 + return YCable.EEPROM_ERROR part_number = str(part_result.decode()) @@ -909,10 +909,10 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) else: self.log_error("platform_chassis is not loaded, failed to get manual switch count") - return -1 + return YCable.EEPROM_ERROR else: self.log_error("not a valid switch_count_type, failed to get switch count") - return -1 + return YCable.EEPROM_ERROR if clear_on_read: if switch_count_type == YCableBase.SWITCH_COUNT_AUTO: @@ -921,7 +921,7 @@ def get_switch_count_total(self, switch_count_type, clear_on_read=False): result = self.platform_chassis.get_sfp( self.port).write_eeprom(curr_offset, 1, buffer) if result is False: - return result + return YCable.EEPROM_ERROR return count @@ -953,7 +953,7 @@ def get_switch_count_tor_a(self, clear_on_read=False): count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) else: self.log_error("platform_chassis is not loaded, failed to get manual switch count") - return -1 + return YCable.EEPROM_ERROR if clear_on_read: buffer = bytearray([4]) @@ -961,7 +961,7 @@ def get_switch_count_tor_a(self, clear_on_read=False): result = self.platform_chassis.get_sfp( self.port).write_eeprom(curr_offset, 1, buffer) if result is False: - return result + return YCable.EEPROM_ERROR return count @@ -993,7 +993,7 @@ def get_switch_count_tor_b(self, clear_on_read=False): count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) else: self.log_error("platform_chassis is not loaded, failed to get manual switch count") - return -1 + return YCable.EEPROM_ERROR if clear_on_read: buffer = bytearray([5]) @@ -1001,7 +1001,7 @@ def get_switch_count_tor_b(self, clear_on_read=False): result = self.platform_chassis.get_sfp( self.port).write_eeprom(curr_offset, 1, buffer) if result is False: - return result + return YCable.EEPROM_ERROR return count @@ -1038,7 +1038,7 @@ def get_switch_count_target(self, switch_count_type, target, clear_on_read=False buffer = bytearray([1]) else: self.log_error("not a valid target") - return -1 + return YCable.EEPROM_ERROR elif switch_count_type == YCableBase.SWITCH_COUNT_AUTO: if target == YCableBase.TARGET_TOR_A: buffer = bytearray([2]) @@ -1046,16 +1046,16 @@ def get_switch_count_target(self, switch_count_type, target, clear_on_read=False buffer = bytearray([3]) else: self.log_error("not a valid target") - return -1 + return YCable.EEPROM_ERROR else: self.log_error("not a valid switch_count_type, failed to get switch count") - return -1 + return YCable.EEPROM_ERROR if self.platform_chassis is not None: result = self.platform_chassis.get_sfp( self.port).write_eeprom(curr_offset, 1, buffer) if result is False: - return result + return YCable.EEPROM_ERROR time_start = time.time() while(True): done = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) @@ -1078,10 +1078,10 @@ def get_switch_count_target(self, switch_count_type, target, clear_on_read=False result = self.platform_chassis.get_sfp( self.port).write_eeprom(curr_offset, 1, buffer) if result is False: - return result + return YCable.EEPROM_ERROR else: self.log_error("platform_chassis is not loaded, failed to get switch count target") - return -1 + return YCable.EEPROM_ERROR return count @@ -1124,7 +1124,7 @@ def get_target_cursor_values(self, lane, target): result.append(c_int8(post2[0]).value) else: self.log_error("platform_chassis is not loaded, failed to get target cursor values") - return -1 + return YCable.EEPROM_ERROR return result @@ -1163,7 +1163,7 @@ def set_target_cursor_values(self, lane, cursor_values, target): idx += 1 else: self.log_error("platform_chassis is not loaded, failed to get target cursor values") - return -1 + return YCable.EEPROM_ERROR return True @@ -1200,7 +1200,7 @@ def get_firmware_version(self, target): data[byte_idx] = read_out[0] else: self.log_error("platform_chassis is not loaded, failed to get NIC lanes active") - return -1 + return YCable.EEPROM_ERROR result = {} NUM_MCU_SIDE = 3 @@ -1273,106 +1273,92 @@ def download_firmware(self, fwfile): or an error code as to what was the cause of firmware download failure """ - inFile = open(fwfile, 'rb') - fwImage = bytearray(inFile.read()) - inFile.close() + if self.platform_chassis is not None: - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS + inFile = open(fwfile, 'rb') + fwImage = bytearray(inFile.read()) + inFile.close() - ''' - Firmware update start - ''' - 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(YCable.MCU_ERROR_CODE_STRING[status]) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED - return YCableBase.FIRMWARE_DOWNLOAD_FAILURE + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_INPROGRESS - ''' - Transfer firmwre image to local side MCU - ''' - total_chunk = len(fwImage) // YCable.VSC_BUFF_SIZE - chunk_idx = 0 - retry_count = 0 - while chunk_idx < total_chunk: - 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 + ''' + Firmware update start + ''' 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 + 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(YCable.MCU_ERROR_CODE_STRING[status]) + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_FAILED + return YCableBase.FIRMWARE_DOWNLOAD_FAILURE - 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 + ''' + Transfer firmwre image to local side MCU + ''' + total_chunk = len(fwImage) // YCable.VSC_BUFF_SIZE + chunk_idx = 0 + retry_count = 0 + while chunk_idx < total_chunk: + 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) - ''' - Complete the local side firmware transferring - ''' - 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 + 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)) - ''' - transfer firmware image from local side MCU to the other two via UART - ''' - 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 + 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 - 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) - if status != YCable.MCU_EC_NO_ERROR: - 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 + ''' + Complete the local side firmware transferring + ''' + 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 - 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) + ''' + transfer firmware image from local side MCU to the other two via UART + ''' + 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 - while busy != 0: 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 @@ -1380,17 +1366,36 @@ def download_firmware(self, fwfile): if status != YCable.MCU_EC_NO_ERROR: 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(0.2) 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) - self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED + while busy != 0: + 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) + if status != YCable.MCU_EC_NO_ERROR: + 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(0.2) + 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) + + self.download_firmware_status = self.FIRMWARE_DOWNLOAD_STATUS_NOT_INITIATED_OR_FINISHED + else: + self.log_error("platform_chassis is not loaded, failed to download firmware") + return YCable.EEPROM_ERROR return YCableBase.FIRMWARE_DOWNLOAD_SUCCESS @@ -1478,7 +1483,7 @@ def activate_firmware(self, fwfile=None, hitless=False): return self.activate_firmware(fwfile, hitless) else: self.log_error("platform_chassis is not loaded, failed to activate firmware") - return YCableBase.FIRMWARE_ACTIVATE_FAILURE + return YCable.EEPROM_ERROR return YCableBase.FIRMWARE_ACTIVATE_SUCCESS @@ -1516,7 +1521,7 @@ def rollback_firmware(self, fwfile=None): return YCableBase.FIRMWARE_ROLLBACK_FAILURE else: self.log_error("platform_chassis is not loaded, failed to activate firmware") - return YCableBase.FIRMWARE_ROLLBACK_FAILURE + return YCable.EEPROM_ERROR return YCableBase.FIRMWARE_ROLLBACK_SUCCESS @@ -1557,7 +1562,7 @@ def set_switching_mode(self, mode): self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error("platform_chassis is not loaded, failed to do a switch target") - return False + return YCable.EEPROM_ERROR return result @@ -1580,7 +1585,7 @@ def get_switching_mode(self): self.port).read_eeprom(curr_offset, 1) else: self.log_error("platform_chassis is not loaded, failed to get the switch mode") - return -1 + return YCable.EEPROM_ERROR if result[0] == 1: return YCableBase.SWITCHING_MODE_AUTO @@ -1625,7 +1630,7 @@ def get_local_temperature(self): temp = result[0] else: self.log_error("platform_chassis is not loaded, failed to get local temp") - return -1 + return YCable.EEPROM_ERROR return temp @@ -1669,7 +1674,7 @@ def get_local_voltage(self): voltage = (((msb_result[0] << 8) | lsb_result[0]) * 0.0001) else: self.log_error("platform_chassis is not loaded, failed to get local voltage") - return -1 + return YCable.EEPROM_ERROR return voltage @@ -1696,7 +1701,7 @@ def get_alive_status(self): return False else: self.log_error("platform_chassis is not loaded, failed to get anlt") - return False + return YCable.EEPROM_ERROR return True @@ -1743,7 +1748,7 @@ def reset(self, target): return False else: self.log_error("platform_chassis is not loaded, failed to reset") - return False + return YCable.EEPROM_ERROR return True @@ -1811,7 +1816,7 @@ def create_port(self, speed, fec_mode_tor = YCableBase.FEC_MODE_NONE, fec_mode_n return result else: self.log_error("platform_chassis is not loaded, failed to create port") - return False + return YCable.EEPROM_ERROR return True @@ -1844,7 +1849,7 @@ def get_speed(self): return -1 else: self.log_error("platform_chassis is not loaded, failed to get speed") - return -1 + return YCable.EEPROM_ERROR return speed @@ -1890,7 +1895,7 @@ def set_fec_mode(self, fec_mode, target): return result else: self.log_error("platform_chassis is not loaded, failed to set fec mode") - return False + return YCable.EEPROM_ERROR return True @@ -1929,7 +1934,7 @@ def get_fec_mode(self, target): self.log_error("get fec mode: unsupported target") else: self.log_error("platform_chassis is not loaded, failed to get fec mode") - return -1 + return YCable.EEPROM_ERROR return fec_mode @@ -1973,7 +1978,7 @@ def set_anlt(self, enable, target): return result else: self.log_error("platform_chassis is not loaded, failed to set anlt") - return False + return YCable.EEPROM_ERROR return True @@ -2010,7 +2015,7 @@ def get_anlt(self, target): self.log_error("get anlt: unsupported target") else: self.log_error("platform_chassis is not loaded, failed to get anlt") - return -1 + return YCable.EEPROM_ERROR return anlt_mode @@ -2102,7 +2107,7 @@ def get_event_log(self, clear_on_read=False): last_read_id = event_id else: self.log_error("platform_chassis is not loaded, failed to get pcs statisics") - return result + return YCable.EEPROM_ERROR return result @@ -2154,7 +2159,7 @@ def get_pcs_stats(self, target): else: self.log_error("platform_chassis is not loaded, failed to get pcs statisics") - return pcs_stats + return YCable.EEPROM_ERROR return pcs_stats @@ -2228,7 +2233,7 @@ def get_fec_stats(self, target): fec_stats['Corrected CW (15 sym err)'] = self.tcm_read(base + (26 << 2)) else: self.log_error("platform_chassis is not loaded, failed to get fec statisics") - return fec_stats + return YCable.EEPROM_ERROR return fec_stats @@ -2254,7 +2259,7 @@ def set_autoswitch_hysteresis_timer(self, time): self.platform_chassis.get_sfp(self.port).write_eeprom(curr_offset, 1, buffer) else: self.log_error("platform_chassis is not loaded, failed to set autoswitch hysteresis timer") - return -1 + return YCable.EEPROM_ERROR return True @@ -2276,7 +2281,7 @@ def get_autoswitch_hysteresis_timer(self): time = self.platform_chassis.get_sfp(self.port).read_eeprom(curr_offset, 1) else: self.log_error("platform_chassis is not loaded, failed to get autoswitch hysteresis timer") - return -1 + return YCable.EEPROM_ERROR return int(time[0]) @@ -2312,7 +2317,7 @@ def restart_anlt(self, target): self.fw_cmd_ext(0x7040, 0, lane) else: self.log_error("platform_chassis is not loaded, failed to restart anlt") - return -1 + return YCable.EEPROM_ERROR return True @@ -2356,6 +2361,7 @@ def get_anlt_stats(self, target): 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("platform_chassis is not loaded, failed to get anlt stats") + return YCable.EEPROM_ERROR return anlt_stat @@ -2466,7 +2472,7 @@ def enable_prbs_mode(self, target, mode_value, lane_mask, direction=YCableBase.P else: self.log_error("platform_chassis is not loaded, failed to enable the PRBS mode") - return -1 + return YCable.EEPROM_ERROR return result @@ -2508,7 +2514,7 @@ def disable_prbs_mode(self, target, direction): else: self.log_error("platform_chassis is not loaded, failed to disable the PRBS mode") - return -1 + return YCable.EEPROM_ERROR return result @@ -2556,7 +2562,7 @@ def enable_loopback_mode(self, target, lane_mask, mode=YCableBase.LOOPBACK_MODE_ else: self.log_error("platform_chassis is not loaded, failed to enable the loopback mode") - return -1 + return YCable.EEPROM_ERROR return result @@ -2593,7 +2599,7 @@ def disable_loopback_mode(self, target): else: self.log_error("platform_chassis is not loaded, failed to disable the loopback mode") - return -1 + return YCable.EEPROM_ERROR return result @@ -2649,7 +2655,7 @@ def get_loopback_mode(self, target): return YCableBase.LOOPBACK_MODE_NEAR_END else: self.log_error("platform_chassis is not loaded, failed to get loopback mode") - return -1 + return YCable.EEPROM_ERROR return YCableBase.LOOPBACK_MODE_NONE @@ -2706,7 +2712,7 @@ def get_ber_info(self, target): idx += 2 else: self.log_error("platform_chassis is not loaded, failed to get ber info") - return -1 + return YCable.EEPROM_ERROR return ber_result @@ -2772,6 +2778,7 @@ def debug_dump_registers(self, option=None): else: self.log_error("platform_chassis is not loaded, failed to dump registers") + return YCable.EEPROM_ERROR return result