DellEMC: S5296F Platform API 2.0 changes (#11162)
Why I did it S5296F - Platform API 2.0 changes How I did it Implemented the functional API's needed for Platform API 2.0 How to verify it Used the API 2.0 test suite to validate the test cases.
This commit is contained in:
parent
8d06de37ae
commit
13bd63e73a
578
device/dell/x86_64-dellemc_s5296f_c3538-r0/platform.json
Normal file
578
device/dell/x86_64-dellemc_s5296f_c3538-r0/platform.json
Normal file
@ -0,0 +1,578 @@
|
||||
{
|
||||
"chassis": {
|
||||
"name": "S5296F-ON",
|
||||
"status_led": {
|
||||
"controllable": true,
|
||||
"colors": ["green", "flashing green", "yellow", "flashing yellow"]
|
||||
},
|
||||
"thermal_manager" : false,
|
||||
"components": [
|
||||
{
|
||||
"name": "BIOS"
|
||||
},
|
||||
{
|
||||
"name": "FPGA"
|
||||
},
|
||||
{
|
||||
"name": "BMC"
|
||||
},
|
||||
{
|
||||
"name": "System CPLD"
|
||||
},
|
||||
{
|
||||
"name": "Secondary CPLD 1"
|
||||
},
|
||||
{
|
||||
"name": "Secondary CPLD 2"
|
||||
},
|
||||
{
|
||||
"name": "Secondary CPLD 3"
|
||||
},
|
||||
{
|
||||
"name": "Secondary CPLD 4"
|
||||
}
|
||||
],
|
||||
"fans": [
|
||||
{
|
||||
"name": "FanTray1-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FanTray2-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FanTray3-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FanTray4-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"fan_drawers":[
|
||||
{
|
||||
"name": "FanTray1",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "FanTray1-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FanTray2",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "FanTray2-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FanTray3",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "FanTray3-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FanTray4",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "FanTray4-Fan1",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"psus": [
|
||||
{
|
||||
"name": "PSU1",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "PSU1 Fan",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PSU2",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "PSU2 Fan",
|
||||
"speed": {
|
||||
"controllable": false
|
||||
},
|
||||
"status_led": {
|
||||
"available": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"thermals": [
|
||||
{
|
||||
"name": "ASIC On-board",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "CPU On-board",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "Inlet Airflow Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-threshold": false,
|
||||
"high-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PSU1 Airflow Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-threshold": false,
|
||||
"high-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PSU1 Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PSU2 Airflow Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-threshold": false,
|
||||
"high-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PSU2 Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PT Left Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PT Middle Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-threshold": false,
|
||||
"high-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
},
|
||||
{
|
||||
"name": "PT Right Sensor",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-threshold": false,
|
||||
"high-crit-threshold": false,
|
||||
"minimum-recorded": false,
|
||||
"maximum-recorded": false
|
||||
}
|
||||
],
|
||||
"modules": [],
|
||||
"sfps": [
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "SFP/SFP+/SFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
},
|
||||
{
|
||||
"name": "QSFP28"
|
||||
}
|
||||
]
|
||||
},
|
||||
"interfaces": {}
|
||||
}
|
@ -1,8 +1,3 @@
|
||||
{
|
||||
"skip_sensors": true,
|
||||
"skip_fancontrol": true,
|
||||
"skip_ledd": true,
|
||||
"skip_psud": true,
|
||||
"skip_syseepromd": true,
|
||||
"skip_thermalctld": true
|
||||
"skip_ledd": true
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ s5296f/scripts/sensors usr/bin
|
||||
s5296f/scripts/pcisysfs.py usr/bin
|
||||
s5296f/cfg/s5296f-modules.conf etc/modules-load.d
|
||||
s5296f/systemd/platform-modules-s5296f.service etc/systemd/system
|
||||
s5296f/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_s5296f_c3538-r0
|
||||
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5296f_c3538-r0
|
||||
common/fw-updater usr/local/bin
|
||||
common/onie_mode_set usr/local/bin
|
||||
|
@ -55,6 +55,11 @@ override_dh_auto_build:
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
cd $(MOD_SRC_DIR); \
|
||||
elif [ $$mod = "s5296f" ]; then \
|
||||
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
cd $(MOD_SRC_DIR); \
|
||||
elif [ $$mod = "n3248te" ]; then \
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
@ -143,6 +148,11 @@ override_dh_clean:
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
|
||||
elif [ $$mod = "s5296f" ]; then \
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
|
||||
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
|
||||
elif [ $$mod = "z9332f" ]; then \
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
|
||||
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
|
||||
|
@ -89,7 +89,7 @@ struct fpgapci_dev {
|
||||
unsigned int irq_first;
|
||||
unsigned int irq_length;
|
||||
unsigned int irq_assigned;
|
||||
unsigned int xcvr_intr_count;
|
||||
|
||||
};
|
||||
|
||||
static int use_irq = 1;
|
||||
@ -107,6 +107,13 @@ MODULE_PARM_DESC(num_bus,
|
||||
/* Subsystem: Xilinx Corporation Device 0007 */
|
||||
//#define VENDOR 0x10EE
|
||||
#define DEVICE 0x7021
|
||||
|
||||
/* Altera FPGA PCIE info:
|
||||
Unassigned class [ff00]: Altera Corporation Device 0004 (rev 01)
|
||||
Subsystem: Altera Corporation Device 0004 */
|
||||
#define PCI_VENDOR_ID_ALTERA 0x1172
|
||||
#define PCI_DEVICE_ID_ALTERA 0x0004
|
||||
|
||||
static phys_addr_t fpga_phys_addr;
|
||||
|
||||
typedef signed char s8;
|
||||
@ -190,7 +197,7 @@ struct fpgalogic_i2c {
|
||||
#define FPGAI2C_REG_STAT_NACK 0x80
|
||||
|
||||
/* SR[7:0] - Status register */
|
||||
#define FPGAI2C_REG_SR_RXACK (1 << 7) /* Receive acknowledge from slave ‘1’ = No acknowledge received*/
|
||||
#define FPGAI2C_REG_SR_RXACK (1 << 7) /* Receive acknowledge from secondary <20>1<EFBFBD> = No acknowledge received*/
|
||||
#define FPGAI2C_REG_SR_BUSY (1 << 6) /* Busy, I2C bus busy (as defined by start / stop bits) */
|
||||
#define FPGAI2C_REG_SR_AL (1 << 5) /* Arbitration lost - fpga i2c logic lost arbitration */
|
||||
#define FPGAI2C_REG_SR_TIP (1 << 1) /* Transfer in progress */
|
||||
@ -227,13 +234,6 @@ enum {
|
||||
#define I2C_PCI_BUS_NUM_12 12
|
||||
#define I2C_PCI_BUS_NUM_16 16
|
||||
|
||||
#define IRQ_LTCH_STS 0x20
|
||||
#define PRSNT_LTCH_STS 0x10
|
||||
|
||||
#define PORT_CTRL_OFFSET 0x4000
|
||||
#define PORT_STS_OFFSET 0x4004
|
||||
#define PORT_IRQ_STS_OFFSET 0x4008
|
||||
#define PORT_IRQ_EN_OFFSET 0x400C
|
||||
#define MB_BRD_REV_TYPE 0x0008
|
||||
#define MB_BRD_REV_MASK 0x00f0
|
||||
#define MB_BRD_REV_00 0x0000
|
||||
@ -256,7 +256,7 @@ enum {
|
||||
#define BRD_TYPE_S5232_NON_NEBS 0xc
|
||||
#define BRD_TYPE_S5232_NEBS 0xd
|
||||
|
||||
#define FPGA_CTL_REG_SIZE 0x6000
|
||||
#define FPGA_CTL_REG_SIZE 0x60
|
||||
#define MSI_VECTOR_MAP_MASK 0x1f
|
||||
#define MSI_VECTOR_MAP1 0x58
|
||||
#define I2C_CH1_MSI_MAP_VECT_8 0x00000008
|
||||
@ -292,8 +292,6 @@ enum {
|
||||
#define MSI_VECTOR_REV_00 16
|
||||
#define MSI_VECTOR_REV_01 32
|
||||
|
||||
#define FPGA_MSI_VECTOR_ID_4 4
|
||||
#define FPGA_MSI_VECTOR_ID_5 5
|
||||
#define FPGA_MSI_VECTOR_ID_8 8
|
||||
#define FPGA_MSI_VECTOR_ID_9 9
|
||||
#define FPGA_MSI_VECTOR_ID_10 10
|
||||
@ -312,7 +310,7 @@ enum {
|
||||
#define FPGA_MSI_VECTOR_ID_23 23
|
||||
#define FPGA_MSI_VECTOR_ID_24 24
|
||||
|
||||
|
||||
#define MAX_WAIT_LOOP 10
|
||||
|
||||
static int total_i2c_pci_bus = 0;
|
||||
static uint32_t board_rev_type = 0;
|
||||
@ -431,7 +429,7 @@ static int fpgai2c_poll(struct fpgalogic_i2c *i2c)
|
||||
}
|
||||
|
||||
/* Error? */
|
||||
if (stat & FPGAI2C_REG_STAT_ARBLOST) {
|
||||
if ((stat & FPGAI2C_REG_STAT_ARBLOST) || ( i2c->msg == NULL) || ( i2c->msg->buf == NULL)) {
|
||||
i2c->state = STATE_ERROR;
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP);
|
||||
return -EAGAIN;
|
||||
@ -516,72 +514,6 @@ static int fpgai2c_poll(struct fpgalogic_i2c *i2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t get_mod_msi(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int ind = 0, port_status=0, port_irq_status=0;
|
||||
struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(dev);
|
||||
PRINT("%s:xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count);
|
||||
for(ind=0;ind<64;ind++)
|
||||
{
|
||||
port_status = ioread32(fpga_ctl_addr + PORT_STS_OFFSET + (ind*16));
|
||||
port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status);
|
||||
}
|
||||
return sprintf(buf,"0x%04x\n",fpgapci->xcvr_intr_count);
|
||||
}
|
||||
static DEVICE_ATTR(port_msi, S_IRUGO, get_mod_msi, NULL);
|
||||
|
||||
static struct attribute *port_attrs[] = {
|
||||
&dev_attr_port_msi.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group port_attr_grp = {
|
||||
.attrs = port_attrs,
|
||||
};
|
||||
|
||||
|
||||
static irqreturn_t fpgaport_1_32_isr(int irq, void *dev)
|
||||
{
|
||||
struct pci_dev *pdev = dev;
|
||||
struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev);
|
||||
int ind = 0, port_status=0, port_irq_status=0;
|
||||
for(ind=0;ind<32;ind++)
|
||||
{
|
||||
port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
if(port_irq_status&(IRQ_LTCH_STS|PRSNT_LTCH_STS))
|
||||
{
|
||||
PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status);
|
||||
//write on clear
|
||||
iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
}
|
||||
}
|
||||
fpgapci->xcvr_intr_count++;
|
||||
PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count);
|
||||
sysfs_notify(&pdev->dev.kobj, NULL, "port_msi");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t fpgaport_33_64_isr(int irq, void *dev)
|
||||
{
|
||||
struct pci_dev *pdev = dev;
|
||||
struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev);
|
||||
int ind = 0, port_status=0, port_irq_status=0;
|
||||
for(ind=32;ind<64;ind++)
|
||||
{
|
||||
port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
if(port_irq_status| (IRQ_LTCH_STS|PRSNT_LTCH_STS))
|
||||
{
|
||||
PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status);
|
||||
iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16));
|
||||
}
|
||||
}
|
||||
fpgapci->xcvr_intr_count++;
|
||||
PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count);
|
||||
sysfs_notify(&pdev->dev.kobj, NULL, "port_msi");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void fpgai2c_process(struct fpgalogic_i2c *i2c)
|
||||
{
|
||||
struct i2c_msg *msg = i2c->msg;
|
||||
@ -610,6 +542,12 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Spurious IRQs would lead to invocation of handler with msg being NULL.
|
||||
* Skip handling them.
|
||||
*/
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
|
||||
i2c->state =
|
||||
(msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
|
||||
@ -621,6 +559,11 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c)
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(( i2c->msg == NULL) || ( i2c->msg->buf == NULL) || (i2c->pos >= i2c->msg->len) ) {
|
||||
printk("crash debug..1 fpgai2c_process MSG and MAS->BUFF is NULL or pos > len ");
|
||||
return;
|
||||
}
|
||||
|
||||
msg->buf[i2c->pos++] = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA);
|
||||
}
|
||||
|
||||
@ -657,12 +600,25 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c)
|
||||
}
|
||||
|
||||
if (i2c->state == STATE_READ) {
|
||||
|
||||
if(( i2c->msg == NULL) || ( i2c->msg->buf == NULL) || (i2c->pos >= i2c->msg->len) ) {
|
||||
printk("crash debug..2 fpgai2c_process MSG and MAS->BUFF is NULL or pos > len ");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PRINT("fpgai2c_poll STATE_READ i2c->pos=%d msg->len-1 = 0x%x set FPGAI2C_REG_CMD = 0x%x\n",i2c->pos, msg->len-1,
|
||||
i2c->pos == (msg->len-1) ? FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK);
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, i2c->pos == (msg->len-1) ?
|
||||
FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK);
|
||||
} else {
|
||||
PRINT("fpgai2c_process set FPGAI2C_REG_DATA(0x%x)\n",FPGAI2C_REG_DATA);
|
||||
|
||||
if(( i2c->msg == NULL) || ( i2c->msg->buf == NULL) || (i2c->pos >= i2c->msg->len) ) {
|
||||
printk("crash debug..3 fpgai2c_process MSG and MAS->BUFF is NULL or pos > len ");
|
||||
return;
|
||||
}
|
||||
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, msg->buf[i2c->pos++]);
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE);
|
||||
}
|
||||
@ -745,7 +701,7 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c)
|
||||
{
|
||||
int prescale;
|
||||
int diff;
|
||||
u8 ctrl;
|
||||
u8 ctrl = 0, stat, loop = 0;
|
||||
|
||||
if (i2c->reg_io_width == 0)
|
||||
i2c->reg_io_width = 1; /* Set to default value */
|
||||
@ -776,8 +732,6 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c)
|
||||
}
|
||||
}
|
||||
|
||||
ctrl = fpgai2c_reg_get(i2c, FPGAI2C_REG_CONTROL);
|
||||
|
||||
PRINT("%s(), line:%d\n", __func__, __LINE__);
|
||||
PRINT("i2c->base = 0x%p\n",i2c->base);
|
||||
|
||||
@ -806,12 +760,23 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c)
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_PREHIGH, prescale >> 8);
|
||||
|
||||
/* Init the device */
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK);
|
||||
if (!use_irq)
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_EN);
|
||||
else
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_IEN | FPGAI2C_REG_CTRL_EN);
|
||||
|
||||
if (use_irq) {
|
||||
/* Clear any pending interrupts */
|
||||
fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK);
|
||||
while (loop < MAX_WAIT_LOOP) {
|
||||
stat = fpgai2c_reg_get(i2c, FPGAI2C_REG_STATUS);
|
||||
if (stat & FPGAI2C_REG_STAT_IF) {
|
||||
udelay(100);
|
||||
loop++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loop >=10) {
|
||||
printk("interrupts can't be cleared: loop %d\n", loop);
|
||||
}
|
||||
}
|
||||
fpgai2c_dump(i2c);
|
||||
|
||||
/* Initialize interrupt handlers if not already done */
|
||||
@ -820,6 +785,17 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpgai2c_interrupt_enable(struct fpgapci_dev *fpgapci)
|
||||
{
|
||||
int i;
|
||||
u8 ctrl = 0;
|
||||
|
||||
/* Enable Interrupts */
|
||||
for (i = 0 ; i < total_i2c_pci_bus; i ++) {
|
||||
fpgai2c_reg_set(&fpgalogic_i2c[i], FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_IEN | FPGAI2C_REG_CTRL_EN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 fpgai2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
@ -861,56 +837,17 @@ static int i2c_init_internal_data(void)
|
||||
}
|
||||
|
||||
|
||||
static int i2c_pci_init (void)
|
||||
static int i2c_pci_init (struct fpgapci_dev *fpgapci)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (num_bus == 0) {
|
||||
board_rev_type = ioread32(fpga_ctl_addr + MB_BRD_REV_TYPE);
|
||||
|
||||
if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) {
|
||||
num_bus = I2C_PCI_MAX_BUS_REV00;
|
||||
} else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) ||
|
||||
((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) ||
|
||||
((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) {
|
||||
switch (board_rev_type & MB_BRD_TYPE_MASK){
|
||||
case BRD_TYPE_S5212_NON_NEBS:
|
||||
case BRD_TYPE_S5212_NEBS:
|
||||
num_bus = I2C_PCI_BUS_NUM_5;
|
||||
break;
|
||||
case BRD_TYPE_S5224_NON_NEBS:
|
||||
case BRD_TYPE_S5224_NEBS:
|
||||
num_bus = I2C_PCI_BUS_NUM_7;
|
||||
break;
|
||||
case BRD_TYPE_Z9232_NON_NEBS:
|
||||
case BRD_TYPE_Z9232_NEBS:
|
||||
case BRD_TYPE_S5232_NON_NEBS:
|
||||
case BRD_TYPE_S5232_NEBS:
|
||||
num_bus = I2C_PCI_BUS_NUM_8;
|
||||
break;
|
||||
case BRD_TYPE_S5248_NON_NEBS:
|
||||
case BRD_TYPE_S5248_NEBS:
|
||||
if ((fpgapci != NULL) && (fpgapci->pci_dev->vendor == PCI_VENDOR_ID_ALTERA)) {
|
||||
num_bus = I2C_PCI_BUS_NUM_10;
|
||||
break;
|
||||
case BRD_TYPE_Z9264_NON_NEBS:
|
||||
case BRD_TYPE_Z9264_NEBS:
|
||||
num_bus = I2C_PCI_BUS_NUM_12;
|
||||
break;
|
||||
case BRD_TYPE_S5296_NON_NEBS:
|
||||
case BRD_TYPE_S5296_NEBS:
|
||||
num_bus = I2C_PCI_BUS_NUM_16;
|
||||
break;
|
||||
default:
|
||||
num_bus = I2C_PCI_BUS_NUM_16;
|
||||
printk("Wrong BRD_TYPE: 0x%x\n", board_rev_type);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printk("Wrong board_rev_type 0x%x\n", board_rev_type);
|
||||
}
|
||||
num_bus = I2C_PCI_MAX_BUS;
|
||||
}
|
||||
|
||||
printk("board_rev_type 0x%x, num_bus 0x%x\n", board_rev_type, num_bus);
|
||||
printk("vendor 0x%x, num_bus 0x%x\n", fpgapci->pci_dev->vendor, num_bus);
|
||||
total_i2c_pci_bus = num_bus;
|
||||
|
||||
memset (&i2c_pci_adap, 0, sizeof(i2c_pci_adap));
|
||||
@ -1100,84 +1037,8 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id)
|
||||
PRINT ( ": fpgapci_dev is 0\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) {
|
||||
/* Request interrupt line for unique function
|
||||
* alternatively function will be called from free_irq as well
|
||||
* with flag IRQF_SHARED */
|
||||
switch(irq_num_id) {
|
||||
/* Currently we only support test vector 2 for FPGA Logic I2C channel
|
||||
* controller 1-7 interrupt*/
|
||||
case FPGA_MSI_VECTOR_ID_4:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, dev);
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_5:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, dev);
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_8:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[0]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_9:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[1]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_10:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[2]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_11:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[3]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_12:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[4]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_13:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[5]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_14:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[6]);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT("No more interrupt handler for number (%d)\n",
|
||||
dev->irq + irq_num_id);
|
||||
break;
|
||||
}
|
||||
} else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) ||
|
||||
((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) ||
|
||||
((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) {
|
||||
/* FPGA SPEC 4.3.1.34, First i2c channel mapped to vector 8 */
|
||||
switch (irq_num_id) {
|
||||
case FPGA_MSI_VECTOR_ID_4:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, dev);
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_5:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, dev);
|
||||
PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id);
|
||||
fpgapci->irq_assigned++;
|
||||
break;
|
||||
case FPGA_MSI_VECTOR_ID_8:
|
||||
err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME,
|
||||
FPGA_PCI_NAME, &fpgalogic_i2c[0]);
|
||||
@ -1289,7 +1150,6 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id)
|
||||
dev->irq + irq_num_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1415,7 +1275,7 @@ static int fpgapci_setup_device(struct fpgapci_dev *fpgapci,struct pci_dev *dev)
|
||||
goto fail_map_bars;
|
||||
}
|
||||
|
||||
i2c_pci_init();
|
||||
i2c_pci_init(fpgapci);
|
||||
|
||||
return 0;
|
||||
/* ERROR HANDLING */
|
||||
@ -1491,7 +1351,6 @@ error_no_msi:
|
||||
static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
struct fpgapci_dev *fpgapci = 0;
|
||||
int status = 0;
|
||||
|
||||
#ifdef TEST
|
||||
PRINT ( " vendor = 0x%x, device = 0x%x, class = 0x%x, bus:slot.func = %02x:%02x.%02x\n",
|
||||
@ -1508,11 +1367,6 @@ static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
fpgapci->pci_dev = dev;
|
||||
dev_set_drvdata(&dev->dev, (void*)fpgapci);
|
||||
|
||||
status = sysfs_create_group(&dev->dev.kobj, &port_attr_grp);
|
||||
if (status) {
|
||||
printk(KERN_INFO "%s:Cannot create sysfs\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
fpgapci->upstream = find_upstream_dev (dev);
|
||||
|
||||
if(fpgapci_setup_device(fpgapci,dev)) {
|
||||
@ -1523,6 +1377,9 @@ static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
if(fpgapci_configure_msi(fpgapci,dev)) {
|
||||
goto error_cannot_configure;
|
||||
}
|
||||
/* Enable interrupt after config msi */
|
||||
fpgai2c_interrupt_enable(fpgapci);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1581,6 +1438,7 @@ static void fpgapci_remove(struct pci_dev *dev)
|
||||
|
||||
static const struct pci_device_id fpgapci_ids[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_XILINX, DEVICE)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_ALTERA)},
|
||||
{0, },
|
||||
};
|
||||
|
||||
@ -1624,3 +1482,4 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("joyce_yu@dell.com");
|
||||
MODULE_DESCRIPTION ("Driver for FPGA Logic I2C bus");
|
||||
MODULE_SUPPORTED_DEVICE ("FPGA Logic I2C bus");
|
||||
MODULE_VERSION ("01.01");
|
||||
|
1
platform/broadcom/sonic-platform-modules-dell/s5296f/setup.py
Symbolic link
1
platform/broadcom/sonic-platform-modules-dell/s5296f/setup.py
Symbolic link
@ -0,0 +1 @@
|
||||
../s6100/setup.py
|
@ -0,0 +1,3 @@
|
||||
__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan","fan_drawer","watchdog"]
|
||||
from sonic_platform import *
|
||||
|
@ -0,0 +1,453 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DELLEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from sonic_platform.sfp import Sfp
|
||||
from sonic_platform.eeprom import Eeprom
|
||||
from sonic_platform.component import Component
|
||||
from sonic_platform.psu import Psu
|
||||
from sonic_platform.thermal import Thermal
|
||||
from sonic_platform.watchdog import Watchdog
|
||||
from sonic_platform.fan_drawer import FanDrawer
|
||||
from sonic_platform.hwaccess import pci_get_value, pci_set_value
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
MAX_S5296F_COMPONENT = 8 # BIOS,BMC,FPGA,SYSTEM CPLD,4 SECONDARY CPLDs
|
||||
MAX_S5296F_FANTRAY = 4
|
||||
MAX_S5296F_FAN = 1
|
||||
MAX_S5296F_PSU = 2
|
||||
MAX_S5296F_THERMAL = 10
|
||||
SYSTEM_LED_REG = 0x24
|
||||
SYSTEM_BEACON_LED_SET = 0x8
|
||||
SYSTEM_BEACON_LED_CLEAR = 0xFFFFFFF7
|
||||
|
||||
media_part_num_list = set([ \
|
||||
"8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC",
|
||||
"C5RNH","5250G","N8TDR","7D64H","7D64H","RN84N","RN84N","HMTNW","6K3Y6","6K3Y6","TY5FM","50M0R","PGYJT","WP2PP","85Y13","1HCGH","FP9R1","FYD0M","C6Y7M","C6Y7M","V250M","V250M",
|
||||
"5CWK6","5CWK6","53HVN","53HVN","358VV","358VV","MV799","MV799","YJF03","P9GND","T1KCN","1DXKP","MT7R2","K0T7R","W5G04","7TCDN","7TCDN","7TCDN","7TCDN","7TCDN","V3XJK","0MV31",
|
||||
"5FVP7","N6KM9","C41MF","77KC3","XW7J0","V4NJV","2XJHY","H93DH","H93DH","F8CG0","F8CG0","F8CG0","119N6","WFMF5","794RX","288F6","1M31V","1M31V","5NP8R","5NP8R","4TC09","4TC09",
|
||||
"FC6KV","FC6KV","J90VN","J90VN","05RH0","05RH0","YDN52","0C2YV","YDN52","0C2YV","9JT65","D7M6H","6GW14","FYVFW","0VF5H","P4YPY","P4YPY","TCPM2","TCPM2","JNPF8","JNPF8","27GG5",
|
||||
"27GG5","P8T4W","P8T4W","JR54Y","M6N0J","XJYD0","K44H9","035KG","P7C7N","76V43","3CC35","FN4FC","26FN3","YFNDD","YFNDD","7R9N9","035KG","P7C7N","76V43","3CC35","PLRXPLSCS43811",
|
||||
"FN4FC","26FN3","YFNDD","YFNDD","7R9N9","G86YJ","V407F","V407F","9KH6T","G86YJ","V407F","9KH6T","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY",
|
||||
"9X8JP","GMFC5","GMFC5","GMFC5","D7P80","3MFXG","3MFXG","0GWXJ","THPF3","THPF3","THPF3","THPF3","THPF3","PJ62G","3XCX1","JJYKG","RRRTK","16K56","86JM2","K5R6C","7MG2C","WTPPN","9HTT2",
|
||||
"NKM4F","VXGGG","JC9W6","6MR8M","RP3GV","M5PPJ","XKY55","TKCXT","05J8P","5WGKD","XFDRT","NW8DM","YPKH3","5WGKD","XFDRT","NW8DM","YPKH3","71XXK","MVCX6","0XYP6","HPPVW","3GHRT","71XXK",
|
||||
"MVCX6","0XYP6","HPPVW","3GHRT","2X5T6","135V2","KD5MV","2X5T6","KD5MV","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","3YWG7","5CMT2","RCVP5","X5DH4",
|
||||
"4WJ41","4WJ41","14NV5","14NV5","14NV5","4WGYD","YKMH7","X7CCC","X7CCC","0X9CT","0CY8V","P7D7R","W4GPP","W4GPP","W4GPP","HHHCHC","07RN7","07RN7","0YR96","0YR96","JCYM9","FTLX8571D3BCL",
|
||||
"DDW0X","VPFDJ","229KM","9FC7D","DDW0X","VPFDJ","6FMR5","J7K20","N3K9W","6FMR5","8R4VM","7VN5T","D9YM8","8R4VM","VYXPW","87TPX","WY6FK","VYXPW","87TPX","WY6FK","WG8C4","N8K82","2DV6Y",
|
||||
"77C3C","RC0HM","77C3C","RC0HM","JHXTN","3P3PG","92YVM","4VX5M","4VX5M","6RRGD","W4JWV","22V6R","XR11M","9GMDY","JMCWK","TP2F0","6MGDY","78RHK", "C0TP5","0WDNV","FCLF8522P2BTL"\
|
||||
])
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
"""
|
||||
DELLEMC Platform-specific Chassis class
|
||||
"""
|
||||
|
||||
REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason"
|
||||
OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi"
|
||||
PCI_RES = "/sys/bus/pci/devices/0000:04:00.0/resource0"
|
||||
oir_fd = -1
|
||||
|
||||
sysled_offset = 0x0024
|
||||
SYSLED_COLOR_TO_REG = {
|
||||
"blinking_green": 0x0,
|
||||
"green" : 0x10,
|
||||
"amber" : 0x20,
|
||||
"blinking_amber": 0x30
|
||||
}
|
||||
|
||||
REG_TO_SYSLED_COLOR = {
|
||||
0x0 : "blinking_green",
|
||||
0x10 : "green",
|
||||
0x20 : "amber",
|
||||
0x30 : "blinking_amber"
|
||||
}
|
||||
|
||||
_global_port_pres_dict = {}
|
||||
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
# sfp.py will read eeprom contents and retrive the eeprom data.
|
||||
# We pass the eeprom path from chassis.py
|
||||
self.PORT_START = 1
|
||||
self.PORT_END = 104
|
||||
self.SFP28_PORT_END = 96
|
||||
i2c_bus_for_port = 2
|
||||
i2c_mux_to_populate = 603
|
||||
i2c_mux_is_good = False
|
||||
|
||||
PORTS_IN_BLOCK = (self.PORT_END + 1)
|
||||
_sfp_port = range(1, self.SFP28_PORT_END + 1)
|
||||
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
|
||||
mux_channel = "/sys/class/i2c-adapter/i2c-{0}/{0}-0074/channel-0"
|
||||
|
||||
for index in range(self.PORT_START, PORTS_IN_BLOCK):
|
||||
eeprom_path = ""
|
||||
if index%8 == 1: # 8 buses per i2c mux
|
||||
i2c_mux_is_good = True if os.path.exists(mux_channel.format(i2c_mux_to_populate)) else False
|
||||
i2c_mux_to_populate += 1
|
||||
if i2c_mux_is_good:
|
||||
eeprom_path = eeprom_base.format(i2c_bus_for_port)
|
||||
i2c_bus_for_port += 1
|
||||
if index not in _sfp_port:
|
||||
sfp_node = Sfp(index, 'QSFP', eeprom_path)
|
||||
else:
|
||||
sfp_node = Sfp(index, 'SFP', eeprom_path)
|
||||
self._sfp_list.append(sfp_node)
|
||||
self._num_sfps = len(self._sfp_list)
|
||||
|
||||
self._eeprom = Eeprom()
|
||||
|
||||
for i in range(MAX_S5296F_THERMAL):
|
||||
self._thermal_list.append(Thermal(i))
|
||||
|
||||
for i in range(MAX_S5296F_COMPONENT):
|
||||
self._component_list.append(Component(i))
|
||||
|
||||
for i in range(MAX_S5296F_PSU):
|
||||
self._psu_list.append(Psu(i))
|
||||
|
||||
for i in range(MAX_S5296F_FANTRAY):
|
||||
fandrawer = FanDrawer(i)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
self._num_fans = MAX_S5296F_FANTRAY * MAX_S5296F_FAN
|
||||
|
||||
self._watchdog = Watchdog()
|
||||
|
||||
def __del__(self):
|
||||
if self.oir_fd != -1:
|
||||
self.epoll.unregister(self.oir_fd.fileno())
|
||||
self.epoll.close()
|
||||
self.oir_fd.close()
|
||||
|
||||
# not needed /delete after validation
|
||||
|
||||
def _get_register(self, reg_file):
|
||||
retval = 'ERR'
|
||||
if (not os.path.isfile(reg_file)):
|
||||
print(reg_file, 'not found !')
|
||||
return retval
|
||||
|
||||
try:
|
||||
with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd:
|
||||
retval = fd.read()
|
||||
except Exception as ex:
|
||||
pass
|
||||
retval = retval.rstrip('\r\n')
|
||||
retval = retval.lstrip(" ")
|
||||
return retval
|
||||
|
||||
# not needed /delete after validation
|
||||
|
||||
def _check_interrupts(self, port_dict):
|
||||
retval = 0
|
||||
is_port_dict_updated = False
|
||||
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
|
||||
sfp = self.get_sfp(port_num)
|
||||
presence = sfp.get_presence()
|
||||
if(presence and (self._global_port_pres_dict[port_num] == '0')):
|
||||
is_port_dict_updated = True
|
||||
self._global_port_pres_dict[port_num] = '1'
|
||||
port_dict[port_num] = '1'
|
||||
elif(not presence and (self._global_port_pres_dict[port_num] == '1')):
|
||||
is_port_dict_updated = True
|
||||
self._global_port_pres_dict[port_num] = '0'
|
||||
port_dict[port_num] = '0'
|
||||
return retval, is_port_dict_updated
|
||||
|
||||
# check for this event change for sfp / do we need to handle timeout/sleep
|
||||
|
||||
def get_change_event(self, timeout=0):
|
||||
"""
|
||||
Returns a nested dictionary containing all devices which have
|
||||
experienced a change at chassis level
|
||||
"""
|
||||
start_ms = time.time() * 1000
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
if not self._global_port_pres_dict:
|
||||
for port_num in self._sfp_port:
|
||||
presence = self.get_sfp(port_num).get_presence()
|
||||
self._global_port_pres_dict[port_num] = '1' if presence else '0'
|
||||
|
||||
while True:
|
||||
time.sleep(0.5)
|
||||
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
|
||||
presence = self.get_sfp(port_num).get_presence()
|
||||
if(presence and self._global_port_pres_dict[port_num] == '0'):
|
||||
self._global_port_pres_dict[port_num] = '1'
|
||||
port_dict[port_num] = '1'
|
||||
elif(not presence and
|
||||
self._global_port_pres_dict[port_num] == '1'):
|
||||
self._global_port_pres_dict[port_num] = '0'
|
||||
port_dict[port_num] = '0'
|
||||
|
||||
if(len(port_dict) > 0):
|
||||
return True, change_dict
|
||||
|
||||
if timeout:
|
||||
now_ms = time.time() * 1000
|
||||
if (now_ms - start_ms >= timeout):
|
||||
return True, change_dict
|
||||
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
Retrieves sfp represented by (0-based) index <index>
|
||||
|
||||
Args:
|
||||
index: An integer, the index (0-based) of the sfp to retrieve.
|
||||
The index should be the sequence of a physical port in a chassis,
|
||||
starting from 0.
|
||||
For example, 0 for Ethernet0, 1 for Ethernet4 and so on.
|
||||
|
||||
Returns:
|
||||
An object dervied from SfpBase representing the specified sfp
|
||||
"""
|
||||
sfp = None
|
||||
|
||||
try:
|
||||
# The 'index' is 1-based
|
||||
sfp = self._sfp_list[index-1]
|
||||
except IndexError:
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the chassis
|
||||
Returns:
|
||||
string: The name of the chassis
|
||||
"""
|
||||
return self._eeprom.modelstr()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the chassis
|
||||
Returns:
|
||||
bool: True if chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the chassis
|
||||
Returns:
|
||||
string: Model/part number of chassis
|
||||
"""
|
||||
return self._eeprom.part_number_str()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the chassis (Service tag)
|
||||
Returns:
|
||||
string: Serial number of chassis
|
||||
"""
|
||||
return self._eeprom.serial_str()
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the chassis
|
||||
Returns:
|
||||
bool: A boolean value, True if chassis is operating properly
|
||||
False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the system LED
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
system LED
|
||||
Returns:
|
||||
bool: True if system LED state is set successfully, False if not
|
||||
"""
|
||||
if color not in list(self.SYSLED_COLOR_TO_REG.keys()):
|
||||
return False
|
||||
|
||||
val = pci_get_value(self.PCI_RES, self.sysled_offset)
|
||||
val = (val & 0xFFCF) | self.SYSLED_COLOR_TO_REG[color]
|
||||
|
||||
pci_set_value(self.PCI_RES, val, self.sysled_offset)
|
||||
self.sys_ledcolor = color
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
"""
|
||||
Gets the state of the system LED
|
||||
Returns:
|
||||
A string, one of the valid LED color strings which could be
|
||||
vendor specified.
|
||||
"""
|
||||
val = pci_get_value(self.PCI_RES, self.sysled_offset)
|
||||
if val != -1:
|
||||
val = val & 0x30
|
||||
return self.REG_TO_SYSLED_COLOR.get(val)
|
||||
return self.sys_ledcolor
|
||||
|
||||
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._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._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.
|
||||
"""
|
||||
return self._eeprom.system_eeprom_info()
|
||||
|
||||
def get_eeprom(self):
|
||||
"""
|
||||
Retrieves the Sys Eeprom instance for the chassis.
|
||||
Returns :
|
||||
The instance of the Sys Eeprom
|
||||
"""
|
||||
return self._eeprom
|
||||
|
||||
def get_num_fans(self):
|
||||
"""
|
||||
Retrives the number of Fans on the chassis.
|
||||
Returns :
|
||||
An integer represents the number of Fans on the chassis.
|
||||
"""
|
||||
return self._num_fans
|
||||
|
||||
def get_num_sfps(self):
|
||||
"""
|
||||
Retrives the numnber of Media on the chassis.
|
||||
Returns:
|
||||
An integer represences the number of SFPs on the chassis.
|
||||
"""
|
||||
return self._num_sfps
|
||||
|
||||
def get_revision(self):
|
||||
"""
|
||||
Retrieves the revision number of the chassis (Service tag)
|
||||
Returns:
|
||||
string: Revision number of chassis
|
||||
"""
|
||||
return self._eeprom.revision_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.
|
||||
"""
|
||||
try:
|
||||
with open(self.REBOOT_CAUSE_PATH) as fd:
|
||||
reboot_cause = int(fd.read(), 16)
|
||||
except Exception as ex:
|
||||
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
|
||||
|
||||
if reboot_cause & 0x1:
|
||||
return (self.REBOOT_CAUSE_POWER_LOSS, "Power on reset")
|
||||
elif reboot_cause & 0x2:
|
||||
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
|
||||
elif reboot_cause & 0x4:
|
||||
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown")
|
||||
elif reboot_cause & 0x8:
|
||||
return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None)
|
||||
elif reboot_cause & 0x10:
|
||||
return (self.REBOOT_CAUSE_WATCHDOG, None)
|
||||
elif reboot_cause & 0x20:
|
||||
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown")
|
||||
elif reboot_cause & 0x40:
|
||||
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown")
|
||||
elif reboot_cause & 0x80:
|
||||
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown")
|
||||
elif reboot_cause & 0x100:
|
||||
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot")
|
||||
else:
|
||||
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
|
||||
|
||||
def get_qualified_media_list(self):
|
||||
return media_part_num_list
|
||||
|
||||
def set_locator_led(self, color):
|
||||
"""
|
||||
Sets the state of the Chassis Locator LED
|
||||
|
||||
Args:
|
||||
color: A string representing the color with which to set the Chassis Locator LED
|
||||
|
||||
Returns:
|
||||
bool: True if the Chassis Locator LED state is set successfully, False if not
|
||||
|
||||
"""
|
||||
val = pci_get_value(self.PCI_RES, SYSTEM_LED_REG)
|
||||
if self.LOCATOR_LED_ON == color:
|
||||
val = int(val) | SYSTEM_BEACON_LED_SET
|
||||
elif self.LOCATOR_LED_OFF == color:
|
||||
val = int(val) & SYSTEM_BEACON_LED_CLEAR
|
||||
else:
|
||||
return False
|
||||
pci_set_value(self.PCI_RES, val, SYSTEM_LED_REG)
|
||||
return True
|
||||
|
||||
def get_locator_led(self):
|
||||
"""
|
||||
Gets the state of the Chassis Locator LED
|
||||
|
||||
Returns:
|
||||
LOCATOR_LED_ON or LOCATOR_LED_OFF
|
||||
"""
|
||||
val = pci_get_value(self.PCI_RES, SYSTEM_LED_REG)
|
||||
val = int(val) & SYSTEM_BEACON_LED_SET
|
||||
if not val:
|
||||
return self.LOCATOR_LED_OFF
|
||||
else:
|
||||
return self.LOCATOR_LED_ON
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return -1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether Chassis is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return False
|
@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DELLEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Components' (e.g., BIOS, CPLD, FPGA, BMC etc.) available in
|
||||
# the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
import sonic_platform.hwaccess as hwaccess
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
def get_bios_version():
|
||||
return subprocess.check_output(['dmidecode', '-s',
|
||||
'system-version']).decode('utf-8').strip()
|
||||
|
||||
def get_fpga_version():
|
||||
val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:04:00.0/resource0', 0)
|
||||
return '{}.{}'.format((val >> 8) & 0xff, val & 0xff)
|
||||
|
||||
def get_bmc_version():
|
||||
""" Returns BMC Version """
|
||||
bmc_ver = ''
|
||||
try:
|
||||
bmc_ver = subprocess.check_output(
|
||||
"ipmitool mc info | awk '/Firmware Revision/ { print $NF }'",
|
||||
shell=True, text=True).strip()
|
||||
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||
pass
|
||||
return bmc_ver
|
||||
|
||||
def get_cpld_version(bus, i2caddr):
|
||||
""" Return CPLD version """
|
||||
major = hwaccess.i2c_get(bus, i2caddr, 1)
|
||||
minor = hwaccess.i2c_get(bus, i2caddr, 0)
|
||||
if major != -1 and minor != -1:
|
||||
return '{}.{}'.format(major, minor)
|
||||
return ''
|
||||
|
||||
def get_cpld0_version():
|
||||
return get_cpld_version(601, 0x31)
|
||||
|
||||
def get_cpld1_version():
|
||||
return get_cpld_version(600, 0x30)
|
||||
|
||||
def get_cpld2_version():
|
||||
return get_cpld_version(600, 0x31)
|
||||
|
||||
def get_cpld3_version():
|
||||
return get_cpld_version(600, 0x32)
|
||||
|
||||
def get_cpld4_version():
|
||||
return get_cpld_version(600, 0x33)
|
||||
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""DellEMC Platform-specific Component class"""
|
||||
|
||||
CHASSIS_COMPONENTS = [
|
||||
['BIOS',
|
||||
'Performs initialization of hardware components during booting',
|
||||
get_bios_version
|
||||
],
|
||||
|
||||
['FPGA',
|
||||
'Used for managing the system LEDs',
|
||||
get_fpga_version
|
||||
],
|
||||
|
||||
['BMC',
|
||||
'Platform management controller for on-board temperature monitoring, in-chassis power, Fan and LED control',
|
||||
get_bmc_version
|
||||
],
|
||||
|
||||
['System CPLD',
|
||||
'Used for managing the CPU power sequence and CPU states',
|
||||
get_cpld0_version
|
||||
],
|
||||
|
||||
['Secondary CPLD 1',
|
||||
'Used for managing SFP28/QSFP28 port transceivers (SFP28 1-24, QSFP28 1-4)',
|
||||
get_cpld1_version
|
||||
],
|
||||
|
||||
['Secondary CPLD 2',
|
||||
'Used for managing SFP28/QSFP28 port transceivers (SFP28 25-48, QSFP28 5-8)',
|
||||
get_cpld2_version
|
||||
],
|
||||
|
||||
['Secondary CPLD 3',
|
||||
'Used for managing SFP28/QSFP28 port transceivers (SFP28 49-72)',
|
||||
get_cpld3_version
|
||||
],
|
||||
|
||||
['Secondary CPLD 4',
|
||||
'Used for managing SFP28/QSFP28 port transceivers (SFP28 73-96)',
|
||||
get_cpld4_version
|
||||
]
|
||||
]
|
||||
|
||||
def __init__(self, component_index = 0):
|
||||
self.index = component_index
|
||||
self.name = self.CHASSIS_COMPONENTS[self.index][0]
|
||||
self.description = self.CHASSIS_COMPONENTS[self.index][1]
|
||||
self.version = self.CHASSIS_COMPONENTS[self.index][2]()
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the component
|
||||
Returns:
|
||||
A string containing the name of the component
|
||||
"""
|
||||
return self.name
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Retrieves the description of the component
|
||||
Returns:
|
||||
A string containing the description of the component
|
||||
"""
|
||||
return self.description
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""
|
||||
Retrieves the firmware version of the component
|
||||
Returns:
|
||||
A string containing the firmware version of the component
|
||||
"""
|
||||
return self.version
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the component
|
||||
Returns:
|
||||
bool: True if present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the component
|
||||
Returns:
|
||||
string: Part number of component
|
||||
"""
|
||||
return 'NA'
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the component
|
||||
Returns:
|
||||
string: Serial number of component
|
||||
"""
|
||||
return 'NA'
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the component
|
||||
Returns:
|
||||
bool: True if component is operating properly, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return -1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether component is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return False
|
||||
|
||||
def install_firmware(self, image_path):
|
||||
"""
|
||||
Installs firmware to the component
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A boolean, True if install was successful, False if not
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_available_firmware_version(self, image_path):
|
||||
"""
|
||||
Retrieves the available firmware version of the component
|
||||
Note: the firmware version will be read from image
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A string containing the available firmware version of the component
|
||||
"""
|
||||
return "N/A"
|
||||
|
||||
def get_firmware_update_notification(self, image_path):
|
||||
"""
|
||||
Retrieves a notification on what should be done in order to complete
|
||||
the component firmware update
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Returns:
|
||||
A string containing the component firmware update notification if required.
|
||||
By default 'None' value will be used, which indicates that no actions are required
|
||||
"""
|
||||
return "None"
|
||||
|
||||
def update_firmware(self, image_path):
|
||||
"""
|
||||
Updates firmware of the component
|
||||
This API performs firmware update: it assumes firmware installation and loading in a single call.
|
||||
In case platform component requires some extra steps (apart from calling Low Level Utility)
|
||||
to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API
|
||||
Args:
|
||||
image_path: A string, path to firmware image
|
||||
Raises:
|
||||
RuntimeError: update failed
|
||||
"""
|
||||
return False
|
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DellEmc S5296F
|
||||
#
|
||||
# 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:
|
||||
import os.path
|
||||
from sonic_eeprom import eeprom_tlvinfo
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
|
||||
def __init__(self):
|
||||
self.eeprom_path = None
|
||||
for b in (0, 1):
|
||||
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
|
||||
if os.path.exists(f):
|
||||
self.eeprom_path = f
|
||||
break
|
||||
if self.eeprom_path is None:
|
||||
return
|
||||
super(Eeprom, self).__init__(self.eeprom_path, 0, '', True)
|
||||
self.eeprom_tlv_dict = dict()
|
||||
try:
|
||||
self.eeprom_data = self.read_eeprom()
|
||||
except:
|
||||
self.eeprom_data = "N/A"
|
||||
raise RuntimeError("Eeprom is not Programmed")
|
||||
else:
|
||||
eeprom = self.eeprom_data
|
||||
|
||||
if not self.is_valid_tlvinfo_header(eeprom):
|
||||
return
|
||||
|
||||
total_length = (eeprom[9] << 8) | eeprom[10]
|
||||
tlv_index = self._TLV_INFO_HDR_LEN
|
||||
tlv_end = self._TLV_INFO_HDR_LEN + total_length
|
||||
|
||||
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
|
||||
if not self.is_valid_tlv(eeprom[tlv_index:]):
|
||||
break
|
||||
|
||||
tlv = eeprom[tlv_index:tlv_index + 2
|
||||
+ eeprom[tlv_index + 1]]
|
||||
code = "0x%02X" % tlv[0]
|
||||
name, value = self.decoder(None, tlv)
|
||||
|
||||
self.eeprom_tlv_dict[code] = value
|
||||
if eeprom[tlv_index] == self._TLV_CODE_CRC_32:
|
||||
break
|
||||
|
||||
tlv_index += eeprom[tlv_index+1] + 2
|
||||
|
||||
def serial_number_str(self):
|
||||
"""
|
||||
Returns the serial number
|
||||
"""
|
||||
(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].decode('ascii')
|
||||
|
||||
def base_mac_addr(self):
|
||||
"""
|
||||
Returns the base mac address found in the system EEPROM
|
||||
"""
|
||||
(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(["{:02x}".format(T) for T in t[2]]).upper()
|
||||
|
||||
def modelstr(self):
|
||||
"""
|
||||
Returns the Model name
|
||||
"""
|
||||
(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].decode('ascii')
|
||||
|
||||
def part_number_str(self):
|
||||
"""
|
||||
Returns the part number
|
||||
"""
|
||||
(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].decode('ascii')
|
||||
|
||||
def serial_str(self):
|
||||
"""
|
||||
Returns the servicetag number
|
||||
"""
|
||||
(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].decode('ascii')
|
||||
|
||||
def revision_str(self):
|
||||
"""
|
||||
Returns the device revision
|
||||
"""
|
||||
(is_valid, results) = self.get_tlv_field(
|
||||
self.eeprom_data, self._TLV_CODE_LABEL_REVISION)
|
||||
if not is_valid:
|
||||
return "N/A"
|
||||
|
||||
return results[2].decode('ascii')
|
||||
|
||||
def system_eeprom_info(self):
|
||||
"""
|
||||
Returns a dictionary, where keys are the type code defined in
|
||||
ONIE EEPROM format and values are their corresponding values
|
||||
found in the system EEPROM.
|
||||
"""
|
||||
return self.eeprom_tlv_dict
|
@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Fans' information which are available in the platform.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
from sonic_platform.ipmihelper import IpmiSensor, IpmiFru
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
FAN1_MAX_SPEED_OFFSET = 71
|
||||
PSU_FAN_MAX_SPEED_OFFSET = 50
|
||||
FAN_DIRECTION_OFFSET = 69
|
||||
PSU_FAN_DIRECTION_OFFSET = 47
|
||||
|
||||
|
||||
class Fan(FanBase):
|
||||
"""DellEMC Platform-specific Fan class"""
|
||||
# { FAN-ID: { Sensor-Name: Sensor-ID } }
|
||||
FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x53, "State": 0x5b, "Speed": 0x20},
|
||||
2: {"Prsnt": 0x54, "State": 0x5c, "Speed": 0x21},
|
||||
3: {"Prsnt": 0x55, "State": 0x5d, "Speed": 0x22},
|
||||
4: {"Prsnt": 0x56, "State": 0x5e, "Speed": 0x23}
|
||||
}
|
||||
PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x28},
|
||||
2: {"State": 0x32, "Speed": 0x29} }
|
||||
|
||||
# { FANTRAY-ID: FRU-ID }
|
||||
FAN_FRU_MAPPING = { 1: 3, 2: 4, 3: 5, 4: 6 }
|
||||
PSU_FRU_MAPPING = { 1: 1, 2: 2 }
|
||||
|
||||
def __init__(self, fantray_index=1, fan_index=1, psu_fan=False,
|
||||
dependency=None):
|
||||
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.max_speed_offset = FAN1_MAX_SPEED_OFFSET
|
||||
self.fan_direction_offset = FAN_DIRECTION_OFFSET
|
||||
self.index = self.fantrayindex
|
||||
self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"],
|
||||
is_discrete = True)
|
||||
self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"],
|
||||
is_discrete = True)
|
||||
self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"])
|
||||
self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex])
|
||||
else:
|
||||
self.dependency = dependency
|
||||
self.fanindex = fan_index
|
||||
self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"],
|
||||
is_discrete = True)
|
||||
self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"])
|
||||
self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex])
|
||||
self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET
|
||||
self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET
|
||||
self.max_speed = 0
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
String: The name of the device
|
||||
"""
|
||||
if self.is_psu_fan:
|
||||
return "PSU{} Fan".format(self.fanindex)
|
||||
else:
|
||||
return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex)
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the FAN
|
||||
Returns:
|
||||
String: Part number of FAN
|
||||
"""
|
||||
return self.fru.get_board_part_number()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the FAN
|
||||
Returns:
|
||||
String: Serial number of FAN
|
||||
"""
|
||||
return self.fru.get_board_serial()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the FAN
|
||||
Returns:
|
||||
bool: True if fan is present, False if not
|
||||
"""
|
||||
presence = False
|
||||
if self.is_psu_fan:
|
||||
return self.dependency.get_presence()
|
||||
else:
|
||||
is_valid, state = self.prsnt_sensor.get_reading()
|
||||
if is_valid:
|
||||
if (state & 0b1):
|
||||
presence = True
|
||||
return presence
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the FAN
|
||||
Returns:
|
||||
bool: True if FAN is operating properly, False if not
|
||||
"""
|
||||
status = False
|
||||
is_valid, state = self.state_sensor.get_reading()
|
||||
if is_valid:
|
||||
if not state > 1:
|
||||
status = True
|
||||
return status
|
||||
|
||||
def get_direction(self):
|
||||
"""
|
||||
Retrieves the fan airfow direction
|
||||
Returns:
|
||||
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||
depending on fan direction
|
||||
|
||||
Notes:
|
||||
In DellEMC platforms,
|
||||
- Forward/Exhaust : Air flows from Port side to Fan side.
|
||||
- Reverse/Intake : Air flows from Fan side to Port side.
|
||||
"""
|
||||
direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE]
|
||||
fan_status = self.get_presence()
|
||||
if not fan_status:
|
||||
return None
|
||||
is_valid, fan_direction = self.fru.get_fru_data(self.fan_direction_offset)
|
||||
if is_valid and fan_direction[0] < len(direction):
|
||||
return direction[fan_direction[0]]
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_speed_rpm(self):
|
||||
"""
|
||||
Retrieves the speed of fan in revolutions per minute (RPM)
|
||||
|
||||
Returns:
|
||||
An integer, speed of the fan in RPM
|
||||
"""
|
||||
is_valid, fan_speed = self.speed_sensor.get_reading()
|
||||
return fan_speed if is_valid else None
|
||||
|
||||
def get_speed(self):
|
||||
"""
|
||||
Retrieves the speed of the fan
|
||||
Returns:
|
||||
int: percentage of the max fan speed
|
||||
"""
|
||||
rpm = self.get_speed_rpm()
|
||||
if rpm is None:
|
||||
return None
|
||||
if self.max_speed == 0:
|
||||
is_valid, resp = self.fru.get_fru_data(self.max_speed_offset, 2)
|
||||
if is_valid:
|
||||
self.max_speed = (resp[1] << 8) | resp[0]
|
||||
if self.max_speed == 0:
|
||||
return None
|
||||
return (100 * rpm) // self.max_speed
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.fanindex
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether Fan is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return False
|
||||
|
||||
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 platforms
|
||||
tolerance = 20
|
||||
else:
|
||||
tolerance = 0
|
||||
|
||||
return tolerance
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Set led to expected color
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
fan status LED
|
||||
Returns:
|
||||
bool: True if set success, False if fail.
|
||||
"""
|
||||
# Fan tray status LED controlled by HW
|
||||
# Return True to avoid thermalctld alarm
|
||||
return True
|
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Fan-Drawers' information available in the platform.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_drawer_base import FanDrawerBase
|
||||
from sonic_platform.fan import Fan
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
S5296F_FANS_PER_FANTRAY = 1
|
||||
|
||||
|
||||
class FanDrawer(FanDrawerBase):
|
||||
"""DellEMC Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index):
|
||||
|
||||
FanDrawerBase.__init__(self)
|
||||
# FanTray is 1-based in DellEMC platforms
|
||||
self.fantrayindex = fantray_index + 1
|
||||
for i in range(S5296F_FANS_PER_FANTRAY):
|
||||
self._fan_list.append(Fan(fantray_index, i))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the fan drawer name
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "FanTray{}".format(self.fantrayindex)
|
||||
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrives the presence of the fan drawer
|
||||
Returns:
|
||||
bool: True if fan_tray is present, False if not
|
||||
"""
|
||||
return self.get_fan(0).get_presence()
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the fan drawer
|
||||
Returns:
|
||||
string: Part number of fan drawer
|
||||
"""
|
||||
return "NA"
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the fan drawer
|
||||
Returns:
|
||||
string: Serial number of the fan drawer
|
||||
"""
|
||||
return "NA"
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the fan drawer
|
||||
Returns:
|
||||
bool: True if fan drawer is operating properly, False if not
|
||||
"""
|
||||
return self.get_fan(0).get_status()
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.fantrayindex
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this fan drawer is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
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.
|
||||
"""
|
||||
# Fan tray status LED controlled by BMC
|
||||
# Return True to avoid thermalctld alarm
|
||||
return True
|
||||
|
||||
def get_maximum_consumed_power(self):
|
||||
"""
|
||||
Retrives the maximum power drawn by Fan Drawer
|
||||
Returns:
|
||||
A float, with value of the maximum consumable power of the
|
||||
component.
|
||||
"""
|
||||
# Value based on the hw spec
|
||||
return 54.0
|
@ -0,0 +1 @@
|
||||
../../common/sonic_platform/hwaccess.py
|
@ -0,0 +1,13 @@
|
||||
# Media settings key plugin
|
||||
#
|
||||
# Generate keys used for lookup in media_settings,json
|
||||
|
||||
def get_media_settings_key(physical_port, transceiver_dict):
|
||||
d = transceiver_dict[physical_port]
|
||||
media_interface = d['media_interface']
|
||||
generic_key = '{}-{}'.format(d['form_factor'], media_interface)
|
||||
if media_interface == 'CR':
|
||||
generic_key = '{}-{}'.format(generic_key, d['cable_length_detailed'])
|
||||
return ['{}-{}'.format(d['manufacturename'], d['modelname']),
|
||||
generic_key
|
||||
]
|
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.platform_base import PlatformBase
|
||||
from sonic_platform.chassis import Chassis
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Platform(PlatformBase):
|
||||
"""
|
||||
DELLEMC Platform-specific class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
PlatformBase.__init__(self)
|
||||
self._chassis = Chassis()
|
@ -0,0 +1,325 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs' information which are available in the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from sonic_platform.ipmihelper import IpmiSensor, IpmiFru
|
||||
from sonic_platform.fan import Fan
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""DellEMC Platform-specific PSU class"""
|
||||
|
||||
# { PSU-ID: { Sensor-Name: Sensor-ID } }
|
||||
SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39,
|
||||
"Power": 0x37, "Voltage": 0x38,
|
||||
"InCurrent": 0x36, "InPower": 0x34,
|
||||
"InVoltage": 0x35, "Temperature": 0xc },
|
||||
2: { "State": 0x32, "Current": 0x3F,
|
||||
"Power": 0x3D, "Voltage": 0x3E,
|
||||
"InCurrent": 0x3C, "InPower": 0x3A,
|
||||
"InVoltage": 0x3B, "Temperature": 0xd } }
|
||||
# ( PSU-ID: FRU-ID }
|
||||
FRU_MAPPING = { 1: 1, 2: 2 }
|
||||
|
||||
def __init__(self, psu_index):
|
||||
PsuBase.__init__(self)
|
||||
# PSU is 1-based in DellEMC platforms
|
||||
self.index = psu_index + 1
|
||||
self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"],
|
||||
is_discrete=True)
|
||||
self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"])
|
||||
self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"])
|
||||
self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"])
|
||||
self.input_voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InVoltage"])
|
||||
self.input_current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InCurrent"])
|
||||
self.input_power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InPower"])
|
||||
self.temp_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Temperature"])
|
||||
self.fru = IpmiFru(self.FRU_MAPPING[self.index])
|
||||
|
||||
self._fan_list.append(Fan(fan_index=self.index, psu_fan=True,
|
||||
dependency=self))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "PSU{}".format(self.index)
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Power Supply Unit (PSU)
|
||||
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
presence = False
|
||||
is_valid, state = self.state_sensor.get_reading()
|
||||
if is_valid:
|
||||
if (state & 0b1) == 1:
|
||||
presence = True
|
||||
|
||||
return presence
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from thermal
|
||||
Returns:
|
||||
A float number of current temperature in Celcius up to
|
||||
nearest thousandth of one degree celcius, e.g. 30.125
|
||||
"""
|
||||
is_valid, temperature = self.temp_sensor.get_reading()
|
||||
if not is_valid:
|
||||
temperature = 0
|
||||
return float(temperature)
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the PSU
|
||||
|
||||
Returns:
|
||||
string: Part number of PSU
|
||||
"""
|
||||
return self.fru.get_board_part_number()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the PSU
|
||||
|
||||
Returns:
|
||||
string: Serial number of PSU
|
||||
"""
|
||||
return self.fru.get_board_serial()
|
||||
|
||||
def get_revision(self):
|
||||
"""
|
||||
Retrives thehardware revision of the device
|
||||
Returns:
|
||||
String: revision value of device
|
||||
"""
|
||||
serial = self.fru.get_board_serial()
|
||||
if serial != "NA" and len(serial) == 23:
|
||||
return serial[-3:]
|
||||
else:
|
||||
return "NA"
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this PSU is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the PSU
|
||||
|
||||
Returns:
|
||||
bool: True if PSU is operating properly, False if not
|
||||
"""
|
||||
status = False
|
||||
is_valid, state = self.state_sensor.get_reading()
|
||||
if is_valid:
|
||||
if (state == 0x01):
|
||||
status = True
|
||||
|
||||
return status
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
is_valid, voltage = self.voltage_sensor.get_reading()
|
||||
if not is_valid:
|
||||
return None
|
||||
return float(voltage)
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
|
||||
Returns:
|
||||
A float number, electric current in amperes,
|
||||
e.g. 15.4
|
||||
"""
|
||||
is_valid, current = self.current_sensor.get_reading()
|
||||
if not is_valid:
|
||||
return None
|
||||
|
||||
return float(current)
|
||||
|
||||
def get_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied by PSU
|
||||
|
||||
Returns:
|
||||
A float number, the power in watts,
|
||||
e.g. 302.6
|
||||
"""
|
||||
is_valid, power = self.power_sensor.get_reading()
|
||||
if not is_valid:
|
||||
return None
|
||||
|
||||
return float(power)
|
||||
|
||||
def get_input_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage input
|
||||
|
||||
Returns:
|
||||
A float number, the input voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
is_valid, input_voltage = self.input_voltage_sensor.get_reading()
|
||||
if not is_valid:
|
||||
return None
|
||||
|
||||
return float(input_voltage)
|
||||
|
||||
def get_input_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied to PSU
|
||||
|
||||
Returns:
|
||||
A float number, electric current in amperes,
|
||||
e.g. 15.4
|
||||
"""
|
||||
is_valid, input_current = self.input_current_sensor.get_reading()
|
||||
if not is_valid:
|
||||
return None
|
||||
|
||||
return float(input_current)
|
||||
|
||||
def get_input_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied to PSU
|
||||
|
||||
Returns:
|
||||
A float number, the power in watts,
|
||||
e.g. 302.6
|
||||
"""
|
||||
is_valid, input_power = self.input_power_sensor.get_reading()
|
||||
if not is_valid:
|
||||
return None
|
||||
|
||||
return float(input_power)
|
||||
|
||||
def get_powergood_status(self):
|
||||
"""
|
||||
Retrieves the powergood status of PSU
|
||||
|
||||
Returns:
|
||||
A boolean, True if PSU has stablized its output voltages and
|
||||
passed all its internal self-tests, False if not.
|
||||
"""
|
||||
status = False
|
||||
is_valid, state = self.state_sensor.get_reading()
|
||||
if is_valid:
|
||||
if (state == 0x01):
|
||||
status = True
|
||||
|
||||
return status
|
||||
|
||||
def get_mfr_id(self):
|
||||
"""
|
||||
Retrives the Manufacturer Id of PSU
|
||||
|
||||
Returns:
|
||||
A string, the manunfacturer id.
|
||||
"""
|
||||
return self.fru.get_board_mfr_id()
|
||||
|
||||
def get_type(self):
|
||||
"""
|
||||
Retrives the Power Type of PSU
|
||||
|
||||
Returns :
|
||||
A string, PSU power type
|
||||
"""
|
||||
board_product = self.fru.get_board_product()
|
||||
if board_product is not None :
|
||||
info = board_product.split(',')
|
||||
if 'AC' in info : return 'AC'
|
||||
if 'DC' in info : return 'DC'
|
||||
return None
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.index
|
||||
|
||||
def get_temperature_high_threshold(self):
|
||||
"""
|
||||
Returns the high temperature threshold for PSU in Celsius
|
||||
"""
|
||||
is_valid, high_threshold = self.temp_sensor.get_threshold("UpperCritical")
|
||||
if not is_valid:
|
||||
high_threshold = 105
|
||||
high_threshold = "{:.2f}".format(high_threshold)
|
||||
|
||||
return float(high_threshold)
|
||||
|
||||
def get_voltage_low_threshold(self):
|
||||
"""
|
||||
Returns PSU low threshold in Volts
|
||||
"""
|
||||
is_valid, low_threshold = self.voltage_sensor.get_threshold("LowerCritical")
|
||||
if not is_valid:
|
||||
low_threshold = 11.4 #Revisit the value
|
||||
low_threshold = "{:.2f}".format(low_threshold)
|
||||
|
||||
return float(low_threshold)
|
||||
|
||||
|
||||
def get_voltage_high_threshold(self):
|
||||
"""
|
||||
Returns PSU high threshold in Volts
|
||||
"""
|
||||
is_valid, high_threshold = self.voltage_sensor.get_threshold("UpperCritical")
|
||||
if not is_valid:
|
||||
high_threshold = 12.6 #Revisit the value
|
||||
high_threshold = "{:.2f}".format(high_threshold)
|
||||
|
||||
return float(high_threshold)
|
||||
|
||||
def get_maximum_supplied_power(self):
|
||||
"""
|
||||
Retrieves the maximum supplied power by PSU
|
||||
Returns:
|
||||
A float number, the maximum power output in Watts.
|
||||
e.g. 1200.1
|
||||
"""
|
||||
return float(750)
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the PSU status LED
|
||||
Args:
|
||||
color: A string representing the color with which to set the PSU status LED
|
||||
Note: Only support green and off
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if not
|
||||
"""
|
||||
# Hardware not supported
|
||||
return False
|
@ -0,0 +1,367 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DELLEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os
|
||||
import time
|
||||
import struct
|
||||
import mmap
|
||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
QSFP_INFO_OFFSET = 128
|
||||
SFP_INFO_OFFSET = 0
|
||||
QSFP_DD_PAGE0 = 0
|
||||
|
||||
SFP_TYPE_LIST = [
|
||||
'0x3' # SFP/SFP+/SFP28 and later
|
||||
]
|
||||
QSFP_TYPE_LIST = [
|
||||
'0xc', # QSFP
|
||||
'0xd', # QSFP+ or later
|
||||
'0x11' # QSFP28 or later
|
||||
]
|
||||
QSFP_DD_TYPE_LIST = [
|
||||
'0x18' #QSFP-DD Type
|
||||
]
|
||||
|
||||
class Sfp(SfpOptoeBase):
|
||||
"""
|
||||
DELLEMC Platform-specific Sfp class
|
||||
"""
|
||||
BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0"
|
||||
|
||||
def __init__(self, index, sfp_type, eeprom_path):
|
||||
SfpOptoeBase.__init__(self)
|
||||
self.port_type = sfp_type
|
||||
self.sfp_type = sfp_type
|
||||
self.index = index
|
||||
self.eeprom_path = eeprom_path
|
||||
self._initialize_media(delay=False)
|
||||
|
||||
def get_eeprom_path(self):
|
||||
return self.eeprom_path
|
||||
|
||||
def get_name(self):
|
||||
return "SFP/SFP+/SFP28" if self.index < 96 else "QSFP28 or later"
|
||||
|
||||
def pci_mem_read(self, mm, offset):
|
||||
mm.seek(offset)
|
||||
read_data_stream = mm.read(4)
|
||||
reg_val = struct.unpack('I', read_data_stream)
|
||||
mem_val = str(reg_val)[1:-2]
|
||||
# print "reg_val read:%x"%reg_val
|
||||
return mem_val
|
||||
|
||||
def pci_mem_write(self, mm, offset, data):
|
||||
mm.seek(offset)
|
||||
# print "data to write:%x"%data
|
||||
mm.write(struct.pack('I', data))
|
||||
|
||||
def pci_set_value(self, resource, val, offset):
|
||||
fd = os.open(resource, os.O_RDWR)
|
||||
mm = mmap.mmap(fd, 0)
|
||||
val = self.pci_mem_write(mm, offset, val)
|
||||
mm.close()
|
||||
os.close(fd)
|
||||
return val
|
||||
|
||||
def pci_get_value(self, resource, offset):
|
||||
fd = os.open(resource, os.O_RDWR)
|
||||
mm = mmap.mmap(fd, 0)
|
||||
val = self.pci_mem_read(mm, offset)
|
||||
mm.close()
|
||||
os.close(fd)
|
||||
return val
|
||||
|
||||
def _initialize_media(self,delay=False):
|
||||
"""
|
||||
Initialize the media type and eeprom driver for SFP
|
||||
"""
|
||||
if delay:
|
||||
time.sleep(1)
|
||||
self._xcvr_api = None
|
||||
self.get_xcvr_api()
|
||||
|
||||
self.set_media_type()
|
||||
self.reinit_sfp_driver()
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.index
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the sfp
|
||||
Returns : True if sfp is present and false if it is absent
|
||||
"""
|
||||
# Check for invalid port_num
|
||||
mask = {'QSFP' : (1 << 4), 'SFP' : (1 << 0)}
|
||||
# Port offset starts with 0x4004
|
||||
port_offset = 16388 + ((self.index-1) * 16)
|
||||
|
||||
try:
|
||||
reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset))
|
||||
# ModPrsL is active low
|
||||
if reg_value & mask[self.port_type] == 0:
|
||||
return True
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrives the reset status of SFP
|
||||
"""
|
||||
reset_status = False
|
||||
if (self.port_type == 'QSFP'):
|
||||
# Port offset starts with 0x4000
|
||||
port_offset = 16384 + ((self.index-1) * 16)
|
||||
|
||||
reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset))
|
||||
|
||||
# Absence of status throws error
|
||||
if (reg_value == ""):
|
||||
return reset_status
|
||||
|
||||
# Mask off 4th bit for reset status
|
||||
mask = (1 << 4)
|
||||
|
||||
if ((reg_value & mask) == 0):
|
||||
reset_status = True
|
||||
else:
|
||||
reset_status = False
|
||||
|
||||
return reset_status
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
Retrieves the lpmode(low power mode) of this SFP
|
||||
"""
|
||||
lpmode_state = False
|
||||
if (self.port_type == 'QSFP'):
|
||||
|
||||
# Port offset starts with 0x4000
|
||||
port_offset = 16384 + ((self.index-1) * 16)
|
||||
|
||||
reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset))
|
||||
|
||||
# Absence of status throws error
|
||||
if (reg_value == ""):
|
||||
return lpmode_state
|
||||
|
||||
# Mask off 6th bit for lpmode
|
||||
mask = (1 << 6)
|
||||
|
||||
# LPMode is active high
|
||||
if reg_value & mask == 0:
|
||||
lpmode_state = False
|
||||
else:
|
||||
lpmode_state = True
|
||||
|
||||
return lpmode_state
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the SFP and returns all user settings to their default state
|
||||
"""
|
||||
if (self.port_type == 'QSFP'):
|
||||
# Port offset starts with 0x4000
|
||||
port_offset = 16384 + ((self.index-1) * 16)
|
||||
|
||||
reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset))
|
||||
|
||||
# Absence of status throws error
|
||||
if (reg_value == ""):
|
||||
return False
|
||||
|
||||
# Mask off 4th bit for reset
|
||||
mask = (1 << 4)
|
||||
|
||||
# ResetL is active low
|
||||
reg_value = reg_value & ~mask
|
||||
|
||||
# Convert our register value back to a hex string and write back
|
||||
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
|
||||
|
||||
# Sleep 1 second to allow it to settle
|
||||
time.sleep(1)
|
||||
|
||||
reg_value = reg_value | mask
|
||||
|
||||
# Convert our register value back to a hex string and write back
|
||||
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
|
||||
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
def set_lpmode(self, lpmode):
|
||||
"""
|
||||
Sets the lpmode(low power mode) of this SFP
|
||||
"""
|
||||
if (self.port_type == 'QSFP'):
|
||||
# Port offset starts with 0x4000
|
||||
port_offset = 16384 + ((self.index-1) * 16)
|
||||
|
||||
reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset))
|
||||
|
||||
# Absence of status throws error
|
||||
if (reg_value == ""):
|
||||
return False
|
||||
|
||||
# Mask off 6th bit for lowpower mode
|
||||
mask = (1 << 6)
|
||||
|
||||
# LPMode is active high; set or clear the bit accordingly
|
||||
if lpmode is True:
|
||||
reg_value = reg_value | mask
|
||||
else:
|
||||
reg_value = reg_value & ~mask
|
||||
|
||||
# Convert our register value back to a hex string and write back
|
||||
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
|
||||
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
"""
|
||||
reset = self.get_reset_status()
|
||||
|
||||
if (reset == True):
|
||||
status = False
|
||||
else:
|
||||
status = True
|
||||
|
||||
return status
|
||||
|
||||
def set_media_type(self):
|
||||
"""
|
||||
Reads optic eeprom byte to determine media type inserted
|
||||
"""
|
||||
eeprom_raw = []
|
||||
eeprom_raw = self._xcvr_api_factory._get_id()
|
||||
if eeprom_raw is not None:
|
||||
eeprom_raw = hex(eeprom_raw)
|
||||
if eeprom_raw in SFP_TYPE_LIST:
|
||||
self.sfp_type = 'SFP'
|
||||
elif eeprom_raw in QSFP_TYPE_LIST:
|
||||
self.sfp_type = 'QSFP'
|
||||
elif eeprom_raw in QSFP_DD_TYPE_LIST:
|
||||
self.sfp_type = 'QSFP_DD'
|
||||
else:
|
||||
#Set native port type if EEPROM type is not recognized/readable
|
||||
self.sfp_type = self.port_type
|
||||
else:
|
||||
self.sfp_type = self.port_type
|
||||
|
||||
return self.sfp_type
|
||||
|
||||
def reinit_sfp_driver(self):
|
||||
"""
|
||||
Changes the driver based on media type detected
|
||||
"""
|
||||
del_sfp_path = "/sys/class/i2c-adapter/i2c-{0}/delete_device".format(self.index+1)
|
||||
new_sfp_path = "/sys/class/i2c-adapter/i2c-{0}/new_device".format(self.index+1)
|
||||
driver_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/name".format(self.index+1)
|
||||
delete_device = "echo 0x50 >" + del_sfp_path
|
||||
|
||||
if not os.path.isfile(driver_path):
|
||||
print(driver_path, "does not exist")
|
||||
return False
|
||||
|
||||
try:
|
||||
with os.fdopen(os.open(driver_path, os.O_RDONLY)) as fd:
|
||||
driver_name = fd.read()
|
||||
driver_name = driver_name.rstrip('\r\n')
|
||||
driver_name = driver_name.lstrip(" ")
|
||||
|
||||
#Avoid re-initialization of the QSFP/SFP optic on QSFP/SFP port.
|
||||
if self.sfp_type == 'SFP' and driver_name in ['optoe1', 'optoe3']:
|
||||
subprocess.Popen(delete_device, shell=True, stdout=subprocess.PIPE)
|
||||
time.sleep(0.2)
|
||||
new_device = "echo optoe2 0x50 >" + new_sfp_path
|
||||
subprocess.Popen(new_device, shell=True, stdout=subprocess.PIPE)
|
||||
time.sleep(2)
|
||||
elif self.sfp_type == 'QSFP' and driver_name in ['optoe2', 'optoe3']:
|
||||
subprocess.Popen(delete_device, shell=True, stdout=subprocess.PIPE)
|
||||
time.sleep(0.2)
|
||||
new_device = "echo optoe1 0x50 >" + new_sfp_path
|
||||
subprocess.Popen(new_device, shell=True, stdout=subprocess.PIPE)
|
||||
time.sleep(2)
|
||||
elif self.sfp_type == 'QSFP_DD' and driver_name in ['optoe1', 'optoe2']:
|
||||
subprocess.Popen(delete_device, shell=True, stdout=subprocess.PIPE)
|
||||
time.sleep(0.2)
|
||||
new_device = "echo optoe3 0x50 >" + new_sfp_path
|
||||
subprocess.Popen(new_device, shell=True, stdout=subprocess.PIPE)
|
||||
time.sleep(2)
|
||||
|
||||
except IOError as e:
|
||||
print("Error: Unable to open file: %s" % str(e))
|
||||
return False
|
||||
|
||||
def get_max_port_power(self):
|
||||
"""
|
||||
Retrieves the maximumum power allowed on the port in watts
|
||||
"""
|
||||
return 5.0 if self.sfp_type == 'QSFP' else 2.5
|
||||
|
||||
def get_error_description(self):
|
||||
"""
|
||||
Retrives the error descriptions of the SFP module
|
||||
Returns:
|
||||
String that represents the current error descriptions of vendor specific errors
|
||||
In case there are multiple errors, they should be joined by '|',
|
||||
like: "Bad EEPROM|Unsupported cable"
|
||||
"""
|
||||
if not self.get_presence():
|
||||
return self.SFP_STATUS_UNPLUGGED
|
||||
else:
|
||||
if not os.path.isfile(self.eeprom_path):
|
||||
return "EEPROM driver is not attached"
|
||||
|
||||
if self.sfp_type == 'SFP':
|
||||
offset = SFP_INFO_OFFSET
|
||||
elif self.sfp_type == 'QSFP':
|
||||
offset = QSFP_INFO_OFFSET
|
||||
elif self.sfp_type == 'QSFP_DD':
|
||||
offset = QSFP_DD_PAGE0
|
||||
|
||||
try:
|
||||
with open(self.eeprom_path, mode="rb", buffering=0) as eeprom:
|
||||
eeprom.seek(offset)
|
||||
eeprom.read(1)
|
||||
except OSError as e:
|
||||
return "EEPROM read failed ({})".format(e.strerror)
|
||||
|
||||
return self.SFP_STATUS_OK
|
||||
|
@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC S5296F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Thermals' information which are available in the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
try:
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
from sonic_platform.ipmihelper import IpmiSensor
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""DellEMC Platform-specific Thermal class"""
|
||||
|
||||
# [ Sensor-Name, Sensor-ID ]
|
||||
SENSOR_MAPPING = [
|
||||
['PT Middle Sensor', 0x1],
|
||||
['ASIC On-board', 0x2],
|
||||
['PT Left Sensor', 0x3],
|
||||
['PT Right Sensor', 0x4],
|
||||
['Inlet Airflow Sensor', 0x5],
|
||||
['PSU1 Airflow Sensor', 0x7],
|
||||
['PSU2 Airflow Sensor', 0x8],
|
||||
['PSU1 Sensor', 0xc],
|
||||
['PSU2 Sensor', 0xd],
|
||||
['CPU On-board', 0xe]
|
||||
]
|
||||
|
||||
def __init__(self, thermal_index):
|
||||
ThermalBase.__init__(self)
|
||||
self.index = thermal_index + 1
|
||||
self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1])
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the thermal
|
||||
|
||||
Returns:
|
||||
string: The name of the thermal
|
||||
"""
|
||||
return self.SENSOR_MAPPING[self.index - 1][0]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the thermal
|
||||
|
||||
Returns:
|
||||
bool: True if thermal is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the Thermal
|
||||
|
||||
Returns:
|
||||
string: Model/part number of Thermal
|
||||
"""
|
||||
return 'NA'
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the Thermal
|
||||
|
||||
Returns:
|
||||
string: Serial number of Thermal
|
||||
"""
|
||||
return 'NA'
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the thermal
|
||||
|
||||
Returns:
|
||||
A boolean value, True if thermal is operating properly,
|
||||
False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from thermal
|
||||
|
||||
Returns:
|
||||
A float number of current temperature in Celsius up to
|
||||
nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
is_valid, temperature = self.sensor.get_reading()
|
||||
if not is_valid:
|
||||
temperature = 0
|
||||
|
||||
return float(temperature)
|
||||
|
||||
def get_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of thermal
|
||||
|
||||
Returns:
|
||||
A float number, the high threshold temperature of thermal in
|
||||
Celsius up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
"""
|
||||
is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical")
|
||||
if not is_valid:
|
||||
return 0.0
|
||||
|
||||
return float(high_threshold)
|
||||
|
||||
def get_high_critical_threshold(self):
|
||||
"""
|
||||
Retrieves the high critical threshold temperature of thermal
|
||||
|
||||
Returns:
|
||||
A float number, the high critical threshold temperature of thermal in
|
||||
Celsius up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
"""
|
||||
is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical")
|
||||
if not is_valid:
|
||||
return 0.0
|
||||
|
||||
return float(high_crit_threshold)
|
||||
|
||||
def get_low_threshold(self):
|
||||
"""
|
||||
Retrieves the low threshold temperature of thermal
|
||||
|
||||
Returns:
|
||||
A float number, the low threshold temperature of thermal in
|
||||
Celsius up to nearest thousandth of one degree Celsius,
|
||||
e.g. 30.125
|
||||
"""
|
||||
is_valid, low_threshold = self.sensor.get_threshold("LowerNonRecoverable")
|
||||
if not is_valid:
|
||||
low_threshold = 0
|
||||
|
||||
return float(low_threshold)
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high threshold temperature of thermal
|
||||
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one
|
||||
degree Celsius, e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if
|
||||
not
|
||||
"""
|
||||
# Thermal threshold values are pre-defined based on HW.
|
||||
return False
|
||||
|
||||
def set_low_threshold(self, temperature):
|
||||
"""
|
||||
Sets the low threshold temperature of thermal
|
||||
|
||||
Args :
|
||||
temperature: A float number up to nearest thousandth of one
|
||||
degree Celsius, e.g. 30.125
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if
|
||||
not
|
||||
"""
|
||||
# Thermal threshold values are pre-defined based on HW.
|
||||
return False
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent
|
||||
device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.index
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this Thermal is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return False
|
@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# DELLEMC S5296F
|
||||
#
|
||||
# Abstract base class for implementing a platform-specific class with
|
||||
# which to interact with a hardware watchdog module in SONiC
|
||||
#
|
||||
########################################################################
|
||||
|
||||
try:
|
||||
import ctypes
|
||||
import subprocess
|
||||
from sonic_platform_base.watchdog_base import WatchdogBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class _timespec(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('tv_sec', ctypes.c_long),
|
||||
('tv_nsec', ctypes.c_long)
|
||||
]
|
||||
|
||||
|
||||
class Watchdog(WatchdogBase):
|
||||
"""
|
||||
Abstract base class for interfacing with a hardware watchdog module
|
||||
"""
|
||||
|
||||
TIMERS = [15,20,30,40,50,60,65,70,80,100,120,140,160,180,210,240]
|
||||
|
||||
armed_time = 0
|
||||
timeout = 0
|
||||
CLOCK_MONOTONIC = 1
|
||||
|
||||
def __init__(self):
|
||||
self._librt = ctypes.CDLL('librt.so.1', use_errno=True)
|
||||
self._clock_gettime = self._librt.clock_gettime
|
||||
self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)]
|
||||
|
||||
def _get_command_result(self, cmdline):
|
||||
try:
|
||||
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
stdout = proc.communicate()[0]
|
||||
proc.wait()
|
||||
result = stdout.rstrip('\n'.encode())
|
||||
except OSError:
|
||||
result = None
|
||||
|
||||
return result
|
||||
|
||||
def _get_reg_val(self):
|
||||
# 0x31 = CPLD I2C Base Address
|
||||
# 0x07 = Watchdog Function Register
|
||||
value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07")
|
||||
if not value:
|
||||
return None
|
||||
else:
|
||||
return int(value, 16)
|
||||
|
||||
def _set_reg_val(self,val):
|
||||
# 0x31 = CPLD I2C Base Address
|
||||
# 0x07 = Watchdog Function Register
|
||||
value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s"
|
||||
% (val))
|
||||
return value
|
||||
|
||||
def _get_time(self):
|
||||
"""
|
||||
To get clock monotonic time
|
||||
"""
|
||||
ts = _timespec()
|
||||
if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0:
|
||||
self._errno = ctypes.get_errno()
|
||||
return 0
|
||||
return ts.tv_sec + ts.tv_nsec * 1e-9
|
||||
|
||||
def arm(self, seconds):
|
||||
"""
|
||||
Arm the hardware watchdog with a timeout of <seconds> seconds.
|
||||
If the watchdog is currently armed, calling this function will
|
||||
simply reset the timer to the provided value. If the underlying
|
||||
hardware does not support the value provided in <seconds>, this
|
||||
method should arm the watchdog with the *next greater*
|
||||
available value.
|
||||
|
||||
Returns:
|
||||
An integer specifying the *actual* number of seconds the
|
||||
watchdog was armed with. On failure returns -1.
|
||||
"""
|
||||
timer_offset = -1
|
||||
for key,timer_seconds in enumerate(self.TIMERS):
|
||||
if seconds > 0 and seconds <= timer_seconds:
|
||||
timer_offset = key
|
||||
seconds = timer_seconds
|
||||
break
|
||||
|
||||
if timer_offset == -1:
|
||||
return -1
|
||||
|
||||
# cpld_version = Component.get_cpld0_version()
|
||||
# wd_enabled_version = "0.8"
|
||||
|
||||
# if cpld_version < wd_enabled_version:
|
||||
# syslog.syslog(syslog.LOG_ERR,
|
||||
# 'Older System CPLD ver, Update to 0.8 to support watchdog ')
|
||||
# return -1
|
||||
|
||||
# Extracting 5th to 8th bits for WD timer values
|
||||
reg_val = self._get_reg_val()
|
||||
wd_timer_offset = (reg_val >> 4) & 0xf
|
||||
|
||||
if wd_timer_offset != timer_offset:
|
||||
# Setting 5th to 7th bits
|
||||
# value from timer_offset
|
||||
self.disarm()
|
||||
self._set_reg_val((reg_val & 0x07) | (timer_offset << 4))
|
||||
|
||||
if self.is_armed():
|
||||
# Setting last bit to WD Timer punch
|
||||
# Last bit = WD Timer punch
|
||||
self._set_reg_val(reg_val & 0xFE)
|
||||
|
||||
else:
|
||||
# Setting 4th bit to enable WD
|
||||
# 4th bit = Enable WD
|
||||
reg_val = self._get_reg_val()
|
||||
self._set_reg_val(reg_val | 0x8)
|
||||
|
||||
self.armed_time = self._get_time()
|
||||
self.timeout = seconds
|
||||
return seconds
|
||||
|
||||
def disarm(self):
|
||||
"""
|
||||
Disarm the hardware watchdog
|
||||
|
||||
Returns:
|
||||
A boolean, True if watchdog is disarmed successfully, False
|
||||
if not
|
||||
"""
|
||||
if self.is_armed():
|
||||
# Setting 4th bit to disable WD
|
||||
# 4th bit = Disable WD
|
||||
reg_val = self._get_reg_val()
|
||||
self._set_reg_val(reg_val & 0xF7)
|
||||
|
||||
self.armed_time = 0
|
||||
self.timeout = 0
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_armed(self):
|
||||
"""
|
||||
Retrieves the armed state of the hardware watchdog.
|
||||
|
||||
Returns:
|
||||
A boolean, True if watchdog is armed, False if not
|
||||
"""
|
||||
|
||||
# Extracting 4th bit to get WD Enable/Disable status
|
||||
# 0 - Disabled WD
|
||||
# 1 - Enabled WD
|
||||
reg_val = self._get_reg_val()
|
||||
wd_offset = (reg_val >> 3) & 1
|
||||
|
||||
return bool(wd_offset)
|
||||
|
||||
def get_remaining_time(self):
|
||||
"""
|
||||
If the watchdog is armed, retrieve the number of seconds
|
||||
remaining on the watchdog timer
|
||||
|
||||
Returns:
|
||||
An integer specifying the number of seconds remaining on
|
||||
their watchdog timer. If the watchdog is not armed, returns
|
||||
-1.
|
||||
|
||||
S5296F doesnot have hardware support to show remaining time.
|
||||
Due to this limitation, this API is implemented in software.
|
||||
This API would return correct software time difference if it
|
||||
is called from the process which armed the watchdog timer.
|
||||
If this API called from any other process, it would return
|
||||
0. If the watchdog is not armed, this API would return -1.
|
||||
"""
|
||||
if not self.is_armed():
|
||||
return -1
|
||||
|
||||
if self.armed_time > 0 and self.timeout != 0:
|
||||
cur_time = self._get_time()
|
||||
|
||||
if cur_time <= 0:
|
||||
return 0
|
||||
|
||||
diff_time = int(cur_time - self.armed_time)
|
||||
|
||||
if diff_time > self.timeout:
|
||||
return self.timeout
|
||||
else:
|
||||
return self.timeout - diff_time
|
||||
|
||||
return 0
|
||||
|
Loading…
Reference in New Issue
Block a user