From f8eda1b20f2c7d2030a691d3b5cd79217b8e53d0 Mon Sep 17 00:00:00 2001 From: gengankarthik Date: Mon, 29 Jul 2019 13:37:24 -0700 Subject: [PATCH 1/2] DellEmc: Platform 2.0 Api(chassis,fan,eeprom) for S6100 and Z9100 --- .../common/dell_pmc.c | 179 ++++++++------ .../s6100/sonic_platform/chassis.py | 81 ++++++- .../s6100/sonic_platform/eeprom.py | 78 ++++++ .../s6100/sonic_platform/fan.py | 201 +++++++++++++++- .../z9100/sonic_platform/chassis.py | 82 ++++++- .../z9100/sonic_platform/eeprom.py | 76 ++++++ .../z9100/sonic_platform/fan.py | 222 ++++++++++++++++++ 7 files changed, 828 insertions(+), 91 deletions(-) create mode 100644 platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/eeprom.py create mode 100755 platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py diff --git a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c index 7e725a35a8ad..c5995a764670 100644 --- a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c +++ b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c @@ -70,7 +70,7 @@ #define FAN_TRAY_AIRFLOW 0x0116 -/* FAN Z9100 */ +/* FAN */ #define SMF_FAN_SPEED_ADDR 0x00F3 #define FAN_TRAY_1_SPEED 0x00F3 #define FAN_TRAY_1_FAN_2_SPEED 0x00F5 @@ -83,6 +83,11 @@ #define FAN_TRAY_5_FAN_1_SPEED 0x0103 #define FAN_TRAY_5_FAN_2_SPEED 0x0105 #define FAN_TRAY_5 4 +#define FAN_1_SERIAL_CODE 0x0117 +#define FAN_2_SERIAL_CODE 0x013A +#define FAN_3_SERIAL_CODE 0x015D +#define FAN_4_SERIAL_CODE 0x0180 +#define FAN_5_SERIAL_CODE 0x01A3 #define FAN_601_FAULT (2 + 1) #define IN28_INPUT (27 + 1) #define IN404_INPUT (43 + 1) @@ -1738,12 +1743,12 @@ static ssize_t show_psu(struct device *dev, /* FAN and PSU EEPROM PPID format is: COUNTRY_CODE-PART_NO-MFG_ID-MFG_DATE_CODE-SERIAL_NO-LABEL_REV */ -static ssize_t show_psu_ppid(struct device *dev, +static ssize_t show_ppid(struct device *dev, struct device_attribute *devattr, char *buf) { int index = to_sensor_dev_attr(devattr)->index; struct smf_data *data = dev_get_drvdata(dev); - char psu_ppid[EEPROM_PPID_SIZE + 1] = {0}; + char ppid[EEPROM_PPID_SIZE + 1] = {0}; char psu_mfg_date[EEPROM_MFG_DATE_SIZE + 1] = {0}; char psu_mfg_date_code[EEPROM_DATE_CODE_SIZE + 1] = {0}; char temp; @@ -1751,11 +1756,26 @@ static ssize_t show_psu_ppid(struct device *dev, switch(index) { - case 1: - // PPID starts from Country Code + /* PPID starts from Country Code*/ + case 0: + reg = FAN_1_SERIAL_CODE; + break; + case 1: + reg = FAN_2_SERIAL_CODE; + break; + case 2: + reg = FAN_3_SERIAL_CODE; + break; + case 3: + reg = FAN_4_SERIAL_CODE; + break; + case 4: + reg = FAN_5_SERIAL_CODE; + break; + case 10: reg = PSU_1_COUNTRY_CODE; break; - case 2: + case 11: reg = PSU_2_COUNTRY_CODE; break; default: @@ -1764,89 +1784,100 @@ static ssize_t show_psu_ppid(struct device *dev, // Get Country Code for( i = 0; i < EEPROM_COUNTRY_CODE_SIZE; i++) { - psu_ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); + ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); } - psu_ppid[ppid_pos++] = '-'; + ppid[ppid_pos++] = '-'; // Get Part Number for( i = 0; i < EEPROM_PART_NO_SIZE; i++) { - psu_ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); + ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); } - psu_ppid[ppid_pos++] = '-'; + ppid[ppid_pos++] = '-'; // Get Manufacture ID for( i = 0; i < EEPROM_MFG_ID_SIZE; i++) { - psu_ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); - } - psu_ppid[ppid_pos++] = '-'; - - // Get Manufacture date - for( i = 0; i < EEPROM_MFG_DATE_SIZE; i++) { - psu_mfg_date[i] = (char)smf_read_reg(data,reg++); - } - - /* Converting 6 digit date code [yymmdd] to 3 digit[ymd] - Year Starting from 2010 [0-9] , Day : 1-9 and A-V , Month : 1-9 and A-C */ - // Year Validation and Conversion - if( ( psu_mfg_date[0] == '1' ) && ( psu_mfg_date[1] >= '0' ) && ( psu_mfg_date[1] <= '9') ) - { - psu_mfg_date_code[0] = psu_mfg_date[1]; - } - else - { - psu_mfg_date_code[0] = ' '; + ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); } + ppid[ppid_pos++] = '-'; + if(index > 9){ //Applicable only for PSU + // Get Manufacture date + for( i = 0; i < EEPROM_MFG_DATE_SIZE; i++) { + psu_mfg_date[i] = (char)smf_read_reg(data,reg++); + } - // Month Validation and Conversion - temp = ( ( psu_mfg_date[2] - 0x30 ) * 10 ) + ( psu_mfg_date[3] - 0x30 ); - if( ( temp >= 1) && ( temp < 10) ) - { - psu_mfg_date_code[1] = temp + 0x30; // 0- 9 - } - else if ( ( temp >= 10) && ( temp <= 12) ) - { - psu_mfg_date_code[1] = temp + 0x37; // A-C - } - else - { - psu_mfg_date_code[1]= ' '; - } + /* Converting 6 digit date code [yymmdd] to 3 digit[ymd] + Year Starting from 2010 [0-9] , Day : 1-9 and A-V , Month : 1-9 and A-C */ + // Year Validation and Conversion + if( ( psu_mfg_date[0] == '1' ) && ( psu_mfg_date[1] >= '0' ) && ( psu_mfg_date[1] <= '9') ) + { + psu_mfg_date_code[0] = psu_mfg_date[1]; + } + else + { + psu_mfg_date_code[0] = ' '; + } + + // Month Validation and Conversion + temp = ( ( psu_mfg_date[2] - 0x30 ) * 10 ) + ( psu_mfg_date[3] - 0x30 ); + if( ( temp >= 1) && ( temp < 10) ) + { + psu_mfg_date_code[1] = temp + 0x30; // 0- 9 + } + else if ( ( temp >= 10) && ( temp <= 12) ) + { + psu_mfg_date_code[1] = temp + 0x37; // A-C + } + else + { + psu_mfg_date_code[1]= ' '; + } - // Date Validation and Conversion - temp = ( ( psu_mfg_date[4] - 0x30 ) * 10 ) + ( psu_mfg_date[5] - 0x30 ); - if( ( temp >= 1) && ( temp < 10) ) - { - psu_mfg_date_code[2] = temp + 0x30; // 0- 9 - } - else if( ( temp >= 10) && ( temp <= 31) ) - { - psu_mfg_date_code[2] = temp + 0x37; // A-V - } - else - { - psu_mfg_date_code[2] = ' '; + // Date Validation and Conversion + temp = ( ( psu_mfg_date[4] - 0x30 ) * 10 ) + ( psu_mfg_date[5] - 0x30 ); + if( ( temp >= 1) && ( temp < 10) ) + { + psu_mfg_date_code[2] = temp + 0x30; // 0- 9 + } + else if( ( temp >= 10) && ( temp <= 31) ) + { + psu_mfg_date_code[2] = temp + 0x37; // A-V + } + else + { + psu_mfg_date_code[2] = ' '; + } + for( i = 0; i < EEPROM_DATE_CODE_SIZE; i++) { + ppid[ppid_pos++] = psu_mfg_date_code[i]; + } + }else{ + for( i = 0; i < EEPROM_DATE_CODE_SIZE; i++) { + ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); + } } - for( i = 0; i < EEPROM_DATE_CODE_SIZE; i++) { - psu_ppid[ppid_pos++] = psu_mfg_date_code[i]; - } - psu_ppid[ppid_pos++] = '-'; + ppid[ppid_pos++] = '-'; // Get Serial Number for( i = 0; i < EEPROM_SERIAL_NO_SIZE; i++) { - psu_ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); + ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); } - psu_ppid[ppid_pos++] = '-'; + ppid[ppid_pos++] = '-'; - // Skipping service tag in PPID - reg += EEPROM_SERVICE_TAG_SIZE; + if(index > 9){ + // Skipping PSU service tag in PPID + reg += EEPROM_SERVICE_TAG_SIZE; + } + else{ + // Skipping FAN partno tag in PPID + reg += EEPROM_PART_NO_SIZE; + } // Get Label Revision for( i = 0; i < EEPROM_LABEL_REV_SIZE; i++) { - psu_ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); + ppid[ppid_pos++] = (char)smf_read_reg(data,reg++); } - return sprintf(buf, "%s\n",psu_ppid); + return sprintf(buf, "%s\n",ppid); } static umode_t smf_psu_is_visible(struct kobject *kobj, @@ -1924,14 +1955,19 @@ static SENSOR_DEVICE_ATTR(fan7_airflow, S_IRUGO, show_fan_airflow, NULL, 3); static SENSOR_DEVICE_ATTR(fan9_airflow, S_IRUGO, show_fan_airflow, NULL, 4); static SENSOR_DEVICE_ATTR(fan11_airflow, S_IRUGO, show_psu_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan12_airflow, S_IRUGO, show_psu_fan, NULL, 3); +static SENSOR_DEVICE_ATTR(fan1_serialno, S_IRUGO, show_ppid, NULL, 0); +static SENSOR_DEVICE_ATTR(fan3_serialno, S_IRUGO, show_ppid, NULL, 1); +static SENSOR_DEVICE_ATTR(fan5_serialno, S_IRUGO, show_ppid, NULL, 2); +static SENSOR_DEVICE_ATTR(fan7_serialno, S_IRUGO, show_ppid, NULL, 3); +static SENSOR_DEVICE_ATTR(fan9_serialno, S_IRUGO, show_ppid, NULL, 4); /* IOM status */ static SENSOR_DEVICE_ATTR(iom_status, S_IRUGO, show_voltage, NULL, 44); static SENSOR_DEVICE_ATTR(iom_presence, S_IRUGO, show_voltage, NULL, 45); static SENSOR_DEVICE_ATTR(psu1_presence, S_IRUGO, show_psu, NULL, 1); static SENSOR_DEVICE_ATTR(psu2_presence, S_IRUGO, show_psu, NULL, 6); -static SENSOR_DEVICE_ATTR(psu1_serialno, S_IRUGO, show_psu_ppid, NULL, 1); -static SENSOR_DEVICE_ATTR(psu2_serialno, S_IRUGO, show_psu_ppid, NULL, 2); +static SENSOR_DEVICE_ATTR(psu1_serialno, S_IRUGO, show_ppid, NULL, 10); +static SENSOR_DEVICE_ATTR(psu2_serialno, S_IRUGO, show_ppid, NULL, 11); static SENSOR_DEVICE_ATTR(current_total_power, S_IRUGO, show_psu, NULL, 10); /* SMF Version */ @@ -1964,6 +2000,11 @@ static struct attribute *smf_dell_attrs[] = { &sensor_dev_attr_psu2_presence.dev_attr.attr, &sensor_dev_attr_psu1_serialno.dev_attr.attr, &sensor_dev_attr_psu2_serialno.dev_attr.attr, + &sensor_dev_attr_fan1_serialno.dev_attr.attr, + &sensor_dev_attr_fan3_serialno.dev_attr.attr, + &sensor_dev_attr_fan5_serialno.dev_attr.attr, + &sensor_dev_attr_fan7_serialno.dev_attr.attr, + &sensor_dev_attr_fan9_serialno.dev_attr.attr, &sensor_dev_attr_current_total_power.dev_attr.attr, NULL }; @@ -1980,7 +2021,7 @@ static const struct attribute_group *smf_groups[] = { &smf_vsen_group, &smf_curr_group, &smf_tcpu_group, - &smf_dell_group, + &smf_dell_group, NULL }; diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py index ef229bd791e2..bef591a6c528 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ############################################################################# -# DELLEMC +# DELLEMC S6100 # # Module contains an implementation of SONiC Platform Base API and # provides the platform information @@ -13,6 +13,7 @@ from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.psu import Psu from sonic_platform.fan import Fan + from eeprom import Eeprom except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -42,8 +43,10 @@ class Chassis(ChassisBase): power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): - ChassisBase.__init__(self) + ChassisBase.__init__(self) + # Initialize EEPROM + self.sys_eeprom = Eeprom() for i in range(MAX_S6100_FAN): fan = Fan(i) self._fan_list.append(fan) @@ -52,7 +55,7 @@ def __init__(self): psu = Psu(i) self._psu_list.append(psu) - def get_pmc_register(self, reg_name): + def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' @@ -71,12 +74,79 @@ def get_pmc_register(self, reg_name): rv = rv.lstrip(" ") return rv + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self.sys_eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self.sys_eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the device (Service tag) + Returns: + string: Serial number of device + """ + return self.sys_eeprom.serial_str() + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self.sys_eeprom.base_mac_addr() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this chassis. + """ + return self.sys_eeprom.serial_number_str() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. """ - reset_reason = int(self.get_pmc_register('smf_reset_reason')) - power_reason = int(self.get_pmc_register('smf_poweron_reason')) + + reset_reason = int(self._get_pmc_register('smf_reset_reason')) + power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary @@ -93,4 +163,3 @@ def get_reboot_cause(self): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") - diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py new file mode 100644 index 000000000000..86c314f3ef22 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/eeprom.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +############################################################################# +# DellEmc S6100 +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo + import binascii +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom" + super(Eeprom, self).__init__(self.eeprom_path, 0, '', True) + try: + self.eeprom_data = self.read_eeprom() + except: + self.eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + + + def serial_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def base_mac_addr(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join([binascii.b2a_hex(T) for T in results[2]]) + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def serial_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2] + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2] + diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py index 696a9c0dd70b..c822ccdae2b9 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/fan.py @@ -1,42 +1,221 @@ #!/usr/bin/env python ######################################################################## -# DellEMC +# DellEMC S6100 # # Module contains an implementation of SONiC Platform Base API and -# provides the Fans' information which are available in the platform +# provides the Fans' information which are available in the platform. # ######################################################################## +import os.path try: - import os from sonic_platform_base.fan_base import FanBase except ImportError as e: raise ImportError(str(e) + "- required module not found") - MAX_S6100_PSU_FAN_SPEED = 18000 MAX_S6100_FAN_SPEED = 16000 class Fan(FanBase): - """DellEMC Platform-specific FAN class""" + """DellEMC Platform-specific Fan class""" HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" HWMON_NODE = os.listdir(HWMON_DIR)[0] MAILBOX_DIR = HWMON_DIR + HWMON_NODE - def __init__(self, fan_index, psu_fan=False): + def __init__(self, fantray_index, fan_index=1, psu_fan=False): self.is_psu_fan = psu_fan if not self.is_psu_fan: - # Fan is 1-based in DellEMC platforms - self.index = fan_index + 1 - self.get_fan_speed_reg = "fan{}_input".format(2*self.index - 1) + # API index is starting from 0, DellEMC platform index is starting + # from 1 + self.fantrayindex = fantray_index + 1 + self.fanindex = fan_index + 1 + self.get_fan_speed_reg = "fan{}_input".format( + 2 * self.fantrayindex - 1) + self.get_fan_dir_reg = "fan{}_airflow".format( + 2 * self.fantrayindex - 1) + self.fan_serialno_reg = "fan{}_serialno".format( + 2 * self.fantrayindex - 1) self.max_fan_speed = MAX_S6100_FAN_SPEED else: # PSU Fan index starts from 11 - self.index = fan_index + 10 - self.get_fan_speed_reg = "fan{}_input".format(self.index) + self.fanindex = fan_index + 10 + self.get_fan_speed_reg = "fan{}_input".format(self.fanindex) self.max_fan_speed = MAX_S6100_PSU_FAN_SPEED + def _get_pmc_register(self, reg_name): + # On successful read, returns the value read from given + # reg_name and on failure returns 'ERR' + rv = 'ERR' + mb_reg_file = self.MAILBOX_DIR+'/'+reg_name + + if (not os.path.isfile(mb_reg_file)): + return rv + try: + with open(mb_reg_file, 'r') as fd: + rv = fd.read() + except Exception as error: + rv = 'ERR' + + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + + def get_name(self): + """ + Retrieves the fan name + Returns: + string: The name of the device + """ + if not self.is_psu_fan: + return "FanTray{}-Fan{}".format( + self.fantrayindex, self.fanindex - 1) + else: + return "PSU{} Fan".format(self.index - 10) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + # For Serial number "US-01234D-54321-25A-0123-A00", the part + # number is "01234D" + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) + if (fan_serialno != 'ERR') and self.get_presence(): + if (len(fan_serialno.split('-')) > 1): + fan_partno = fan_serialno.split('-')[1] + else: + fan_partno = 'NA' + else: + fan_partno = 'NA' + + return fan_partno + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + # Sample Serial number format "US-01234D-54321-25A-0123-A00" + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) + if (fan_serialno == 'ERR') or not self.get_presence(): + fan_serialno = 'NA' + + return fan_serialno + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + status = False + fantray_presence = self._get_pmc_register(self.get_fan_speed_reg) + if (fantray_presence != 'ERR'): + fantray_presence = int(fantray_presence, 10) + if (fantray_presence > 0): + status = True + + return status + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + status = False + fantray_status = self._get_pmc_register(self.get_fan_speed_reg) + if (fantray_status != 'ERR'): + fantray_status = int(fantray_status, 10) + if (fantray_status > 5000): + status = True + + return status + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = ['FAN_DIRECTION_INTAKE', 'FAN_DIRECTION_EXHAUST'] + fan_direction = self._get_pmc_register(self.get_fan_dir_reg) + if (fan_direction != 'ERR') and self.get_presence(): + fan_direction = int(fan_direction, 10) + else: + return 'N/A' + return direction[fan_direction] + + def get_speed(self): + """ + Retrieves the speed of fan + Returns: + int: percentage of the max fan speed + """ + fan_speed = self._get_pmc_register(self.get_fan_speed_reg) + if (fan_speed != 'ERR') and self.get_presence(): + speed_in_rpm = int(fan_speed, 10) + speed = (100 * speed_in_rpm)/self.max_fan_speed + else: + speed = 0 + + return speed + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + if self.get_presence(): + # The tolerance value is fixed as 20% for all the DellEmc platform + tolerance = 20 + else: + tolerance = 0 + + return tolerance + + def set_speed(self, speed): + """ + Set fan speed to expected value + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + bool: True if set success, False if fail. + """ + + # Fan speeds are controlled by Smart-fussion FPGA. + return False + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Leds are controlled by Smart-fussion FPGA. + status = False + return status + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + return 0 + + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py index 8e53ec81559b..654efa3cd26f 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/chassis.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ############################################################################# -# DELLEMC +# DELLEMC Z9100 # # Module contains an implementation of SONiC Platform Base API and # provides the platform information @@ -11,9 +11,15 @@ try: import os from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.fan import Fan + from eeprom import Eeprom except ImportError as e: raise ImportError(str(e) + "- required module not found") +MAX_Z9100_FANTRAY = 5 +MAX_Z9100_FAN = 2 +MAX_Z9100_PSU = 2 + class Chassis(ChassisBase): """ @@ -37,9 +43,16 @@ class Chassis(ChassisBase): power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED def __init__(self): - ChassisBase.__init__(self) - def get_pmc_register(self, reg_name): + ChassisBase.__init__(self) + # Initialize EEPROM + self.sys_eeprom = Eeprom() + for i in range(MAX_Z9100_FANTRAY): + for j in range(MAX_Z9100_FAN): + fan = Fan(i, j) + self._fan_list.append(fan) + + def _get_pmc_register(self, reg_name): # On successful read, returns the value read from given # reg_name and on failure returns 'ERR' rv = 'ERR' @@ -58,12 +71,70 @@ def get_pmc_register(self, reg_name): rv = rv.lstrip(" ") return rv + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self.sys_eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self.sys_eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the device (Service tag) + Returns: + string: Serial number of device + """ + return self.sys_eeprom.serial_str() + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self.sys_eeprom.base_mac_addr() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this chassis. + """ + return self.sys_eeprom.serial_number_str() + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. """ - reset_reason = int(self.get_pmc_register('smf_reset_reason')) - power_reason = int(self.get_pmc_register('smf_poweron_reason')) + + reset_reason = int(self._get_pmc_register('smf_reset_reason')) + power_reason = int(self._get_pmc_register('smf_poweron_reason')) # Reset_Reason = 11 ==> PowerLoss # So return the reboot reason from Last Power_Reason Dictionary @@ -81,3 +152,4 @@ def get_reboot_cause(self): return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/eeprom.py new file mode 100644 index 000000000000..8be488b791ab --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/eeprom.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +############################################################################# +# DellEmc Z9100 +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo + import binascii +except ImportError, e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom" + super(Eeprom, self).__init__(self.eeprom_path, 0, '', True) + try: + self.eeprom_data = self.read_eeprom() + except: + self.eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + + def serial_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + return results[2] + + def base_mac_addr(self): + (is_valid, t) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or t[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join([binascii.b2a_hex(T) for T in t[2]]) + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def serial_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2] + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2] + diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py new file mode 100755 index 000000000000..2327e24a2f6d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/fan.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC Z9100 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## + +import os.path + +try: + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +MAX_Z9100_PSU_FAN_SPEED = 18000 +MAX_Z9100_FAN_SPEED = 16000 + + +class Fan(FanBase): + """DellEMC Platform-specific Fan class""" + + HWMON_DIR = "/sys/devices/platform/SMF.512/hwmon/" + HWMON_NODE = os.listdir(HWMON_DIR)[0] + MAILBOX_DIR = HWMON_DIR + HWMON_NODE + + def __init__(self, fantray_index, fan_index=1, psu_fan=False): + self.is_psu_fan = psu_fan + if not self.is_psu_fan: + # API index is starting from 0, DellEMC platform index is starting + # from 1 + self.fantrayindex = fantray_index + 1 + self.fanindex = fan_index + 1 + self.get_fan_speed_reg = "fan{}_input".format( + 2 * (self.fantrayindex - 1) + (self.fanindex - 1) + 1 ) + self.get_fan_dir_reg = "fan{}_airflow".format( + 2 * self.fantrayindex - 1) + self.fan_serialno_reg = "fan{}_serialno".format( + 2 * self.fantrayindex - 1) + self.max_fan_speed = MAX_Z9100_FAN_SPEED + else: + # PSU Fan index starts from 11 + self.fanindex = fan_index + 10 + self.get_fan_speed_reg = "fan{}_input".format(self.fanindex) + self.max_fan_speed = MAX_Z9100_PSU_FAN_SPEED + + def _get_pmc_register(self, reg_name): + # On successful read, returns the value read from given + # reg_name and on failure returns 'ERR' + rv = 'ERR' + mb_reg_file = self.MAILBOX_DIR+'/'+reg_name + + if (not os.path.isfile(mb_reg_file)): + return rv + try: + with open(mb_reg_file, 'r') as fd: + rv = fd.read() + except Exception as error: + rv = 'ERR' + + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + + def get_name(self): + """ + Retrieves the fan name + Returns: + string: The name of the device + """ + if not self.is_psu_fan: + return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) + else: + return "PSU{} Fan".format(self.index - 10) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + # For Serial number "US-01234D-54321-25A-0123-A00", the part + # number is "01234D" + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) + if (fan_serialno != 'ERR') and self.get_presence(): + if (len(fan_serialno.split('-')) > 1): + fan_partno = fan_serialno.split('-')[1] + else: + fan_partno = 'NA' + else: + fan_partno = 'NA' + + return fan_partno + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + # Sample Serial number format "US-01234D-54321-25A-0123-A00" + fan_serialno = self._get_pmc_register(self.fan_serialno_reg) + if (fan_serialno == 'ERR') or not self.get_presence(): + fan_serialno = 'NA' + + return fan_serialno + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + status = False + fantray_presence = self._get_pmc_register(self.get_fan_speed_reg) + if (fantray_presence != 'ERR'): + fantray_presence = int(fantray_presence, 10) + if (fantray_presence > 0): + status = True + + return status + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + status = False + fantray_status = self._get_pmc_register(self.get_fan_speed_reg) + if (fantray_status != 'ERR'): + fantray_status = int(fantray_status, 10) + if (fantray_status > 5000): + status = True + + return status + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = ['FAN_DIRECTION_INTAKE', 'FAN_DIRECTION_EXHAUST'] + fan_direction = self._get_pmc_register(self.get_fan_dir_reg) + if (fan_direction != 'ERR') and self.get_presence(): + fan_direction = int(fan_direction, 10) + else: + return 'N/A' + return direction[fan_direction] + + def get_speed(self): + """ + Retrieves the speed of fan + Returns: + int: percentage of the max fan speed + """ + fan_speed = self._get_pmc_register(self.get_fan_speed_reg) + if (fan_speed != 'ERR') and self.get_presence(): + speed_in_rpm = int(fan_speed, 10) + speed = (100 * speed_in_rpm)/self.max_fan_speed + else: + speed = 0 + + return speed + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + if self.get_presence(): + # The tolerance value is fixed as 20% for all the DellEmc platform + tolerance = 20 + else: + tolerance = 0 + + return tolerance + + def set_speed(self, speed): + """ + Set fan speed to expected value + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + bool: True if set success, False if fail. + """ + + # Fan speeds are controlled by Smart-fussion FPGA. + return False + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Leds are controlled by Smart-fussion FPGA. + status = False + return status + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + return 0 + + + + From 26476b16556ee5935fb342a79c4627bb4827d600 Mon Sep 17 00:00:00 2001 From: gengankarthik Date: Wed, 7 Aug 2019 02:52:42 -0700 Subject: [PATCH 2/2] DellEmc: Platform 2.0 Api(chassis,fan,eeprom) for S6100 and Z9100 (corrected Indentation) --- .../common/dell_pmc.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c index c5995a764670..963c2c725f74 100644 --- a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c +++ b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c @@ -1772,15 +1772,15 @@ static ssize_t show_ppid(struct device *dev, case 4: reg = FAN_5_SERIAL_CODE; break; - case 10: - reg = PSU_1_COUNTRY_CODE; - break; - case 11: - reg = PSU_2_COUNTRY_CODE; - break; - default: - return ret; - } + case 10: + reg = PSU_1_COUNTRY_CODE; + break; + case 11: + reg = PSU_2_COUNTRY_CODE; + break; + default: + return ret; +} // Get Country Code for( i = 0; i < EEPROM_COUNTRY_CODE_SIZE; i++) { @@ -2021,7 +2021,7 @@ static const struct attribute_group *smf_groups[] = { &smf_vsen_group, &smf_curr_group, &smf_tcpu_group, - &smf_dell_group, + &smf_dell_group, NULL };