diff --git a/sonic_y_cable/y_cable.py b/sonic_y_cable/y_cable.py index 95b11a59925f..7d557fecd50f 100644 --- a/sonic_y_cable/y_cable.py +++ b/sonic_y_cable/y_cable.py @@ -5,12 +5,15 @@ # API's for Y cable functionality in SONiC try: + import math import struct - from sonic_py_common import logger + from ctypes import c_int8 + import sonic_platform.platform + from sonic_py_common import logger except ImportError as e: # When build python3 xcvrd, it tries to do basic check which will import this file. However, - # not all platform supports python3 API now, so it could cause an issue when importing + # not all platform supports python3 API now, so it could cause an issue when importing # sonic_platform.platform. We skip the ImportError here. This is safe because: # 1. If any python package is not available, there will be exception when use it # 2. Vendors know their platform API version, they are responsible to use correct python @@ -20,14 +23,57 @@ # 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 -Y_CABLE_IDENTFIER_LOWER_PAGE = 0 -Y_CABLE_IDENTFIER_UPPER_PAGE = 128 -Y_CABLE_DETERMINE_CABLE_READ_SIDE = 640 -Y_CABLE_CHECK_LINK_ACTIVE = 641 -Y_CABLE_SWITCH_MUX_DIRECTION = 642 -Y_CABLE_MUX_DIRECTION = 644 -Y_CABLE_ACTIVE_TOR_INDICATOR = 645 -Y_CABLE_MANUAL_SWITCH_COUNT = 669 +OFFSET_IDENTFIER_LOWER_PAGE = 0 +OFFSET_IDENTFIER_UPPER_PAGE = 128 +OFFSET_DETERMINE_CABLE_READ_SIDE = 640 +OFFSET_CHECK_LINK_ACTIVE = 641 +OFFSET_SWITCH_MUX_DIRECTION = 642 +OFFSET_MUX_DIRECTION = 644 +OFFSET_ACTIVE_TOR_INDICATOR = 645 +OFFSET_MANUAL_SWITCH_COUNT = 669 +OFFSET_CONFIGURE_PRBS_TYPE = 768 +OFFSET_ENABLE_PRBS = 769 +OFFSET_INITIATE_BER_MEASUREMENT = 770 +OFFSET_TARGET = 794 +OFFSET_ENABLE_LOOPBACK = 793 +OFFSET_LANE_1_BER_RESULT = 771 +OFFSET_MAX_LANES = 2 +OFFSET_INITIATE_EYE_MEASUREMENT = 784 +OFFSET_LANE_1_EYE_RESULT = 785 +OFFSET_PN_NUMBER = 168 +OFFSET_VENDOR_NAME = 148 +OFFSET_MANUAL_SWITCH_COUNT = 653 +OFFSET_AUTO_SWITCH_COUNT = 657 +OFFSET_NIC_CURSOR_VALUES = 661 +OFFSET_TOR1_CURSOR_VALUES = 681 +OFFSET_TOR2_CURSOR_VALUES = 701 +OFFSET_NIC_LANE_ACTIVE = 721 + +# definitions of targets for getting the cursor +# equalization parameters from the register spec +# the name of the target denotes which side cursor +# values will be retreived + +TARGET_NIC = 0 +TARGET_TOR1 = 1 +TARGET_TOR2 = 2 + +# definitions of targets for getting the EYE/BER +# and initiating PRBS/Loopback on the Y cable +# the name of the target denotes which side values +# will be retreived/initiated + +EYE_PRBS_TARGET_LOCAL = 0 +EYE_PRBS_TARGET_TOR1 = 1 +EYE_PRBS_TARGET_TOR2 = 2 +EYE_PRBS_TARGET_NIC = 3 + +# definitions of switch counter types +# to be entered by the user in get_switch_count api +# for retreiving the counter values + +SWITCH_COUNT_MANUAL = "manual" +SWITCH_COUNT_AUTO = "auto" SYSLOG_IDENTIFIER = "sonic_y_cable" @@ -44,6 +90,24 @@ helper_logger.log_warning("Failed to load chassis due to {}".format(repr(e))) +def y_cable_validate_read_data(result, size, physical_port, message): + + if result is not None: + if isinstance(result, bytearray): + if len(result) != size: + LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a size {} not equal to 1 for port {}" + helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, len(result), physical_port)) + return -1 + else: + LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned an instance value of type {} which is not a bytearray for port {}" + helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, type(result), physical_port)) + return -1 + else: + LOG_MESSAGE_TEMPLATE = "Error: for checking mux_cable {}, eeprom read returned a None value for port {} which is not expected" + helper_logger.log_error(LOG_MESSAGE_TEMPLATE.format(message, physical_port)) + return -1 + + def hook_y_cable_simulator(target): """Decorator to add hook for calling y_cable_simulator_client. @@ -94,7 +158,7 @@ def toggle_mux_to_torA(physical_port): """ buffer = bytearray([2]) - curr_offset = Y_CABLE_SWITCH_MUX_DIRECTION + curr_offset = OFFSET_SWITCH_MUX_DIRECTION if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -132,7 +196,7 @@ def toggle_mux_to_torB(physical_port): """ buffer = bytearray([3]) - curr_offset = Y_CABLE_SWITCH_MUX_DIRECTION + curr_offset = OFFSET_SWITCH_MUX_DIRECTION if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -170,7 +234,7 @@ def check_read_side(physical_port): , -1 if reading the Y cable API fails. """ - curr_offset = Y_CABLE_DETERMINE_CABLE_READ_SIDE + curr_offset = OFFSET_DETERMINE_CABLE_READ_SIDE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -235,7 +299,7 @@ def check_mux_direction(physical_port): , -1 if checking which side mux is pointing to API fails. """ - curr_offset = Y_CABLE_MUX_DIRECTION + curr_offset = OFFSET_MUX_DIRECTION if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -299,7 +363,7 @@ def check_active_linked_tor_side(physical_port): , -1 if checking which side linked for routing API fails. """ - curr_offset = Y_CABLE_ACTIVE_TOR_INDICATOR + curr_offset = OFFSET_ACTIVE_TOR_INDICATOR if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -364,7 +428,7 @@ def check_if_link_is_active_for_NIC(physical_port): a boolean, true if the link is active , false if the link is not active """ - curr_offset = Y_CABLE_CHECK_LINK_ACTIVE + curr_offset = OFFSET_CHECK_LINK_ACTIVE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -420,7 +484,7 @@ def check_if_link_is_active_for_torA(physical_port): , false if the link is not active """ - curr_offset = Y_CABLE_CHECK_LINK_ACTIVE + curr_offset = OFFSET_CHECK_LINK_ACTIVE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -476,7 +540,7 @@ def check_if_link_is_active_for_torB(physical_port): , false if the link is not active """ - curr_offset = Y_CABLE_CHECK_LINK_ACTIVE + curr_offset = OFFSET_CHECK_LINK_ACTIVE if platform_chassis is not None: result = platform_chassis.get_sfp( @@ -507,3 +571,537 @@ def check_if_link_is_active_for_torB(physical_port): return True else: return False + + +@hook_y_cable_simulator +def enable_prbs_mode(physical_port, target, mode_value, lane_map): + """ + This API specifically configures and enables the PRBS mode/type depending upon the mode_value the user provides. + The mode_value configures the PRBS Type for generation and BER sensing on a per side basis. + Each side can only R/W its own value. 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31, 0x04-0xFF reserved. + Target is an integer for selecting which end of the Y cable we want to run PRBS on. + LaneMap specifies the lane configuration to run the PRBS on. + + + Register Specification of upper page 0x5 at offset 128, 129 is documented below + + Byte offset bits Name Description + 128 7-0 Reserved PRBS Type for generation and BER sensing on a per side basis. + Each side can only R/W its own value. + 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31, 0x04-0xFF reserved + + 129 7-4 Reserved + 3 Lane 4 enable "Enable PRBS generation on target lane 0b1 : + Enable, 0b0 disable If any lanes are enabled, + then that side of cable is removed fro mission mode and no longer passing valid traffic." + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + mode_value: + an Integer, the mode/type for configuring the PRBS mode. + 0x00 = PRBS 9, 0x01 = PRBS 15, 0x02 = PRBS 23, 0x03 = PRBS 31 + lane_map: + an Integer, representing the lane_map to be run PRBS on + 0bit for lane 0, 1bit for lane1 and so on. + for example 3 -> 0b'0011 , means running on lane0 and lane1 + + Returns: + a boolean, true if the enable is successful + , false if the enable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([mode_value]) + curr_offset = OFFSET_CONFIGURE_PRBS_TYPE + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([lane_map]) + curr_offset = OFFSET_ENABLE_PRBS + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def disable_prbs_mode(physical_port, target): + """ + This API specifically disables the PRBS mode on the physcial port. + + Register Specification of upper page 0x5 at offset 129 is documented below + + Byte offset bits Name Description + 129 7-4 Reserved + 3 Lane 4 enable "Enable PRBS generation on target lane 0b1 : + Enable, 0b0 disable If any lanes are enabled, + then that side of cable is removed fro mission mode and no longer passing valid traffic." + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + + Returns: + a boolean, true if the disable is successful + , false if the disable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_ENABLE_PRBS + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def enable_loopback_mode(physical_port, target, lane_map): + """ + This API specifically configures and enables the Loopback mode on the port user provides. + Target is an integer for selecting which end of the Y cable we want to run loopback on. + LaneMap specifies the lane configuration to run the loopback on. + + + Register Specification of upper page 0x5 at offset 153 is documented below + + Byte offset bits Name Description + 153 7-4 Reserved + 3 Lane 4 enable "Enable loopback generation on target lane 0b1 : + Enable, 0b0 disable.The cable supports 3 modes of operation : mission mode; PRBS mode or loopback mode. + Enabling loopback on any lane of any sides puts cable in loopback mode and disables PRBS. + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + lane_map: + an Integer, representing the lane_map to be run PRBS on + 0bit for lane 0, 1bit for lane1 and so on. + for example 3 -> 0b'0011 , means running on lane0 and lane1 + + Returns: + a boolean, true if the enable is successful + , false if the enable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([lane_map]) + curr_offset = OFFSET_ENABLE_LOOPBACK + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def disable_loopback_mode(physical_port, target): + """ + This API specifically disables the Loopback mode on the port user provides. + Target is an integer for selecting which end of the Y cable we want to run loopback on. + + + Register Specification of upper page 0x5 at offset 153 is documented below + + Byte offset bits Name Description + 153 7-4 Reserved + 3 Lane 4 enable "Enable loopback generation on target lane 0b1 : + Enable, 0b0 disable.The cable supports 3 modes of operation : + mission mode; PRBS mode or loopback mode. + Enabling loopback on any lane of any sides puts cable in loopback mode and disables PRBS. + 2 Lane 3 enable + 1 Lane 2 enable + 0 Lane 1 enable + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + + Returns: + a boolean, true if the disable is successful + , false if the disable failed + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_ENABLE_LOOPBACK + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return result + + +@hook_y_cable_simulator +def get_ber_info(physical_port, target): + """ + This API specifically returns the BER (Bit error rate) value for a specfic port. + The target could be local side, TOR1, TOR2, NIC etc. + + + Register Specification of upper page 0x5 at offset 130 is documented below + + Byte offset bits Name Description + 130 1-0 Initiate BER Measurement "Write 0x00 - initiate gated BER measurement on target side with PRBS traffic + Write 0x01-0xFF - reserved + Read 0x00 - BER Gate in process + Read 0x01 - BER Gate complete, valid values in Lane BER registers + NB this command is only valid when PRBS has been enabled on at least one lane + The cable supports 3 modes of operation : mission mode; PRBS mode or loopback mode. + Enabling PRBS on any lane of any sides puts cable in PRBS mode and disables loopback and mission mode." + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + Returns: + a list, with BER values of lane 0 and lane 1 with corresponding index + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + ber_result = [] + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_INITIATE_BER_MEASUREMENT + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + while(True): + done = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(done, 1, physical_port, "BER data ready to read") + if done[0] == 1: + break + + idx = 0 + maxLane = 2 + curr_offset = OFFSET_LANE_1_BER_RESULT + for lane in range(maxLane): + msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+idx, 1) + y_cable_validate_read_data(msb_result, 1, physical_port, "BER data msb result") + lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+1+idx, 1) + y_cable_validate_read_data(lsb_result, 1, physical_port, "BER data lsb result") + lane_result = msb_result[0] * math.pow(10, (lsb_result[0]-24)) + ber_result.append(lane_result) + idx += 2 + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return ber_result + + +@hook_y_cable_simulator +def get_eye_info(physical_port, target): + """ + This API specifically returns the EYE height value for a specfic port. + The target could be local side, TOR1, TOR2, NIC etc. + + + Register Specification of upper page 0x5 at offset 144 is documented below + + Byte offset bits Name Description + 144 1-0 Initiate EYE Measurement "Write 0x00 - initiate gated eye height measurement on target side with any traffic (PRBS or mission mode) + Write 0x01-0xFF - reserved + Read 0x00 - Eye Height Measurement in process + Read 0x01 - Eye Height Gate complete, valid values in Eye Height Registers + NB this command can be issued whenever the side is linked, this does not interrupt mission mode traffic" R/W + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + target: + an Integer, the target on which to enable the PRBS + EYE_PRBS_TARGET_LOCAL -> local side, + EYE_PRBS_TARGET_TOR1 -> TOR 1 + EYE_PRBS_TARGET_TOR2 -> TOR 2 + EYE_PRBS_TARGET_NIC -> NIC + Returns: + a list, with EYE values of lane 0 and lane 1 with corresponding index + """ + + buffer = bytearray([target]) + curr_offset = OFFSET_TARGET + + eye_result = [] + + if platform_chassis is not None: + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + buffer = bytearray([0]) + curr_offset = OFFSET_INITIATE_EYE_MEASUREMENT + result = platform_chassis.get_sfp( + physical_port).write_eeprom(curr_offset, 1, buffer) + if result is False: + return result + + while(True): + done = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(done, 1, physical_port, "EYE data ready to read") + if done[0] == 1: + break + + idx = 0 + maxLane = 2 + for lane in range(maxLane): + curr_offset = OFFSET_LANE_1_EYE_RESULT + msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+idx, 1) + y_cable_validate_read_data(msb_result, 1, physical_port, "EYE data msb result") + lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+1+idx, 1) + y_cable_validate_read_data(lsb_result, 1, physical_port, "EYE data lsb result") + lane_result = (msb_result[0] << 8 | lsb_result[0]) + eye_result.append(lane_result) + idx += 2 + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to configure the PRBS type") + return -1 + + return eye_result + + +@hook_y_cable_simulator +def get_pn_number_and_vendor_name(physical_port): + """ + This API specifically returns the pn number and vendor name for a specfic port. + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + Returns: + a tuple, with pn_number and vendor name + """ + + curr_offset = OFFSET_PN_NUMBER + + if platform_chassis is not None: + pn_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 15) + y_cable_validate_read_data(pn_result, 1, physical_port, "PN number") + curr_offset = OFFSET_VENDOR_NAME + vendor_name = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 15) + y_cable_validate_read_data(vendor_name, 15, physical_port, "vendor name") + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get pin results") + return -1 + + return pn_result, vendor_name + + +@hook_y_cable_simulator +def get_switch_count(physical_port, count_type): + """ + This API specifically returns the switch count to change the Active TOR which has + been done manually by the user. + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + count_type: + a string, for getting the count type + "manual" -> manual switch count + "auto" -> automatic switch count + Returns: + an integer, the number of times manually the Y-cable has been switched + """ + + if count_type == SWITCH_COUNT_MANUAL: + curr_offset = OFFSET_MANUAL_SWITCH_COUNT + elif count_type == SWITCH_COUNT_AUTO: + curr_offset = OFFSET_AUTO_SWITCH_COUNT + else: + helper_logger.log_error("not a valid count_type, failed to get switch count") + return -1 + + count = 0 + + if platform_chassis is not None: + msb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(msb_result, 1, physical_port, "{} switch count msb result".format(count_type)) + msb_result_1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + 1, 1) + y_cable_validate_read_data(msb_result_1, 1, physical_port, "{} switch count msb result 1".format(count_type)) + msb_result_2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + 2, 1) + y_cable_validate_read_data(msb_result_2, 1, physical_port, "{} switch count msb result 2".format(count_type)) + lsb_result = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset+3, 1) + y_cable_validate_read_data(lsb_result, 1, physical_port, "{} switch count lsb result".format(count_type)) + count = (msb_result[0] << 24 | msb_result_1[0] << 16 | msb_result_2[0] << 8 | lsb_result[0]) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get manual switch count") + return -1 + + return count + + +@hook_y_cable_simulator +def get_target_cursor_values(physical_port, lane, target): + """ + This API specifically returns the cursor equalization parameters for a target(NIC, TOR1, TOR2). + This includes pre one, pre two , main, post one, post two cursor values + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + lane: + an Integer, the lane on which to collect the cursor values + 1 -> lane 1, + 2 -> lane 2 + 3 -> lane 3 + 4 -> lane 4 + target: + an Integer, the actual target to get the cursor values on + TARGET_NIC -> NIC, + TARGET_TOR1-> TOR1, + TARGET_TOR2 -> TOR2 + Returns: + an list, with pre one, pre two , main, post one, post two cursor values in the order + """ + + curr_offset = OFFSET_NIC_CURSOR_VALUES + + result = [] + + if platform_chassis is not None: + pre1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5, 1) + y_cable_validate_read_data(pre1, 1, physical_port, "target cursor result") + result.append(c_int8(pre1[0]).value) + pre2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 1, 1) + y_cable_validate_read_data(pre2, 1, physical_port, "target cursor result") + result.append(c_int8(pre2[0]).value) + main = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 2, 1) + y_cable_validate_read_data(main, 1, physical_port, "target cursor result") + result.append(c_int8(main[0]).value) + post1 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 3, 1) + y_cable_validate_read_data(post1, 1, physical_port, "target cursor result") + result.append(c_int8(post1[0]).value) + post2 = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset + (target)*20 + (lane-1)*5 + 4, 1) + y_cable_validate_read_data(post2, 1, physical_port, "target cursor result") + result.append(c_int8(post2[0]).value) + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get target cursor values") + return -1 + + return result + + +@hook_y_cable_simulator +def check_if_nic_lanes_active(physical_port): + """ + This API specifically returns the byte value which denotes which nic lanes + are detected and active + + Args: + physical_port: + an Integer, the actual physical port connected to a Y cable + Returns: + an integer, with lower 4 bits representing which lanes are active from 1, 2, 3, 4 + in that order. + """ + + curr_offset = OFFSET_NIC_LANE_ACTIVE + + result = None + + if platform_chassis is not None: + res = platform_chassis.get_sfp(physical_port).read_eeprom(curr_offset, 1) + y_cable_validate_read_data(res, 1, physical_port, "nic lanes active") + result = res[0] + + else: + helper_logger.log_error("platform_chassis is not loaded, failed to get NIC lanes active") + return -1 + + return result