From 7137e3f949bc51ef1cd1beceee7a0df0ea62d822 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar T <53558409+santhosh-kt@users.noreply.github.com> Date: Thu, 21 Oct 2021 18:53:41 +0530 Subject: [PATCH] [Dell] S6000 I2C not responding to certain optics (#8736) * [Dell] S6000 I2C not responding to certain optics * Revising return states * Moved lock file from /var/run/platform_cache to /etc/sonic --- .../plugins/sfputil.py | 108 +++++++++++++++++- .../s6000/modules/dell_s6000_platform.c | 21 +++- .../s6000/scripts/s6000_platform.sh | 4 + .../s6000/sonic_platform/sfp.py | 78 +++++++++++++ 4 files changed, 206 insertions(+), 5 deletions(-) diff --git a/device/dell/x86_64-dell_s6000_s1220-r0/plugins/sfputil.py b/device/dell/x86_64-dell_s6000_s1220-r0/plugins/sfputil.py index f03415cbc7..8d8892fdce 100644 --- a/device/dell/x86_64-dell_s6000_s1220-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dell_s6000_s1220-r0/plugins/sfputil.py @@ -6,6 +6,7 @@ try: import time import datetime + import fcntl from sonic_sfp.sfputilbase import SfpUtilBase except ImportError as e: raise ImportError("%s - required module not found" % str(e)) @@ -19,6 +20,7 @@ class SfpUtil(SfpUtilBase): PORTS_IN_BLOCK = 32 EEPROM_OFFSET = 20 + SFP_LOCK_FILE="/etc/sonic/sfp_lock" _port_to_eeprom_mapping = {} port_dict = {} @@ -72,8 +74,42 @@ class SfpUtil(SfpUtilBase): if port_num < self.port_start or port_num > self.port_end: return False + try: + fd = open(self.SFP_LOCK_FILE, "r") + except IOError as e: + print("Error: unable to open file: "+ str(e)) + return False + fcntl.flock(fd, fcntl.LOCK_EX) + self.set_modsel(port_num) + try: reg_file = open("/sys/devices/platform/dell-s6000-cpld.0/qsfp_modprs") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + fcntl.flock(fd, fcntl.LOCK_UN) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + fcntl.flock(fd, fcntl.LOCK_UN) + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_modsel(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/dell-s6000-cpld.0/qsfp_modsel") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -86,11 +122,75 @@ class SfpUtil(SfpUtilBase): # Mask off the bit corresponding to our port mask = (1 << port_num) - # ModPrsL is active low - if reg_value & mask == 0: - return True + if reg_value & mask == 1: + return False - return False + return True + + def set_modsel(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/dell-s6000-cpld.0/qsfp_modsel", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + reg_value = reg_value | int("0xffffffff", 16) + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def get_eeprom_raw(self, port_num, num_bytes=256): + # Read interface id EEPROM at addr 0x50 + try: + fd = open(self.SFP_LOCK_FILE, "r") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + fcntl.flock(fd, fcntl.LOCK_EX) + self.set_modsel(port_num) + eeprom_bytes = self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 0, num_bytes) + fcntl.flock(fd, fcntl.LOCK_UN) + return eeprom_bytes + + def get_eeprom_dom_raw(self, port_num): + if port_num in self.osfp_ports: + return None + if port_num in self.qsfp_ports: + # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw + return None + else: + # Read dom eeprom at addr 0x51 + if not self.get_modsel(port_num): + try: + fd = open(self.SFP_LOCK_FILE, "r") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + fcntl.flock(fd, fcntl.LOCK_EX) + self.set_modsel(port_num) + eeprom_bytes = self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 0) + fcntl.flock(fd, fcntl.LOCK_UN) + return eeprom_bytes + else: + return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 0) def get_low_power_mode(self, port_num): # Check for invalid port_num diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/modules/dell_s6000_platform.c b/platform/broadcom/sonic-platform-modules-dell/s6000/modules/dell_s6000_platform.c index cbf506940a..351e518ba4 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/modules/dell_s6000_platform.c +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/modules/dell_s6000_platform.c @@ -312,6 +312,25 @@ static ssize_t get_modsel(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "0x%08x\n", data); } +static ssize_t set_modsel(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + int err; + unsigned long data = 0; + struct cpld_platform_data *pdata = dev->platform_data; + + err = kstrtoul(buf, 16, &data); + if (err) + return err; + + dell_i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x0, (u8)(data & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x1, (u8)((data >> 8) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0xa, (u8)((data >> 16) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0xb, (u8)((data >> 24) & 0xff)); + + msleep(2); // As per HW spec + return count; +} + static ssize_t get_lpmode(struct device *dev, struct device_attribute *devattr, char *buf) { int ret; @@ -1128,7 +1147,7 @@ static ssize_t get_reboot_reason(struct device *dev, return sprintf(buf, "0x%x\n", data); } -static DEVICE_ATTR(qsfp_modsel, S_IRUGO, get_modsel, NULL); +static DEVICE_ATTR(qsfp_modsel, S_IRUGO | S_IWUSR, get_modsel, set_modsel); static DEVICE_ATTR(qsfp_modprs, S_IRUGO, get_modprs, NULL); static DEVICE_ATTR(qsfp_lpmode, S_IRUGO | S_IWUSR, get_lpmode, set_lpmode); static DEVICE_ATTR(qsfp_reset, S_IRUGO | S_IWUSR, get_reset, set_reset); diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh index a98df43ef2..862667ba61 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/scripts/s6000_platform.sh @@ -97,6 +97,10 @@ remove_python_api_package() { # read SONiC immutable variables [ -f /etc/sonic/sonic-environment ] && . /etc/sonic/sonic-environment +if [ ! -e /etc/sonic/sfp_lock ]; then + touch /etc/sonic/sfp_lock +fi + if [[ "$1" == "init" ]]; then depmod -a modprobe nvram diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py index b66cb31ec9..56b8287302 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py @@ -12,6 +12,7 @@ try: import re import struct import time + import fcntl from sonic_platform_base.sfp_base import SfpBase from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom @@ -154,6 +155,15 @@ class Sfp(SfpBase): if (self.sfpInfo is None): return None + SFP_LOCK_FILE="/etc/sonic/sfp_lock" + try: + fd = open(SFP_LOCK_FILE, "r") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + fcntl.flock(fd, fcntl.LOCK_EX) + self.set_modsel() + page_offset = sff8436_parser[eeprom_key][PAGE_OFFSET] eeprom_data_raw = self._read_eeprom_bytes( self.eeprom_path, @@ -172,6 +182,7 @@ class Sfp(SfpBase): self.sfpDomInfo, sff8436_parser[eeprom_key][FUNC_NAME])( eeprom_data_raw, 0) + fcntl.flock(fd, fcntl.LOCK_UN) return eeprom_data def _strip_unit_from_str(self, value_str): @@ -423,6 +434,16 @@ class Sfp(SfpBase): Retrieves the presence of the sfp """ presence_ctrl = self.sfp_control + 'qsfp_modprs' + SFP_LOCK_FILE="/etc/sonic/sfp_lock" + + try: + fd = open(SFP_LOCK_FILE, "r") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + fcntl.flock(fd, fcntl.LOCK_EX) + self.set_modsel() + try: reg_file = open(presence_ctrl) except IOError as e: @@ -437,12 +458,69 @@ class Sfp(SfpBase): # Mask off the bit corresponding to our port mask = (1 << self.sfp_ctrl_idx) + fcntl.flock(fd, fcntl.LOCK_UN) + # ModPrsL is active low if ((reg_value & mask) == 0): return True return False + def get_modsel(self): + modsel_ctrl = self.sfp_control + 'qsfp_modsel' + try: + reg_file = open(modsel_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + if ((reg_value & mask) == 1): + modsel_state = False + else: + modsel_state = True + + return modsel_state + + def set_modsel(self): + modsel_ctrl = self.sfp_control + 'qsfp_modsel' + try: + reg_file = open(modsel_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + reg_value = reg_value | int("0xffffffff", 16) + mask = (1 << index) + + reg_value = (reg_value & ~mask) + + # Convert our register value back to a hex string and write back + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + def get_model(self): """ Retrieves the model number (or part number) of the sfp