Dell: E3224F platform onboarding (#16002)

* Dell: E3224F platform onboarding

* Dell: E3224F platform onboarding
This commit is contained in:
Arun LK 2023-08-11 05:57:30 +05:30 committed by GitHub
parent a86eb95005
commit 97113bae61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 7518 additions and 1 deletions

View File

@ -0,0 +1,2 @@
{%- set default_topo = 't0' %}
{%- include 'buffers_config.j2' %}

View File

@ -0,0 +1,41 @@
{%- set default_cable = '5m' %}
{%- macro generate_port_lists(PORT_ALL) %}
{# Generate list of ports #}
{% for port_idx in range(0,24) %}
{% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %}
{% endfor %}
{%- endmacro %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "8192000",
"type": "ingress",
"mode": "dynamic",
"xoff": "196608"
},
"egress_lossless_pool": {
"size": "8388608",
"type": "egress",
"mode": "static"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"static_th":"8388608"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"1518",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,41 @@
{%- set default_cable = '300m' %}
{%- macro generate_port_lists(PORT_ALL) %}
{# Generate list of ports #}
{% for port_idx in range(0,24) %}
{% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %}
{% endfor %}
{%- endmacro %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "8192000",
"type": "ingress",
"mode": "dynamic",
"xoff": "196608"
},
"egress_lossless_pool": {
"size": "8388608",
"type": "egress",
"mode": "static"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"static_th":"8388608"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"1518",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,3 @@
{
"copp_rx_rate":15000
}

View File

@ -0,0 +1,145 @@
{
"COPP_GROUP": {
"copp-system-lacp": {
"cir":"250",
"cbs":"250"
},
"copp-system-udld": {
"cir":"250",
"cbs":"250"
},
"copp-system-stp": {
"cir":"8000",
"cbs":"8000"
},
"copp-system-bfd": {
"cir":"750",
"cbs":"750"
},
"copp-system-lldp": {
"cir":"250",
"cbs":"250"
},
"copp-system-vrrp": {
"cir":"250",
"cbs":"250"
},
"copp-system-iccp": {
"cir":"2500",
"cbs":"2500"
},
"copp-system-ospf": {
"cir":"2500",
"cbs":"2500"
},
"copp-system-bgp": {
"cir":"5000",
"cbs":"5000"
},
"copp-system-pim": {
"cir":"2500",
"cbs":"2500"
},
"copp-system-igmp": {
"cir":"1000",
"cbs":"1000"
},
"copp-system-suppress": {
"cir":"1500",
"cbs":"1500"
},
"copp-system-arp": {
"cir":"1500",
"cbs":"1500"
},
"copp-system-dhcp": {
"cir":"150",
"cbs":"150"
},
"copp-system-icmp": {
"cir":"500",
"cbs":"500"
},
"copp-system-ip2me": {
"cir":"3000",
"cbs":"3000"
},
"copp-system-subnet": {
"cir":"1000",
"cbs":"1000"
},
"copp-system-mtu": {
"cir":"250",
"cbs":"250"
},
"copp-system-sflow": {
"cir":"4000",
"cbs":"4000"
}
},
"SCHEDULER": {
"copp-scheduler-policy@23": {
"pir": "250"
},
"copp-scheduler-policy@22": {
"pir": "250"
},
"copp-scheduler-policy@21": {
"pir": "8000"
},
"copp-scheduler-policy@20": {
"pir": "750"
},
"copp-scheduler-policy@19": {
"pir": "2500"
},
"copp-scheduler-policy@18": {
"pir": "250"
},
"copp-scheduler-policy@17": {
"pir": "250"
},
"copp-scheduler-policy@16": {
"pir": "2500"
},
"copp-scheduler-policy@15": {
"pir": "2500"
},
"copp-scheduler-policy@14": {
"pir": "5000"
},
"copp-scheduler-policy@13": {
"pir": "2500"
},
"copp-scheduler-policy@12": {
"pir": "1000"
},
"copp-scheduler-policy@11": {
"pir": "1500"
},
"copp-scheduler-policy@10": {
"pir": "1500"
},
"copp-scheduler-policy@9": {
"pir": "150"
},
"copp-scheduler-policy@8": {
"pir": "500"
},
"copp-scheduler-policy@7": {
"pir": "3000"
},
"copp-scheduler-policy@6": {
"pir": "1000"
},
"copp-scheduler-policy@4": {
"pir": "250"
},
"copp-scheduler-policy@3": {
"pir": "4000"
},
"copp-scheduler-policy@1": {
"pir": "100"
}
}
}

View File

@ -0,0 +1,157 @@
bcm_num_cos=8
bcm_stat_interval=2000000
bcm_tunnel_term_compatible_mode=1
cdma_timeout_usec=3000000
flow_init_mode=0
ifa_enable=0
ifp_inports_support_enable=1
ipv6_lpm_128b_enable=0x1
l2xmsg_mode=1
#Default L3 profile
l2_mem_entries=32768
l3_alpm_enable=2
l3_alpm_ipv6_128b_bkt_rsvd=1
l3_max_ecmp_mode=1
l3_mem_entries=16348
lpm_scaling_enable=0
memlist_enable=1
reglist_enable=1
scache_filename=/tmp/brcm_bcm_scache
schan_intr_enable=0
stable_size=0x5500000
tdma_timeout_usec=3000000
pfc_deadlock_seq_control=1
#Port and PHY configs
core_clock_frequency=668
pbmp_xport_xe=0x1ffffffe
port_gmii_mode_33=1
port_gmii_mode_17=1
port_gmii_mode_1=1
portmap_1=1:1
portmap_2=2:1
portmap_3=3:1
portmap_4=4:1
portmap_5=5:1
portmap_6=6:1
portmap_7=7:1
portmap_8=8:1
portmap_9=9:1
portmap_10=10:1
portmap_11=11:1
portmap_12=12:1
portmap_13=13:1
portmap_14=14:1
portmap_15=15:1
portmap_16=16:1
portmap_17=17:1
portmap_18=18:1
portmap_19=19:1
portmap_20=20:1
portmap_21=21:1
portmap_22=22:1
portmap_23=23:1
portmap_24=24:1
portmap_25=64:10
portmap_26=63:10
portmap_27=62:10
portmap_28=61:10
portmap_29=69:100
portmap_33=73:100
phy_chain_tx_lane_map_physical{33.0}=0x2301
phy_chain_rx_lane_map_physical{33.0}=0x2301
phy_port_primary_and_offset_1=0x0100
phy_port_primary_and_offset_2=0x0101
phy_port_primary_and_offset_3=0x0102
phy_port_primary_and_offset_4=0x0103
phy_port_primary_and_offset_5=0x0104
phy_port_primary_and_offset_6=0x0105
phy_port_primary_and_offset_7=0x0106
phy_port_primary_and_offset_8=0x0107
phy_port_primary_and_offset_9=0x0900
phy_port_primary_and_offset_10=0x0901
phy_port_primary_and_offset_11=0x0902
phy_port_primary_and_offset_12=0x0903
phy_port_primary_and_offset_13=0x0904
phy_port_primary_and_offset_14=0x0905
phy_port_primary_and_offset_15=0x0906
phy_port_primary_and_offset_16=0x0907
phy_port_primary_and_offset_17=0x1200
phy_port_primary_and_offset_18=0x1201
phy_port_primary_and_offset_19=0x1202
phy_port_primary_and_offset_20=0x1203
phy_port_primary_and_offset_21=0x1204
phy_port_primary_and_offset_22=0x1205
phy_port_primary_and_offset_23=0x1206
phy_port_primary_and_offset_24=0x1207
port_phy_addr_1=0x0
port_phy_addr_2=0x1
port_phy_addr_3=0x2
port_phy_addr_4=0x3
port_phy_addr_5=0x4
port_phy_addr_6=0x5
port_phy_addr_7=0x6
port_phy_addr_8=0x7
port_phy_addr_9=0x9
port_phy_addr_10=0xa
port_phy_addr_11=0xb
port_phy_addr_12=0xc
port_phy_addr_13=0xd
port_phy_addr_14=0xe
port_phy_addr_15=0xf
port_phy_addr_16=0x10
port_phy_addr_17=0x12
port_phy_addr_18=0x13
port_phy_addr_19=0x14
port_phy_addr_20=0x15
port_phy_addr_21=0x16
port_phy_addr_22=0x17
port_phy_addr_23=0x18
port_phy_addr_24=0x19
port_phy_addr_25=0x20
port_phy_addr_26=0x21
port_phy_addr_27=0x22
port_phy_addr_28=0x23
phy_force_firmware_load_26=0x01
phy_force_firmware_load_27=0x01
phy_force_firmware_load_28=0x01
phy_pcs_repeater_25=0x01
phy_pcs_repeater_26=0x01
phy_pcs_repeater_27=0x01
phy_pcs_repeater_28=0x01
phy_fiber_pref_ge=1
phy_automedium_ge=0
dport_map_port_1=8
dport_map_port_2=7
dport_map_port_3=6
dport_map_port_4=5
dport_map_port_5=4
dport_map_port_6=3
dport_map_port_7=2
dport_map_port_8=1
dport_map_port_9=16
dport_map_port_10=15
dport_map_port_11=14
dport_map_port_12=13
dport_map_port_13=12
dport_map_port_14=11
dport_map_port_15=10
dport_map_port_16=9
dport_map_port_17=24
dport_map_port_18=23
dport_map_port_19=22
dport_map_port_20=21
dport_map_port_21=20
dport_map_port_22=19
dport_map_port_23=18
dport_map_port_24=17
dport_map_port_25=25
dport_map_port_26=26
dport_map_port_27=27
dport_map_port_28=28
sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc

View File

@ -0,0 +1,17 @@
# PG lossless profiles.
# speed cable size xon xoff threshold xon_offset
10000 5m 9427 0 50176 1 3584
25000 5m 9427 0 50176 1 3584
40000 5m 9427 0 50176 1 3584
50000 5m 9427 0 50176 1 3584
100000 5m 9427 0 50176 1 3584
10000 40m 9427 0 50176 1 3584
25000 40m 9427 0 50176 1 3584
40000 40m 9427 0 50176 1 3584
50000 40m 9427 0 50176 1 3584
100000 40m 9427 0 50176 1 3584
10000 300m 9427 0 50176 1 3584
25000 300m 9427 0 50176 1 3584
40000 300m 9427 0 50176 1 3584
50000 300m 9427 0 50176 1 3584
100000 300m 9427 0 50176 1 3584

View File

@ -0,0 +1,31 @@
# name lanes alias index speed autoneg
Ethernet0 8 oneGigE1/1 1 1000 1
Ethernet1 7 oneGigE1/2 2 1000 1
Ethernet2 6 oneGigE1/3 3 1000 1
Ethernet3 5 oneGigE1/4 4 1000 1
Ethernet4 4 oneGigE1/5 5 1000 1
Ethernet5 3 oneGigE1/6 6 1000 1
Ethernet6 2 oneGigE1/7 7 1000 1
Ethernet7 1 oneGigE1/8 8 1000 1
Ethernet8 16 oneGigE1/9 9 1000 1
Ethernet9 15 oneGigE1/10 10 1000 1
Ethernet10 14 oneGigE1/11 11 1000 1
Ethernet11 13 oneGigE1/12 12 1000 1
Ethernet12 12 oneGigE1/13 13 1000 1
Ethernet13 11 oneGigE1/14 14 1000 1
Ethernet14 10 oneGigE1/15 15 1000 1
Ethernet15 9 oneGigE1/16 16 1000 1
Ethernet16 24 oneGigE1/17 17 1000 1
Ethernet17 23 oneGigE1/18 18 1000 1
Ethernet18 22 oneGigE1/19 19 1000 1
Ethernet19 21 oneGigE1/20 20 1000 1
Ethernet20 20 oneGigE1/21 21 1000 1
Ethernet21 19 oneGigE1/22 22 1000 1
Ethernet22 18 oneGigE1/23 23 1000 1
Ethernet23 17 oneGigE1/24 24 1000 1
Ethernet24 64 tenGigE1/25 25 10000 0
Ethernet25 63 tenGigE1/26 26 10000 0
Ethernet26 62 tenGigE1/27 27 10000 0
Ethernet27 61 tenGigE1/28 28 10000 0
Ethernet28 69,70,71,72 hundredGigE1/29 29 100000 0
Ethernet32 73,74,75,76 hundredGigE1/30 30 100000 0

View File

@ -0,0 +1 @@
{%- include 'qos_config_t1.j2' %}

View File

@ -0,0 +1,175 @@
{%- set PORT_ALL = [] %}
{%- for port in PORT %}
{%- if PORT_ALL.append(port) %}{% endif %}
{%- endfor %}
{%- if PORT_ALL | sort_by_port_index %}{% endif %}
{%- set port_names_list_all = [] %}
{%- for port in PORT_ALL %}
{%- if port_names_list_all.append(port) %}{% endif %}
{%- endfor %}
{%- set port_names_all = port_names_list_all | join(',') -%}
{%- set PORT_ACTIVE = [] %}
{%- if DEVICE_NEIGHBOR is not defined %}
{%- set PORT_ACTIVE = PORT_ALL %}
{%- else %}
{%- for port in DEVICE_NEIGHBOR.keys() %}
{%- if PORT_ACTIVE.append(port) %}{%- endif %}
{%- endfor %}
{%- endif %}
{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %}
{%- set port_names_list_active = [] %}
{%- for port in PORT_ACTIVE %}
{%- if port_names_list_active.append(port) %}{%- endif %}
{%- endfor %}
{%- set port_names_active = port_names_list_active | join(',') -%}
{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%}
{
{% if generate_tc_to_pg_map is defined %}
{{- generate_tc_to_pg_map() }}
{% else %}
"TC_TO_PRIORITY_GROUP_MAP": {
"AZURE": {
"0": "0",
"1": "0",
"2": "0",
"3": "3",
"4": "4",
"5": "0",
"6": "0",
"7": "7"
}
},
{% endif %}
"MAP_PFC_PRIORITY_TO_QUEUE": {
"AZURE": {
"0": "0",
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7"
}
},
"TC_TO_QUEUE_MAP": {
"AZURE": {
"0": "0",
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7"
}
},
"DSCP_TO_TC_MAP": {
"AZURE": {
"0" : "1",
"1" : "1",
"2" : "1",
"3" : "3",
"4" : "4",
"5" : "2",
"6" : "1",
"7" : "1",
"8" : "0",
"9" : "1",
"10": "1",
"11": "1",
"12": "1",
"13": "1",
"14": "1",
"15": "1",
"16": "1",
"17": "1",
"18": "1",
"19": "1",
"20": "1",
"21": "1",
"22": "1",
"23": "1",
"24": "1",
"25": "1",
"26": "1",
"27": "1",
"28": "1",
"29": "1",
"30": "1",
"31": "1",
"32": "1",
"33": "1",
"34": "1",
"35": "1",
"36": "1",
"37": "1",
"38": "1",
"39": "1",
"40": "1",
"41": "1",
"42": "1",
"43": "1",
"44": "1",
"45": "1",
"46": "5",
"47": "1",
"48": "6",
"49": "1",
"50": "1",
"51": "1",
"52": "1",
"53": "1",
"54": "1",
"55": "1",
"56": "1",
"57": "1",
"58": "1",
"59": "1",
"60": "1",
"61": "1",
"62": "1",
"63": "1"
}
},
"SCHEDULER": {
"scheduler.0": {
"type" : "DWRR",
"weight": "14"
},
"scheduler.1": {
"type" : "DWRR",
"weight": "15"
}
},
{% if asic_type in pfc_to_pg_map_supported_asics %}
"PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": {
"AZURE": {
"3": "3",
"4": "4"
}
},
{% endif %}
"PORT_QOS_MAP": {
{% for port in PORT_ACTIVE %}
"{{ port }}": {
"dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]",
"tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]",
"tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]",
"pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]",
{% if asic_type in pfc_to_pg_map_supported_asics %}
"pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]",
{% endif %}
"pfc_enable" : "3,4"
}{% if not loop.last %},{% endif %}
{% endfor %}
}
}

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/hx5-e3224f-24x1G+4x10G.config.bcm

View File

@ -0,0 +1,2 @@
m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin
m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin

View File

@ -0,0 +1 @@
Dell-E3224F t1

View File

@ -0,0 +1,13 @@
{
"FEATURE": {
"tam": {
"state": "disabled"
},
"telemetry": {
"state": "disabled"
},
"nat": {
"state": "disabled"
}
}
}

View File

@ -0,0 +1,4 @@
CONSOLE_PORT=0x3f8
CONSOLE_DEV=0
VAR_LOG_SIZE=512
ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_iommu=off irqfixup"

View File

@ -0,0 +1,7 @@
# LED microprocessor initialization for Dell E3224F
#
#
#Led0
#led auto on
m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin
led start

View File

@ -0,0 +1,281 @@
{
"chassis": {
"name": "E3224F-ON",
"status_led": {
"controllable": true,
"colors": ["green", "blink_green", "yellow", "blink_yellow"]
},
"thermal_manager" : false,
"components": [
{
"name": "BIOS"
},
{
"name": "CPU CPLD"
},
{
"name": "SYS CPLD"
},
{
"name": "PORT CPLD"
}
],
"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
}
}
],
"fan_drawers":[
{
"name": "FanTray1",
"status_led": {
"controllable": true,
"colors": ["off", "green", "yellow"]
},
"fans": [
{
"name": "FanTray1-Fan1",
"speed": {
"controllable":false
},
"status_led": {
"available": false
}
}
]
},
{
"name": "FanTray2",
"status_led": {
"controllable": true,
"colors": ["off", "green", "yellow"]
},
"fans": [
{
"name": "FanTray2-Fan1",
"speed": {
"controllable":false
},
"status_led": {
"available": false
}
}
]
},
{
"name": "FanTray3",
"status_led": {
"controllable": true,
"colors": ["off", "green", "yellow"]
},
"fans": [
{
"name": "FanTray3-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": "Front Panel PHY Temperature",
"controllable": false,
"low-crit-threshold": false,
"high-crit-threshold": false,
"minimum-recorded": false,
"maximum-recorded": false
},
{
"name": "Middle Fan Tray Temperature",
"controllable": false,
"low-crit-threshold": false,
"high-crit-threshold": false,
"minimum-recorded": false,
"maximum-recorded": false
},
{
"name": "Near Front Panel Temperature",
"controllable": false,
"low-crit-threshold": false,
"high-crit-threshold": false,
"minimum-recorded": false,
"maximum-recorded": false
},
{
"name": "Switch Near Temperature",
"controllable": false,
"low-crit-threshold": false,
"high-crit-threshold": false,
"minimum-recorded": false,
"maximum-recorded": false
},
{
"name": "Switch Rear Temperature",
"controllable": false,
"low-crit-threshold": false,
"high-crit-threshold": false,
"minimum-recorded": false,
"maximum-recorded": false
}
],
"modules": [],
"sfps": [
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP"
},
{
"name": "SFP/SFP+/SFP28"
},
{
"name": "SFP/SFP+/SFP28"
},
{
"name": "SFP/SFP+/SFP28"
},
{
"name": "SFP/SFP+/SFP28"
},
{
"name": "QSFP or later"
},
{
"name": "QSFP or later"
}
]
},
"interfaces": {}
}

View File

@ -0,0 +1 @@
broadcom

View File

@ -0,0 +1,22 @@
#!/usr/bin/python3
#############################################################################
# Dell E3224F
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
from sonic_eeprom import eeprom_tlvinfo
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,71 @@
#
# fanutil.py
# Platform-specific FAN status interface for SONiC
#
import sys
from sonic_py_common.general import getstatusoutput_noshell
SENSORS_CMD = ["docker", "exec", "-i", "pmon", "/usr/bin/sensors"]
DOCKER_SENSORS_CMD = "/usr/bin/sensors"
try:
from sonic_fan.fan_base import FanBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class FanUtil(FanBase):
"""Platform-specific FanUtil class"""
_fan_mapping = {
1 : '0',
2 : '1',
3 : '2'
}
def __init__(self):
FanBase.__init__(self)
def isDockerEnv(self):
num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker")
if num_docker > 0:
return True
def get_num_fans(self):
E3224F_MAX_FANTRAYS = 3
return E3224F_MAX_FANTRAYS
def get_presence(self, idx):
sysfs_path = "/sys/devices/platform/dell-e3224f-cpld.0/fan" + self._fan_mapping[idx] + "_prs"
return int(open(sysfs_path).read(), 16)
def get_direction(self, idx):
sysfs_path = "/sys/devices/platform/dell-e3224f-cpld.0/fan" + self._fan_mapping[idx] + "_dir"
return open(sysfs_path).read()
def get_speed(self, idx):
dockerenv = self.isDockerEnv()
if not dockerenv:
status, cmd_output = getstatusoutput_noshell(SENSORS_CMD)
else:
status, cmd_output = getstatusoutput_noshell(DOCKER_SENSORS_CMD)
if status:
print('Failed to execute sensors command')
sys.exit(0)
fan_id = 'Fan ' + str(idx)
found = False
for line in cmd_output.splitlines():
if line.startswith('emc2305-i2c-7-2c'):
found = True
if found and line.startswith(fan_id):
return line.split()[3]
return 0.0
def get_status(self, idx):
sysfs_path = "/sys/devices/platform/dell-e3224f-cpld.0/fan" + self._fan_mapping[idx] + "_prs"
return int(open(sysfs_path).read(), 16)
def set_speed(self, idx):
return False

View File

@ -0,0 +1,16 @@
- bus: '02'
dev: '00'
fn: '0'
id: '1533'
name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev
03)'
- bus: '01'
dev: '00'
fn: '0'
id: b371
name: 'Ethernet controller: Broadcom Limited BCM56371 Switch ASIC (rev 02)'
- bus: '00'
dev: '14'
fn: '0'
id: 19c2
name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)'

View File

@ -0,0 +1,190 @@
#
# psuutil.py
# Platform-specific PSU status interface for SONiC
#
import os
import sys
from sonic_py_common.general import getstatusoutput_noshell
SENSORS_CMD = ["docker", "exec", "-i", "pmon", "/usr/bin/sensors"]
DOCKER_SENSORS_CMD = "/usr/bin/sensors"
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
_psu_mapping = {
1 : '0',
2 : '1'
}
def __init__(self):
PsuBase.__init__(self)
def isDockerEnv(self):
num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker")
if num_docker > 0:
return True
else:
return False
def remove_nonnumeric(self, text):
digits='0123456789.'
return ''.join(c for c in text if c in digits)
def get_cpld_register(self, reg_name):
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
retval = 'ERR'
reg_file = cpld_dir +'/' + reg_name
if (not os.path.isfile(reg_file)):
return retval
try:
with open(reg_file, 'r') as fd:
retval = fd.read()
except Exception as error:
print("Unable to open ", reg_file, "file !")
retval = retval.rstrip('\r\n')
return retval
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
E3224F_MAX_PSUS = 2
return E3224F_MAX_PSUS
def get_psu_status(self, index):
"""
Retrieves the oprational status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is operating properly, False if PSU is\
faulty
"""
status = 0
psu_status = self.get_cpld_register('psu'+self._psu_mapping[index]+'_status')
if (psu_status != 'ERR'):
status = int(psu_status, 10)
presence = self.get_psu_presence(index)
return (status & presence)
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
status = 0
psu_presence = self.get_cpld_register('psu'+self._psu_mapping[index]+'_prs')
if (psu_presence != 'ERR'):
status = int(psu_presence, 10)
return status
def get_sensor(self):
dockerenv = self.isDockerEnv()
if not dockerenv:
status, cmd_output = getstatusoutput_noshell(SENSORS_CMD)
else:
status, cmd_output = getstatusoutput_noshell(DOCKER_SENSORS_CMD)
if status:
print('Failed to execute sensors command')
sys.exit(0)
return cmd_output
def get_output_current(self, index):
cmd_output= self.get_sensor()
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
found = False
for line in cmd_output.splitlines():
if line.startswith(sensor_name):
found = True
if found:
if 'Output Current' in line :
return float(self.remove_nonnumeric(line.split()[2]))
return 0.0
def get_output_voltage(self, index):
cmd_output= self.get_sensor()
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
found = False
for line in cmd_output.splitlines():
if line.startswith(sensor_name):
found = True
if found:
if 'Output Voltage' in line :
return float(self.remove_nonnumeric(line.split()[2]))
return 0.0
def get_fan_rpm(self, index, fan_index):
if fan_index > 1 : return 0.0
cmd_output= self.get_sensor()
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
found = False
for line in cmd_output.splitlines():
if line.startswith(sensor_name):
found = True
if found:
if 'Fan RPM' in line :
return self.remove_nonnumeric(line.split()[2])
return 0.0
def get_output_power(self, index):
cmd_output= self.get_sensor()
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
found = False
for line in cmd_output.splitlines():
if line.startswith(sensor_name):
found = True
if found:
if 'Output Power' in line :
return float(self.remove_nonnumeric(line.split()[2]))
return 0.0
def get_direction(self, index):
psuid = '0' if index == 1 else '1'
sysfs_path = '/sys/devices/platform/dell-e3224f-cpld.0/psu' + psuid + '_prs'
found_psu = int(open(sysfs_path).read())
if not found_psu : return ''
bus_no = '10' if index == 1 else '11'
sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom"
val = (open(sysfs_path, "rb").read())[0xe1:0xe8]
dir = 'F2B' if 'FORWARD' == val else 'B2F'
return dir
def get_serial(self, index):
psuid = '0' if index == 1 else '1'
sysfs_path = '/sys/devices/platform/dell-e3224f-cpld.0/psu' + psuid + '_prs'
found_psu = int(open(sysfs_path).read())
if not found_psu : return ''
bus_no = '10' if index == 1 else '11'
sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom"
val = (open(sysfs_path, "rb").read())[0xc4:0xd9]
return val
def get_model(self, index):
psuid = '0' if index == 1 else '1'
sysfs_path = '/sys/devices/platform/dell-e3224f-cpld.0/psu' + psuid + '_prs'
found_psu = int(open(sysfs_path).read())
if not found_psu : return ''
bus_no = '10' if index == 1 else '11'
sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom"
val = (open(sysfs_path, "rb").read())[0x50:0x62]
return val
def get_mfr_id(self, index):
psuid = '0' if index == 1 else '1'
sysfs_path = '/sys/devices/platform/dell-e3224f-cpld.0/psu' + psuid + '_prs'
found_psu = int(open(sysfs_path).read())
return 'DELTA' if found_psu else ''

View File

@ -0,0 +1,198 @@
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
try:
import time
from socket import *
from select import *
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 1
PORT_END = 30
PORTS_IN_BLOCK = 30
SFP_PORT_START = 1
SFP_PORT_END = 28
EEPROM_OFFSET = 14
_port_to_eeprom_mapping = {}
_port_i2c_mapping = {
1: 27,
2: 28,
3: 29,
4: 30,
5: 31,
6: 32,
7: 33,
8: 34,
9: 35,
10: 36,
11: 37,
12: 38,
13: 39,
14: 40,
15: 41,
16: 42,
17: 43,
18: 44,
19: 45,
20: 46,
21: 47,
22: 48,
23: 49,
24: 50,
25: 20,
26: 21,
27: 22,
28: 23,
29: 24,
30: 25
}
port_dict = {}
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_ports(self) :
return range(self.SFP_PORT_END+1, self.PORT_END+1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
@property
def get_transceiver_status(self):
try:
sfp_modprs_path = "/sys/devices/platform/dell-e3224f-cpld.0/sfp_modprs"
reg_file = open(sfp_modprs_path)
except IOError as e:
print ("Error: unable to open file: %s" % str(e))
return False
content = reg_file.readline().rstrip()
reg_file.close()
return int(content, 16)
def __init__(self):
sfpplus_eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for x in range(self.SFP_PORT_START, self.PORT_END + 1):
self.port_to_eeprom_mapping[x] = sfpplus_eeprom_path.format(self._port_i2c_mapping[x])
# Get Transceiver status
self.modprs_register = self.get_transceiver_status
SfpUtilBase.__init__(self)
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
if port_num < self.SFP_PORT_START :
return False
port_num -= self.SFP_PORT_START
try:
sfp_modprs_path = "/sys/devices/platform/dell-e3224f-cpld.0/sfp_modprs"
reg_file = open(sfp_modprs_path)
except IOError as e:
print ("Error: unable to open file: %s" % str(e))
return False
content = reg_file.readline().rstrip()
# content is a string containing the hex representation of the register
reg_value = int(content, 16)
# Mask off the bit corresponding to our port
mask = (1 << port_num)
# ModPrsL is active low
if (reg_value & mask) == 0:
return True
return False
def get_low_power_mode(self, port_num):
return False
def set_low_power_mode(self, port_num, lpmode):
return False
def reset(self, port_num):
return False
def get_transceiver_change_event(self, timeout=0):
start_time = time.time()
port = self.SFP_PORT_START
forever = False
if timeout == 0:
forever = True
elif timeout > 0:
timeout = timeout / float(1000) # Convert to secs
else:
print ('get_transceiver_change_event:Invalid timeout value', timeout)
return False, {}
end_time = start_time + timeout
if start_time > end_time:
print ('get_transceiver_change_event:' \
'time wrap / invalid timeout value', timeout)
return False, {} # Time wrap or possibly incorrect timeout
while timeout >= 0:
# Check for OIR events and return updated port_dict
reg_value = self.get_transceiver_status
if reg_value != self.modprs_register:
changed_ports = self.modprs_register ^ reg_value
while port >= self.SFP_PORT_START and port <= self.SFP_PORT_END:
# Mask off the bit corresponding to our port
mask = (1 << (port - self.SFP_PORT_START))
if changed_ports & mask:
# ModPrsL is active low
if reg_value & mask == 0:
self.port_dict[port] = '1'
else:
self.port_dict[port] = '0'
port += 1
# Update reg value
self.modprs_register = reg_value
return True, self.port_dict
if forever:
time.sleep(1)
else:
timeout = end_time - time.time()
if timeout >= 1:
time.sleep(1) # We poll at 1 second granularity
else:
if timeout > 0:
time.sleep(timeout)
return True, {}
print ("get_transceiver_change_event: Should not reach here.")
return False, {}

View File

@ -0,0 +1,3 @@
{
"skip_ledd": true
}

View File

@ -0,0 +1,58 @@
# libsensors configuration file for Dell N3248TE
# The i2c bus portion is omit because adapter name
# changes every time when system boot up.
bus "i2c-7" "i2c-0-mux (chan_id 5)"
bus "i2c-5" "i2c-0-mux (chan_id 3)"
bus "i2c-10" "i2c-5-mux (chan_id 0)"
bus "i2c-11" "i2c-5-mux (chan_id 1)"
chip "tmp75-i2c-7-49"
label temp1 "Switch Near Temperature"
chip "tmp75-i2c-7-4a"
label temp1 "Switch Rear Temperature"
chip "tmp75-i2c-7-4b"
label temp1 "Front Panel PHY Temperature"
chip "tmp75-i2c-7-4c"
label temp1 "Near Front Panel Temperature"
chip "tmp75-i2c-7-4f"
label temp1 "Middle Fan Tray Temperature"
chip "emc2305-i2c-7-2c"
ignore fan4
ignore fan5
label fan1 "Fan 1 "
label fan2 "Fan 2 "
label fan3 "Fan 3 "
chip "dps460-i2c-10-5e"
label power1 "Input Power"
label power2 "Output Power"
label curr1 "Input Current"
label curr2 "Output Current"
label in1 "Input Voltage"
ignore in2
label in3 "Output Voltage"
label fan1 "Fan RPM"
ignore fan2
ignore fan3
ignore temp1
label temp2 "FAN Airflow Temperature"
label temp3 "FAN Normal Temperature"
chip "dps460-i2c-11-5e"
label power1 "Input Power"
label power2 "Output Power"
label curr1 "Input Current"
label curr2 "Output Current"
label in1 "Input Voltage"
ignore in2
label in3 "Output Voltage"
label fan1 "Fan RPM"
ignore fan2
ignore fan3
ignore temp1
label temp2 "FAN Airflow Temperature"
label temp3 "FAN Normal Temperature"

View File

@ -0,0 +1,11 @@
{
"services_to_ignore": [],
"devices_to_ignore": ["fan.speed","psu.temperature","psu.voltage","asic"],
"user_defined_checkers": [],
"polling_interval": 60,
"led_color": {
"fault" : "blink_yellow",
"normal" : "green",
"booting": "blink_green"
}
}

View File

@ -20,6 +20,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(DELL_S6100_PLATFORM_MODULE) \
$(DELL_N3248PXE_PLATFORM_MODULE) \
$(DELL_N3248TE_PLATFORM_MODULE) \
$(DELL_E3224F_PLATFORM_MODULE) \
$(INGRASYS_S8900_54XC_PLATFORM_MODULE) \
$(INGRASYS_S8900_64XC_PLATFORM_MODULE) \
$(INGRASYS_S9100_PLATFORM_MODULE) \

View File

@ -13,6 +13,7 @@ DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5296F_PLATFORM_MODULE_VERSION = 1.1
DELL_N3248PXE_PLATFORM_MODULE_VERSION = 1.1
DELL_N3248TE_PLATFORM_MODULE_VERSION = 1.1
DELL_E3224F_PLATFORM_MODULE_VERSION = 1.1
export DELL_S6000_PLATFORM_MODULE_VERSION
export DELL_Z9100_PLATFORM_MODULE_VERSION
@ -27,6 +28,7 @@ export DELL_S5248F_PLATFORM_MODULE_VERSION
export DELL_S5296F_PLATFORM_MODULE_VERSION
export DELL_N3248PXE_PLATFORM_MODULE_VERSION
export DELL_N3248TE_PLATFORM_MODULE_VERSION
export DELL_E3224F_PLATFORM_MODULE_VERSION
DELL_Z9100_PLATFORM_MODULE = platform-modules-z9100_$(DELL_Z9100_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_Z9100_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-dell
@ -75,6 +77,10 @@ DELL_N3248TE_PLATFORM_MODULE = platform-modules-n3248te_$(DELL_N3248TE_PLATFORM_
$(DELL_N3248TE_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_n3248te_c3338-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_N3248TE_PLATFORM_MODULE)))
DELL_E3224F_PLATFORM_MODULE = platform-modules-e3224f_$(DELL_E3224F_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_E3224F_PLATFORM_MODULE)_PLATFORM = x86_64-dell_e3224f-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_E3224F_PLATFORM_MODULE)))
DELL_S5296F_PLATFORM_MODULE = platform-modules-s5296f_$(DELL_S5296F_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_S5296F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5296f_c3538-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5296F_PLATFORM_MODULE)))

View File

@ -65,6 +65,11 @@ Architecture: amd64
Depends: linux-image-5.10.0-18-2-amd64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-e3224f
Architecture: amd64
Depends: linux-image-5.10.0-18-2-amd64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-s5296f
Architecture: amd64
Depends: linux-image-5.10.0-18-2-amd64-unsigned

View File

@ -0,0 +1,39 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: setup-board
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Setup S3000 board.
### END INIT INFO
case "$1" in
start)
echo -n "Setting up board... "
/usr/local/bin/e3224f_platform.sh init
echo "done."
;;
stop)
/usr/local/bin/e3224f_platform.sh deinit
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-e3224f.init {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,12 @@
e3224f/scripts/e3224f_platform.sh usr/local/bin
e3224f/scripts/platform_sensors.py usr/local/bin
e3224f/scripts/sensors usr/bin
e3224f/scripts//portiocfg.py usr/local/bin
e3224f/scripts//ports_xcvrd_notify.py usr/local/bin
e3224f/systemd/platform-modules-e3224f.service etc/systemd/system
e3224f/cfg/e3224f-modules.conf etc/modules-load.d
common/dell_i2c_utils.sh usr/local/bin
e3224f/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dell_e3224f-r0
common/platform_reboot usr/share/sonic/device/x86_64-dell_e3224f-r0
common/fw-updater /usr/local/bin
common/onie_mode_set usr/local/bin

View File

@ -0,0 +1,7 @@
# postinst script for E3224F
# Enable Dell-E3224F-platform-service
depmod -a
systemctl enable platform-modules-e3224f.service
systemctl start platform-modules-e3224f.service
#DEBHELPER#

View File

@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5212f s5224f s5232f s5248f z9332f z9432f s5296f n3248pxe n3248te
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5212f s5224f s5232f s5248f z9332f z9432f s5296f n3248pxe n3248te e3224f
COMMON_DIR := common
%:
@ -85,6 +85,10 @@ 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 = "e3224f" ]; then \
cd $(MOD_SRC_DIR)/$${mod}; \
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
fi; \
echo "making man page alias $$mod -> $$mod APIs";\
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
@ -187,6 +191,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 = "e3224f" ]; 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; \
fi; \
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \
done); \

View File

@ -0,0 +1,14 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-isch
i2c-ismt
i2c-dev
i2c-mux
i2c-smbus
i2c-mux-pca954x
dell_e3224f_platform

View File

@ -0,0 +1,2 @@
obj-m := dell_e3224f_platform.o emc2305.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,425 @@
/*
* pmbus.h - Common defines and structures for PMBus devices
*
* Copyright (c) 2010, 2011 Ericsson AB.
* Copyright (c) 2012 Guenter Roeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef PMBUS_H
#define PMBUS_H
#include <linux/bitops.h>
#include <linux/regulator/driver.h>
/*
* Registers
*/
enum pmbus_regs {
PMBUS_PAGE = 0x00,
PMBUS_OPERATION = 0x01,
PMBUS_ON_OFF_CONFIG = 0x02,
PMBUS_CLEAR_FAULTS = 0x03,
PMBUS_PHASE = 0x04,
PMBUS_CAPABILITY = 0x19,
PMBUS_QUERY = 0x1A,
PMBUS_VOUT_MODE = 0x20,
PMBUS_VOUT_COMMAND = 0x21,
PMBUS_VOUT_TRIM = 0x22,
PMBUS_VOUT_CAL_OFFSET = 0x23,
PMBUS_VOUT_MAX = 0x24,
PMBUS_VOUT_MARGIN_HIGH = 0x25,
PMBUS_VOUT_MARGIN_LOW = 0x26,
PMBUS_VOUT_TRANSITION_RATE = 0x27,
PMBUS_VOUT_DROOP = 0x28,
PMBUS_VOUT_SCALE_LOOP = 0x29,
PMBUS_VOUT_SCALE_MONITOR = 0x2A,
PMBUS_COEFFICIENTS = 0x30,
PMBUS_POUT_MAX = 0x31,
PMBUS_FAN_CONFIG_12 = 0x3A,
PMBUS_FAN_COMMAND_1 = 0x3B,
PMBUS_FAN_COMMAND_2 = 0x3C,
PMBUS_FAN_CONFIG_34 = 0x3D,
PMBUS_FAN_COMMAND_3 = 0x3E,
PMBUS_FAN_COMMAND_4 = 0x3F,
PMBUS_VOUT_OV_FAULT_LIMIT = 0x40,
PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41,
PMBUS_VOUT_OV_WARN_LIMIT = 0x42,
PMBUS_VOUT_UV_WARN_LIMIT = 0x43,
PMBUS_VOUT_UV_FAULT_LIMIT = 0x44,
PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45,
PMBUS_IOUT_OC_FAULT_LIMIT = 0x46,
PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47,
PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48,
PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49,
PMBUS_IOUT_OC_WARN_LIMIT = 0x4A,
PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B,
PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C,
PMBUS_OT_FAULT_LIMIT = 0x4F,
PMBUS_OT_FAULT_RESPONSE = 0x50,
PMBUS_OT_WARN_LIMIT = 0x51,
PMBUS_UT_WARN_LIMIT = 0x52,
PMBUS_UT_FAULT_LIMIT = 0x53,
PMBUS_UT_FAULT_RESPONSE = 0x54,
PMBUS_VIN_OV_FAULT_LIMIT = 0x55,
PMBUS_VIN_OV_FAULT_RESPONSE = 0x56,
PMBUS_VIN_OV_WARN_LIMIT = 0x57,
PMBUS_VIN_UV_WARN_LIMIT = 0x58,
PMBUS_VIN_UV_FAULT_LIMIT = 0x59,
PMBUS_IIN_OC_FAULT_LIMIT = 0x5B,
PMBUS_IIN_OC_WARN_LIMIT = 0x5D,
PMBUS_POUT_OP_FAULT_LIMIT = 0x68,
PMBUS_POUT_OP_WARN_LIMIT = 0x6A,
PMBUS_PIN_OP_WARN_LIMIT = 0x6B,
PMBUS_STATUS_BYTE = 0x78,
PMBUS_STATUS_WORD = 0x79,
PMBUS_STATUS_VOUT = 0x7A,
PMBUS_STATUS_IOUT = 0x7B,
PMBUS_STATUS_INPUT = 0x7C,
PMBUS_STATUS_TEMPERATURE = 0x7D,
PMBUS_STATUS_CML = 0x7E,
PMBUS_STATUS_OTHER = 0x7F,
PMBUS_STATUS_MFR_SPECIFIC = 0x80,
PMBUS_STATUS_FAN_12 = 0x81,
PMBUS_STATUS_FAN_34 = 0x82,
PMBUS_READ_VIN = 0x88,
PMBUS_READ_IIN = 0x89,
PMBUS_READ_VCAP = 0x8A,
PMBUS_READ_VOUT = 0x8B,
PMBUS_READ_IOUT = 0x8C,
PMBUS_READ_TEMPERATURE_1 = 0x8D,
PMBUS_READ_TEMPERATURE_2 = 0x8E,
PMBUS_READ_TEMPERATURE_3 = 0x8F,
PMBUS_READ_FAN_SPEED_1 = 0x90,
PMBUS_READ_FAN_SPEED_2 = 0x91,
PMBUS_READ_FAN_SPEED_3 = 0x92,
PMBUS_READ_FAN_SPEED_4 = 0x93,
PMBUS_READ_DUTY_CYCLE = 0x94,
PMBUS_READ_FREQUENCY = 0x95,
PMBUS_READ_POUT = 0x96,
PMBUS_READ_PIN = 0x97,
PMBUS_REVISION = 0x98,
PMBUS_MFR_ID = 0x99,
PMBUS_MFR_MODEL = 0x9A,
PMBUS_MFR_REVISION = 0x9B,
PMBUS_MFR_LOCATION = 0x9C,
PMBUS_MFR_DATE = 0x9D,
PMBUS_MFR_SERIAL = 0x9E,
/*
* Virtual registers.
* Useful to support attributes which are not supported by standard PMBus
* registers but exist as manufacturer specific registers on individual chips.
* Must be mapped to real registers in device specific code.
*
* Semantics:
* Virtual registers are all word size.
* READ registers are read-only; writes are either ignored or return an error.
* RESET registers are read/write. Reading reset registers returns zero
* (used for detection), writing any value causes the associated history to be
* reset.
* Virtual registers have to be handled in device specific driver code. Chip
* driver code returns non-negative register values if a virtual register is
* supported, or a negative error code if not. The chip driver may return
* -ENODATA or any other error code in this case, though an error code other
* than -ENODATA is handled more efficiently and thus preferred. Either case,
* the calling PMBus core code will abort if the chip driver returns an error
* code when reading or writing virtual registers.
*/
PMBUS_VIRT_BASE = 0x100,
PMBUS_VIRT_READ_TEMP_AVG,
PMBUS_VIRT_READ_TEMP_MIN,
PMBUS_VIRT_READ_TEMP_MAX,
PMBUS_VIRT_RESET_TEMP_HISTORY,
PMBUS_VIRT_READ_VIN_AVG,
PMBUS_VIRT_READ_VIN_MIN,
PMBUS_VIRT_READ_VIN_MAX,
PMBUS_VIRT_RESET_VIN_HISTORY,
PMBUS_VIRT_READ_IIN_AVG,
PMBUS_VIRT_READ_IIN_MIN,
PMBUS_VIRT_READ_IIN_MAX,
PMBUS_VIRT_RESET_IIN_HISTORY,
PMBUS_VIRT_READ_PIN_AVG,
PMBUS_VIRT_READ_PIN_MIN,
PMBUS_VIRT_READ_PIN_MAX,
PMBUS_VIRT_RESET_PIN_HISTORY,
PMBUS_VIRT_READ_POUT_AVG,
PMBUS_VIRT_READ_POUT_MIN,
PMBUS_VIRT_READ_POUT_MAX,
PMBUS_VIRT_RESET_POUT_HISTORY,
PMBUS_VIRT_READ_VOUT_AVG,
PMBUS_VIRT_READ_VOUT_MIN,
PMBUS_VIRT_READ_VOUT_MAX,
PMBUS_VIRT_RESET_VOUT_HISTORY,
PMBUS_VIRT_READ_IOUT_AVG,
PMBUS_VIRT_READ_IOUT_MIN,
PMBUS_VIRT_READ_IOUT_MAX,
PMBUS_VIRT_RESET_IOUT_HISTORY,
PMBUS_VIRT_READ_TEMP2_AVG,
PMBUS_VIRT_READ_TEMP2_MIN,
PMBUS_VIRT_READ_TEMP2_MAX,
PMBUS_VIRT_RESET_TEMP2_HISTORY,
PMBUS_VIRT_READ_VMON,
PMBUS_VIRT_VMON_UV_WARN_LIMIT,
PMBUS_VIRT_VMON_OV_WARN_LIMIT,
PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
PMBUS_VIRT_VMON_OV_FAULT_LIMIT,
PMBUS_VIRT_STATUS_VMON,
};
/*
* OPERATION
*/
#define PB_OPERATION_CONTROL_ON BIT(7)
/*
* CAPABILITY
*/
#define PB_CAPABILITY_SMBALERT BIT(4)
#define PB_CAPABILITY_ERROR_CHECK BIT(7)
/*
* VOUT_MODE
*/
#define PB_VOUT_MODE_MODE_MASK 0xe0
#define PB_VOUT_MODE_PARAM_MASK 0x1f
#define PB_VOUT_MODE_LINEAR 0x00
#define PB_VOUT_MODE_VID 0x20
#define PB_VOUT_MODE_DIRECT 0x40
/*
* Fan configuration
*/
#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1))
#define PB_FAN_2_RPM BIT(2)
#define PB_FAN_2_INSTALLED BIT(3)
#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5))
#define PB_FAN_1_RPM BIT(6)
#define PB_FAN_1_INSTALLED BIT(7)
/*
* STATUS_BYTE, STATUS_WORD (lower)
*/
#define PB_STATUS_NONE_ABOVE BIT(0)
#define PB_STATUS_CML BIT(1)
#define PB_STATUS_TEMPERATURE BIT(2)
#define PB_STATUS_VIN_UV BIT(3)
#define PB_STATUS_IOUT_OC BIT(4)
#define PB_STATUS_VOUT_OV BIT(5)
#define PB_STATUS_OFF BIT(6)
#define PB_STATUS_BUSY BIT(7)
/*
* STATUS_WORD (upper)
*/
#define PB_STATUS_UNKNOWN BIT(8)
#define PB_STATUS_OTHER BIT(9)
#define PB_STATUS_FANS BIT(10)
#define PB_STATUS_POWER_GOOD_N BIT(11)
#define PB_STATUS_WORD_MFR BIT(12)
#define PB_STATUS_INPUT BIT(13)
#define PB_STATUS_IOUT_POUT BIT(14)
#define PB_STATUS_VOUT BIT(15)
/*
* STATUS_IOUT
*/
#define PB_POUT_OP_WARNING BIT(0)
#define PB_POUT_OP_FAULT BIT(1)
#define PB_POWER_LIMITING BIT(2)
#define PB_CURRENT_SHARE_FAULT BIT(3)
#define PB_IOUT_UC_FAULT BIT(4)
#define PB_IOUT_OC_WARNING BIT(5)
#define PB_IOUT_OC_LV_FAULT BIT(6)
#define PB_IOUT_OC_FAULT BIT(7)
/*
* STATUS_VOUT, STATUS_INPUT
*/
#define PB_VOLTAGE_UV_FAULT BIT(4)
#define PB_VOLTAGE_UV_WARNING BIT(5)
#define PB_VOLTAGE_OV_WARNING BIT(6)
#define PB_VOLTAGE_OV_FAULT BIT(7)
/*
* STATUS_INPUT
*/
#define PB_PIN_OP_WARNING BIT(0)
#define PB_IIN_OC_WARNING BIT(1)
#define PB_IIN_OC_FAULT BIT(2)
/*
* STATUS_TEMPERATURE
*/
#define PB_TEMP_UT_FAULT BIT(4)
#define PB_TEMP_UT_WARNING BIT(5)
#define PB_TEMP_OT_WARNING BIT(6)
#define PB_TEMP_OT_FAULT BIT(7)
/*
* STATUS_FAN
*/
#define PB_FAN_AIRFLOW_WARNING BIT(0)
#define PB_FAN_AIRFLOW_FAULT BIT(1)
#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2)
#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3)
#define PB_FAN_FAN2_WARNING BIT(4)
#define PB_FAN_FAN1_WARNING BIT(5)
#define PB_FAN_FAN2_FAULT BIT(6)
#define PB_FAN_FAN1_FAULT BIT(7)
/*
* CML_FAULT_STATUS
*/
#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0)
#define PB_CML_FAULT_OTHER_COMM BIT(1)
#define PB_CML_FAULT_PROCESSOR BIT(3)
#define PB_CML_FAULT_MEMORY BIT(4)
#define PB_CML_FAULT_PACKET_ERROR BIT(5)
#define PB_CML_FAULT_INVALID_DATA BIT(6)
#define PB_CML_FAULT_INVALID_COMMAND BIT(7)
enum pmbus_sensor_classes {
PSC_VOLTAGE_IN = 0,
PSC_VOLTAGE_OUT,
PSC_CURRENT_IN,
PSC_CURRENT_OUT,
PSC_POWER,
PSC_TEMPERATURE,
PSC_FAN,
PSC_NUM_CLASSES /* Number of power sensor classes */
};
#define PMBUS_PAGES 32 /* Per PMBus specification */
/* Functionality bit mask */
#define PMBUS_HAVE_VIN BIT(0)
#define PMBUS_HAVE_VCAP BIT(1)
#define PMBUS_HAVE_VOUT BIT(2)
#define PMBUS_HAVE_IIN BIT(3)
#define PMBUS_HAVE_IOUT BIT(4)
#define PMBUS_HAVE_PIN BIT(5)
#define PMBUS_HAVE_POUT BIT(6)
#define PMBUS_HAVE_FAN12 BIT(7)
#define PMBUS_HAVE_FAN34 BIT(8)
#define PMBUS_HAVE_TEMP BIT(9)
#define PMBUS_HAVE_TEMP2 BIT(10)
#define PMBUS_HAVE_TEMP3 BIT(11)
#define PMBUS_HAVE_STATUS_VOUT BIT(12)
#define PMBUS_HAVE_STATUS_IOUT BIT(13)
#define PMBUS_HAVE_STATUS_INPUT BIT(14)
#define PMBUS_HAVE_STATUS_TEMP BIT(15)
#define PMBUS_HAVE_STATUS_FAN12 BIT(16)
#define PMBUS_HAVE_STATUS_FAN34 BIT(17)
#define PMBUS_HAVE_VMON BIT(18)
#define PMBUS_HAVE_STATUS_VMON BIT(19)
enum pmbus_data_format { linear = 0, direct, vid };
enum vrm_version { vr11 = 0, vr12 };
struct pmbus_driver_info {
int pages; /* Total number of pages */
enum pmbus_data_format format[PSC_NUM_CLASSES];
enum vrm_version vrm_version;
/*
* Support one set of coefficients for each sensor type
* Used for chips providing data in direct mode.
*/
int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */
int b[PSC_NUM_CLASSES]; /* offset */
int R[PSC_NUM_CLASSES]; /* exponent */
u32 func[PMBUS_PAGES]; /* Functionality, per page */
/*
* The following functions map manufacturing specific register values
* to PMBus standard register values. Specify only if mapping is
* necessary.
* Functions return the register value (read) or zero (write) if
* successful. A return value of -ENODATA indicates that there is no
* manufacturer specific register, but that a standard PMBus register
* may exist. Any other negative return value indicates that the
* register does not exist, and that no attempt should be made to read
* the standard register.
*/
int (*read_byte_data)(struct i2c_client *client, int page, int reg);
int (*read_word_data)(struct i2c_client *client, int page, int reg);
int (*write_word_data)(struct i2c_client *client, int page, int reg,
u16 word);
int (*write_byte)(struct i2c_client *client, int page, u8 value);
/*
* The identify function determines supported PMBus functionality.
* This function is only necessary if a chip driver supports multiple
* chips, and the chip functionality is not pre-determined.
*/
int (*identify)(struct i2c_client *client,
struct pmbus_driver_info *info);
/* Regulator functionality, if supported by this chip driver. */
int num_regulators;
const struct regulator_desc *reg_desc;
};
/* Regulator ops */
extern const struct regulator_ops pmbus_regulator_ops;
/* Macro for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR(_name, _id) \
[_id] = { \
.name = (_name # _id), \
.id = (_id), \
.of_match = of_match_ptr(_name # _id), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &pmbus_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
int pmbus_set_page(struct i2c_client *client, u8 page);
int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
u8 value);
int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
u8 mask, u8 value);
void pmbus_clear_faults(struct i2c_client *client);
bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info);
int pmbus_do_remove(struct i2c_client *client);
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
*client);
#endif /* PMBUS_H */

View File

@ -0,0 +1,174 @@
#!/bin/bash
#platform init script for Dell E3224F
source dell_i2c_utils.sh
SONIC_VERSION=$(cat /etc/sonic/sonic_version.yml | grep "build_version" | sed -e "s/build_version: //g;s/'//g")
FIRST_BOOT_FILE="/host/image-${SONIC_VERSION}/platform/firsttime"
#Attach/Detach the system devices
sys_devices() {
case $1 in
"new_device") #syseeprom
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-2/$1"
#Attach Fan Controller
i2c_config "echo emc2305 0x2c > /sys/bus/i2c/devices/i2c-7/$1"
#Attach temperature monitor
i2c_config "echo tmp75 0x48 > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo tmp75 0x49 > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo tmp75 0x4a > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo tmp75 0x4b > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo tmp75 0x4c > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo tmp75 0x4f > /sys/bus/i2c/devices/i2c-7/$1"
#Attach Fan EEPROM
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-15/$1"
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-16/$1"
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-17/$1"
;;
"delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-2/$1"
i2c_config "echo 0x2c > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x48 > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x49 > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x4a > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x4b > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x4c > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x4f > /sys/bus/i2c/devices/i2c-7/$1"
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-15/$1"
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-16/$1"
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-17/$1"
;;
*) echo "e3224f_platform: main_board_mux : invalid command !"
;;
esac
}
#Attach/Detach the SFP modules on PCA9548_2
switch_board_sfp() {
case $1 in
"new_device")
# SFP ports
for ((i=27;i<=50;i++));
do
i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1"
done
# SFP+ ports
for ((i=20;i<=23;i++));
do
i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1"
done
# QSFP ports
i2c_config "echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-24/$1"
i2c_config "echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-25/$1"
;;
"delete_device")
for ((i=20;i<=50;i++));
do
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1"
done
;;
"media_down")
for ((i=20;i<=23;i++));
do
# Tx disable for 10G BaseT copper optics
eeprom=/sys/bus/i2c/devices/i2c-$i/$i-0050/eeprom
# Gen2 or Gen3 copper optics
# Check for F10 encoding (starts with '0f10' or 'df10') at offset 96 and 7 byte size
# and then compare the 'product id' but skip other part of F10 string
f10_encoding=`hexdump -n7 -s96 $eeprom -e'7/1 "%02x"' 2>&1`
if [[ $f10_encoding =~ ^[0d]f10....28....|^[0d]f10....29.... ]]; then
cmd="\x01\x00\x09\x00\x01\x02"
echo -n -e $cmd | dd bs=1 count=6 of=$eeprom seek=506 obs=1 status=none
fi
done
;;
*) echo "e3224f_platform: switch_board_sfp: invalid command !"
;;
esac
}
#Forcibly bring quad-port phy out of reset for 48-1G port functionality
platform_firmware_versions() {
FIRMWARE_VERSION_FILE=/var/log/firmware_versions
rm -rf ${FIRMWARE_VERSION_FILE}
# Get BIOS version
echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE
# Get CPU CPLD version
echo "CPU CPLD: $((`cat /sys/devices/platform/dell-e3224f-cpld.0/cpu_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-e3224f-cpld.0/cpu_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE
# Get SYS CPLD version
echo "SYS CPLD: $((`cat /sys/devices/platform/dell-e3224f-cpld.0/sys_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-e3224f-cpld.0/sys_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE
# Get PORT CPLD version
echo "PORT CPLD: $((`cat /sys/devices/platform/dell-e3224f-cpld.0/port_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-e3224f-cpld.0/port_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE
}
install_python_api_package() {
device="/usr/share/sonic/device"
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl
}
remove_python_api_package() {
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
if [ $? -eq 0 ]; then
rv=$(pip3 uninstall -y sonic-platform > /dev/null 2>/dev/null)
fi
}
get_reboot_cause() {
REBOOT_REASON_FILE="/host/reboot-cause/platform/reboot_reason"
mkdir -p $(dirname $REBOOT_REASON_FILE)
# Handle First Boot into software version with reboot cause determination support
if [[ ! -e $REBOOT_REASON_FILE ]]; then
echo "0x0" > $REBOOT_REASON_FILE
else
cat /sys/devices/platform/dell-e3224f-cpld.0/reboot_cause > $REBOOT_REASON_FILE
fi
echo "0x0" > /sys/devices/platform/dell-e3224f-cpld.0/reboot_cause
}
if [[ "$1" == "init" ]]; then
if [ -f $FIRST_BOOT_FILE ]; then
systemctl enable system-health.service
systemctl start --no-block system-health.service
fi
modprobe i2c-dev
modprobe i2c-mux-pca954x
modprobe pmbus
modprobe emc2305
modprobe dell_e3224f_platform
sys_devices "new_device"
get_reboot_cause
switch_board_sfp "new_device"
switch_board_sfp "media_down"
echo 0x00 > /sys/devices/platform/dell-e3224f-cpld.0/sfp_txdis
echo 0xf0 > /sys/devices/platform/dell-e3224f-cpld.0/sfpplus_txdis
echo 0xf3 > /sys/devices/platform/dell-e3224f-cpld.0/qsfp_rst
echo 0x00 > /sys/devices/platform/dell-e3224f-cpld.0/qsfp_lpmode
install_python_api_package
platform_firmware_versions
elif [[ "$1" == "deinit" ]]; then
switch_board_sfp "media_down"
switch_board_sfp "delete_device"
sys_devices "delete_device"
modprobe -r dell_e3224f_platform
modprobe -r emc2305
modprobe -r pmbus
modprobe -r i2c-mux-pca954x
modprobe -r i2c-dev
remove_python_api_package
elif [ "$1" == "media_down" ]; then
switch_board_sfp $1
else
echo "e3224f_platform : Invalid option !"
fi

View File

@ -0,0 +1,27 @@
#!/bin/bash
init_devnum() {
found=0
for devnum in 0 1; do
devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name`
# iSMT adapter can be at dff5c000
echo $devname
if [[ "$devname" == 'SMBus iSMT adapter at '* ]] ; then
found=1
break
fi
done
[ $found -eq 0 ] && echo "cannot find iSMT" && exit 0
}
init_devnum
while [ 1 ]
do
if [ ! -f /sys/class/i2c-adapter/i2c-${devnum}/${devnum}-0071/idle_state ]; then
sleep 1
continue
fi
echo -2 > /sys/class/i2c-adapter/i2c-${devnum}/${devnum}-0071/idle_state
break
done

View File

@ -0,0 +1,6 @@
#!/bin/bash
function platform-modules-e3224fServicePreStop()
{
/usr/local/bin/e3224f_platform.sh media_down
}

View File

@ -0,0 +1,162 @@
#!/usr/bin/python3
"""
This provides support for the following objects:
* Onboard temperature sensors
* FAN trays
* PSU
"""
import subprocess
output = ""
try:
rc = 0
output = subprocess.check_output('/usr/bin/sensors', stderr=subprocess.STDOUT, \
encoding="utf-8").splitlines()
valid = False
for line in output:
if line.startswith('acpitz') or line.startswith('coretemp'):
valid = True
if valid:
print(line)
if line == '':
valid = False
print("Onboard Temperature Sensors:")
idx = 0
for line in output:
if line.startswith('tmp75'):
print('\t' + output[idx+2].split('(')[0])
idx += 1
print("\nFan Trays:")
idx = 0
found_emc = False
fan_status = [' Normal', ' Abnormal']
for line in output:
if line.startswith('emc'):
found_emc = True
with open('/sys/devices/platform/dell-e3224f-cpld.0/fan0_prs') as f:
line = f.readline()
present = int(line, 0)
if present:
print('\t' + 'Fan Tray 1:')
with open('/sys/bus/i2c/devices/7-002c/fan1_fault') as f:
line = f.readline()
status = int(line, 0)
print('\t\t' + 'Fan State:' + fan_status[status])
print('\t\t' + 'Fan Speed:' + (output[idx+2].split('(')[0]).split(':')[1])
with open('/sys/devices/platform/dell-e3224f-cpld.0/fan0_dir') as f:
line = f.readline()
direction = 'Intake' if line[:-1] == 'B2F' else 'Exhaust'
print('\t\t' + 'Airflow:\t' + direction)
else:
print('\t' + 'Fan Tray 1:\tNot Present')
with open('/sys/devices/platform/dell-e3224f-cpld.0/fan1_prs') as f:
line = f.readline()
present = int(line, 0)
if present:
print('\t' + 'Fan Tray 2:')
with open('/sys/bus/i2c/devices/7-002c/fan2_fault') as f:
line = f.readline()
status = int(line, 0)
print('\t\t' + 'Fan State:' + fan_status[status])
print('\t\t' + 'Fan Speed:' + (output[idx+3].split('(')[0]).split(':')[1])
with open('/sys/devices/platform/dell-e3224f-cpld.0/fan1_dir') as f:
line = f.readline()
direction = 'Intake' if line[:-1] == 'B2F' else 'Exhaust'
print('\t\t' + 'Airflow:\t' + direction)
else:
print('\t' + 'Fan Tray 2:\tNot Present')
with open('/sys/devices/platform/dell-e3224f-cpld.0/fan2_prs') as f:
line = f.readline()
present = int(line, 0)
if present:
print('\t' + 'Fan Tray 3:')
with open('/sys/bus/i2c/devices/7-002c/fan3_fault') as f:
line = f.readline()
status = int(line, 0)
print('\t\t' + 'Fan State:' + fan_status[status])
print('\t\t' + 'Fan Speed:' + (output[idx+4].split('(')[0]).split(':')[1])
with open('/sys/devices/platform/dell-e3224f-cpld.0/fan2_dir') as f:
line = f.readline()
direction = 'Intake' if line[:-1] == 'B2F' else 'Exhaust'
print('\t\t' + 'Airflow:\t' + direction)
else:
print('\t' + 'Fan Tray 3:\tNot Present')
idx += 1
if not found_emc:
print('\t' + 'Fan Tray 1:\tNot Present')
print('\t' + 'Fan Tray 2:\tNot Present')
print('\t' + 'Fan Tray 3:\tNot Present')
print('\nPSUs:')
idx = 0
with open('/sys/devices/platform/dell-e3224f-cpld.0/psu0_prs') as f:
line = f.readline()
found_psu1 = int(line, 0)
if not found_psu1:
print('\tPSU1:\tNot Present')
else:
for line in output:
if line.startswith('dps460-i2c-10'):
with open('/sys/devices/platform/dell-e3224f-cpld.0/psu0_status') as f:
line = f.readline()
status = int(line, 0)
if not status:
print('\tPSU1:\tNot OK')
break
with open('/sys/bus/i2c/devices/10-0056/eeprom', encoding="ISO-8859-1") as f:
line = f.readline()
direction = 'Exhaust' if 'FORWARD' in line else 'Intake'
print('\tPSU1:')
print('\t\t' + output[idx+2].split('(')[0])
print('\t\t' + output[idx+4].split('(')[0])
print('\t\t' + output[idx+6].split('(')[0])
print('\t\t' + output[idx+7].split('(')[0])
print('\t\t' + output[idx+9].split('(')[0])
print('\t\t' + output[idx+11].split('(')[0])
print('\t\t' + output[idx+13].split('(')[0])
print('\t\t' + output[idx+14].split('(')[0])
print('\t\t' + output[idx+16].split('(')[0])
print('\t\t' + output[idx+17].split('(')[0])
print('\t\t' + 'Airflow:\t\t ' + direction)
idx += 1
idx = 0
with open('/sys/devices/platform/dell-e3224f-cpld.0/psu1_prs') as f:
line = f.readline()
found_psu2 = int(line, 0)
if not found_psu2:
print('\tPSU2:\tNot Present')
else:
for line in output:
if line.startswith('dps460-i2c-11'):
with open('/sys/devices/platform/dell-e3224f-cpld.0/psu1_status') as f:
line = f.readline()
status = int(line, 0)
if not status:
print('\tPSU2:\tNot OK')
break
print('\tPSU2:')
with open('/sys/bus/i2c/devices/11-0056/eeprom', encoding="ISO-8859-1") as f:
line = f.readline()
direction = 'Exhaust' if 'FORWARD' in line else 'Intake'
print('\t\t' + output[idx+2].split('(')[0])
print('\t\t' + output[idx+4].split('(')[0])
print('\t\t' + output[idx+6].split('(')[0])
print('\t\t' + output[idx+7].split('(')[0])
print('\t\t' + output[idx+9].split('(')[0])
print('\t\t' + output[idx+11].split('(')[0])
print('\t\t' + output[idx+13].split('(')[0])
print('\t\t' + output[idx+14].split('(')[0])
print('\t\t' + output[idx+16].split('(')[0])
print('\t\t' + output[idx+17].split('(')[0])
print('\t\t' + 'Airflow:\t\t ' + direction)
idx += 1
except subprocess.CalledProcessError as err:
print("Exception when calling get_sonic_error -> %s\n" %(err))
rc = err.returncode

View File

@ -0,0 +1,105 @@
#!/usr/bin/python3
# Copyright (c) 2015 Dell Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
#
# See the Apache Version 2.0 License for specific language governing
# permissions and limitations under the License.
#Script to read/write the portio based registers
import sys
import os
import getopt
import struct
resource = '/dev/port'
def usage():
''' This is the Usage Method '''
print('\t\t portiocfg.py --default')
print('\t\t portiocfg.py --get --offset <offset>')
print('\t\t portiocfg.py --set --val <val> --offset <offset>')
sys.exit(1)
def portio_reg_read(resource, offset):
fd = os.open(resource, os.O_RDONLY)
if fd < 0:
print('file open failed %s"%resource')
return
if os.lseek(fd, offset, os.SEEK_SET) != offset:
print('lseek failed on %s'%resource)
return
buf = os.read(fd, 1)
reg_val1 = ord(buf)
print('reg value %x'%reg_val1)
os.close(fd)
def portio_reg_write(resource, offset, val):
fd = os.open(resource, os.O_RDWR)
if fd < 0:
print('file open failed %s"%resource')
return
if os.lseek(fd, offset, os.SEEK_SET) != offset:
print('lseek failed on %s'%resource)
return
ret = os.write(fd, struct.pack('B', val))
if ret != 1:
print('write failed %d'%ret)
return
os.close(fd)
def main(argv):
''' The main function will read the user input from the
command line argument and process the request '''
opts = ''
val = ''
choice = ''
resource = ''
offset = ''
try:
opts, args = getopt.getopt(argv, "hgs:", \
["val=", "offset=", "help", "get", "set"])
except getopt.GetoptError:
usage()
for opt, arg in opts:
if opt in ('-h', '--help'):
choice = 'help'
elif opt in ('-g', '--get'):
choice = 'get'
elif opt in ('-s', '--set'):
choice = 'set'
elif opt == '--offset':
offset = int(arg, 16)
elif opt == '--val':
val = int(arg, 16)
if choice == 'get' and offset != '':
portio_reg_read(resource, offset)
elif choice == 'set' and offset != '' and val != '':
portio_reg_write(resource, offset, val)
else:
usage()
#Calling the main method
if __name__ == "__main__":
main(sys.argv[1:])

View File

@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
port_notify
port notify status change for SONiC
"""
try:
from datetime import datetime
from swsscommon import swsscommon
from sonic_py_common import daemon_base, logger
except ImportError as e:
raise ImportError (str(e) + " - required module not found")
#
# Constants ====================================================================
#
SYSLOG_IDENTIFIER = "port_notify"
STATE_PORT_TABLE = 'PORT_TABLE'
RJ45_PORT_START = 0;
RJ45_PORT_END = 47;
# Global logger class instance
helper_logger = logger.Logger(SYSLOG_IDENTIFIER)
XCVR_STATE_EMPTY = 0
XCVR_STATE_ERROR = 1
XCVR_STATE_INCOMP = 2
XCVR_STATE_CONFIG = 3
XCVR_STATE_READY = 4
XCVR_STATE_TIMEOUT = 5
xcvr_state_tbl = {
XCVR_STATE_EMPTY: { "xcvr_state": "N/A", "xcvr_app_status": "down" },
XCVR_STATE_ERROR: { "xcvr_state": "Error", "xcvr_app_status": "down" },
XCVR_STATE_INCOMP: { "xcvr_state": "Incompatible", "xcvr_app_status": "up" },
XCVR_STATE_CONFIG: { "xcvr_state": "Config", "xcvr_app_status": "down" },
XCVR_STATE_TIMEOUT: { "xcvr_state": "Timeout", "xcvr_app_status": "up" },
XCVR_STATE_READY: { "xcvr_state": "Ready", "xcvr_app_status": "up" }
}
# Wait for port init is done
def wait_for_port_init_done():
# Connect to APPL_DB and subscribe to PORT table notifications
appl_db = daemon_base.db_connect("APPL_DB")
sel = swsscommon.Select()
sst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME)
sel.addSelectable(sst)
# Make sure this daemon started after all port configured
while True:
(state, c) = sel.select(1000)
if state == swsscommon.Select.TIMEOUT:
continue
if state != swsscommon.Select.OBJECT:
helper_logger.log_warning("sel.select() did not return swsscommon.Select.OBJECT")
continue
(key, op, fvp) = sst.pop()
# Wait until PortInitDone
if key in ["PortInitDone"]:
break
def notify_port_xcvr_status(port_name, app_status_port_tbl, state_port_tbl, flag):
fvs = swsscommon.FieldValuePairs([("xcvr_status", xcvr_state_tbl[flag]["xcvr_app_status"])])
tm = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
state_fvs = swsscommon.FieldValuePairs([("xcvr_status", xcvr_state_tbl[flag]["xcvr_state"]), ("xcvr_time", tm)])
state_port_tbl.set(port_name, state_fvs)
app_status_port_tbl.set(port_name, fvs)
helper_logger.log_notice("Port {} xcvr_app_status change to {}".format(port_name, xcvr_state_tbl[flag]["xcvr_app_status"]))
return True
def main():
helper_logger.log_notice("Start port_notify")
# Connect to APP_DB and create transceiver dom info table
appl_db = daemon_base.db_connect("APPL_DB")
app_status_port_tbl = swsscommon.ProducerStateTable(appl_db,
swsscommon.APP_PORT_APP_STATUS_TABLE_NAME)
state_db = daemon_base.db_connect("STATE_DB")
state_port_tbl = swsscommon.Table(state_db, STATE_PORT_TABLE)
# Wait for PortInitDone
wait_for_port_init_done()
for port in range(RJ45_PORT_START, RJ45_PORT_END+1):
#print("Ethernet{}".format(port))
notify_port_xcvr_status("Ethernet{}".format(port), app_status_port_tbl, state_port_tbl, XCVR_STATE_READY)
helper_logger.log_notice("End port_notify")
if __name__ == '__main__':
main()

View File

@ -0,0 +1,8 @@
#!/bin/bash
#docker exec -i pmon sensors "$@"
docker exec -i pmon /usr/bin/platform_sensors.py "$@"
#To probe sensors not part of lm-sensors
#if [ -r /usr/local/bin/platform_sensors.py ]; then
# python /usr/local/bin/platform_sensors.py
#fi

View File

@ -0,0 +1 @@
../s6100/setup.py

View File

@ -0,0 +1,8 @@
"""
Module sonic_platform provides the platform dependent population of
platform.py, chassis.py, component.py, sfp.py, thermal.py, psu.py,
fan.py and watchdog.py
"""
__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"]
from sonic_platform import *

View File

@ -0,0 +1,442 @@
#!/usr/bin/env python
#############################################################################
# DELLEMC E3224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import os
import sys
import time
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
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
MAX_E3224F_FANTRAY = 3
MAX_E3224F_FAN = 1
MAX_E3224F_PSU = 2
MAX_E3224F_THERMAL = 5
MAX_E3224F_COMPONENT = 3 # BIOS, CPU CPLD and SYS CPLD
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"
CPLD_DIR = '/sys/devices/platform/dell-e3224f-cpld.0/'
_global_port_pres_dict = {}
_sfpp_port_to_i2c_mapping = {
25: 20,
26: 21,
27: 22,
28: 23,
29: 24,
30: 25,
1: 27,
2: 28,
3: 29,
4: 30,
5: 31,
6: 32,
7: 33,
8: 34,
9: 35,
10: 36,
11: 37,
12: 38,
13: 39,
14: 40,
15: 41,
16: 42,
17: 43,
18: 44,
19: 45,
20: 46,
21: 47,
22: 48,
23: 49,
24: 50,
}
SYSTEM_LED_COLORS = {
"green",
"blink_green",
"yellow",
"blink_yellow"
}
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 = 30
self.PORTS_IN_BLOCK = (self.PORT_END + 1)
self.SFP_PORT_START = 1
self._sfp_port = range(self.SFP_PORT_START, self.PORTS_IN_BLOCK)
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for index in range(self.PORT_START, self.PORTS_IN_BLOCK):
eeprom_path = ''
if index in self._sfp_port:
eeprom_path = eeprom_base.format(self._sfpp_port_to_i2c_mapping[index])
if(index < 29):
port_type = 'SFP'
else:
port_type = 'QSFP'
sfp_node = Sfp(index, port_type, eeprom_path)
self._sfp_list.append(sfp_node)
self._eeprom = Eeprom()
self._watchdog = Watchdog()
self._num_sfps = 30
self._num_fans = MAX_E3224F_FANTRAY * MAX_E3224F_FAN
for k in range(MAX_E3224F_FANTRAY):
fandrawer = FanDrawer(k)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
self._psu_list = [Psu(i) for i in range(MAX_E3224F_PSU)]
self._thermal_list = [Thermal(i) for i in range(MAX_E3224F_THERMAL)]
self._component_list = [Component(i) for i in range(MAX_E3224F_COMPONENT)]
for port_num in self._sfp_port:
# sfp get uses zero-indexing, but port numbers start from 1
presence = self.get_sfp(port_num-1).get_presence()
self._global_port_pres_dict[port_num] = '1' if presence else '0'
self._watchdog = Watchdog()
self.status_led_reg = "system_led"
self.locator_led_reg = "locator_led"
self.LOCATOR_LED_ON = "blink_blue"
self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_reg_file = self.CPLD_DIR + '/' + reg_name
try:
with open(cpld_reg_file, 'r') as fd:
rv = fd.read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# reg_name and on failure returns 'ERR'
rv = 'ERR'
cpld_reg_file = self.CPLD_DIR + '/' + reg_name
if (not os.path.isfile(cpld_reg_file)):
return rv
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception:
rv = 'ERR'
return rv
def get_status_led(self):
"""
Gets the current system LED color
Returns:
A string that represents the supported color
"""
color = self._get_cpld_register(self.status_led_reg)
if color not in list(self.SYSTEM_LED_COLORS):
return self.sys_ledcolor
return color
def initizalize_system_led(self):
self.sys_ledcolor = "green"
def set_status_led(self,color):
"""
Set system LED status based on the color type passed in the argument.
Argument: Color to be set
Returns:
bool: True is specified color is set, Otherwise return False
"""
if color not in list(self.SYSTEM_LED_COLORS):
return False
if(not self._set_cpld_register(self.status_led_reg, color)):
return False
self.sys_ledcolor = color
return True
# 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
"""
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
while True:
for port_num in self._sfp_port:
# sfp get uses zero-indexing, but port numbers start from 1
presence = self.get_sfp(port_num-1).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
time.sleep(0.5)
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 will start from 0
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 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_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:
reset_reason = int(fd.read(), 16)
except:
return(ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
if (reset_reason & 0x02) :
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Shutdown by CPU')
elif (reset_reason & 0x04) :
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Failed to boot from configured boot device")
elif (reset_reason & 0x8) :
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Booted from Backup BIOS")
elif (reset_reason & 0x10) :
return(ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif (reset_reason & 0x20):
return(ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU)
elif (reset_reason & 0x40) :
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Warm Reset')
elif (reset_reason & 0x80) :
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Cold Reset')
elif (reset_reason & 0x01) :
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
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_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
"""
if color == self.LOCATOR_LED_ON or color == self.LOCATOR_LED_OFF:
rv = self._set_cpld_register(self.locator_led_reg, color)
if (rv != 'ERR'):
return True
else:
return False
def get_locator_led(self):
"""
Gets the state of the Chassis Locator LED
Returns:
LOCATOR_LED_ON or LOCATOR_LED_OFF
"""
loc_led = self._get_cpld_register(self.locator_led_reg)
if (loc_led != 'ERR'):
# Actually driver returns the color code 'blink_blue'
# Returning "blue_blink" to make it common to all platforms output
if (loc_led == self.LOCATOR_LED_ON):
self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK
return self.LOCATOR_LED_ON
else:
return self.LOCATOR_LED_OFF
else:
return self.LOCATOR_LED_OFF
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
def get_revision(self):
"""
Retrives the hardware revision of the device
Returns:
string: Revision value of device
"""
return self._eeprom.revision_str()

View File

@ -0,0 +1,137 @@
#!/usr/bin/env python
########################################################################
# DELLEMC E3224F
#
# 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
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
def get_bios_version():
return subprocess.check_output(['dmidecode', '-s', 'system-version']).strip().decode()
def get_cpld_version(cpld):
mjr_ver_path = '/sys/devices/platform/dell-e3224f-cpld.0/' + cpld + '_mjr_ver'
mnr_ver_path = '/sys/devices/platform/dell-e3224f-cpld.0/' + cpld + '_mnr_ver'
mjr_ver = subprocess.check_output(['cat', mjr_ver_path]).strip()[2:].decode()
mnr_ver = subprocess.check_output(['cat', mnr_ver_path]).strip()[2:].decode()
return (str(mjr_ver) + '.' + str(mnr_ver))
class Component(ComponentBase):
"""DellEMC Platform-specific Component class"""
CHASSIS_COMPONENTS = [
['BIOS',
'Performs initialization of hardware components during booting',
get_bios_version()
],
['CPU CPLD',
'Used for managing the CPU power sequence and CPU states',
get_cpld_version('cpu_cpld')
],
['SYS CPLD',
'Used for managing FAN, PSU, SFP+ modules (25-28) and QSFP modules (29-30)',
get_cpld_version('sys_cpld')
],
['PORT CPLD',
'Used for managing SFP modules (1-24)',
get_cpld_version('port_cpld')
]
]
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 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_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

View File

@ -0,0 +1,131 @@
#!/usr/bin/env python
#############################################################################
# DellEmc E3224F
#
# 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
f = '/sys/class/i2c-adapter/i2c-2/2-0050/eeprom'
if not os.path.exists(f):
return
self.eeprom_path = f
super(Eeprom, self).__init__(self.eeprom_path, 0, '', True)
self.eeprom_tlv_dict = dict()
try:
self.eeprom_data = self.read_eeprom()
except Exception:
self.eeprom_data = "N/A"
raise RuntimeError("Eeprom is not Programmed")
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, e):
"""
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_DEVICE_VERSION)
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

View File

@ -0,0 +1,254 @@
#!/usr/bin/env python
########################################################################
# DellEMC E3224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fans' information which are available in the platform.
#
########################################################################
try:
import os
from sonic_platform_base.fan_base import FanBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Fan(FanBase):
"""DellEMC Platform-specific Fan class"""
def __init__(self, fantray_index=0, fan_index=0, 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.presence_reg = "fan{}_prs".format(fantray_index)
self.dir_reg = "fan{}_dir".format(fantray_index)
self.rpm_file = "/sys/bus/i2c/devices/7-002c/fan{}_input".format(fantray_index+1)
self.status_file = "/sys/bus/i2c/devices/7-002c/fan{}_fault".format(fantray_index+1)
self.eeprom = "/sys/bus/i2c/devices/{}-0050/eeprom".format(15 + fantray_index)
self.fantray_index = fantray_index
self.fan_index = fan_index
else:
self.psu_index = fan_index - 1
self.dependancy = dependency
self.presence_reg = "psu{}_prs".format(self.psu_index)
self.status_reg = "psu{}_status".format(self.psu_index)
self.dir_reg = ""
self.dps_hwmon = "/sys/bus/i2c/devices/{}-005e/hwmon/".format(self.psu_index + 10)
self.eeprom = "/sys/bus/i2c/devices/{}-0056/eeprom".format(self.psu_index + 10)
self.fan_index = fan_index
self.max_speed = 0
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'r')as fd:
buf = fd.read()
except (IOError, AttributeError):
return 'ERR'
return buf.strip('\r\n').lstrip(' ')
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.psu_index+1)
else:
return "FanTray{}-Fan{}".format(self.fantray_index+1, self.fan_index+1)
def get_model(self):
"""
Retrieves the part number of the FAN
Returns:
String: Part number of FAN
"""
try:
val = open(self.eeprom, "rb").read()[13:19]
except Exception:
val = None
return val.decode()
def get_serial(self):
"""
Retrieves the serial number of the FAN
Returns:
String: Serial number of FAN
"""
try:
val = open(self.eeprom, "rb").read()[21:41]
except Exception:
val = None
return val.decode()
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if fan is present, False if not
"""
presence = self._get_cpld_register(self.presence_reg)
if presence == 'ERR':
return False
if int(presence,0) == 1:
return True
else:
return False
def get_status(self):
"""
Retrieves the operational status of the FAN
Returns:
bool: True if FAN is operating properly, False if not
"""
if not self.is_psu_fan:
status = open(self.status_file, "rb").read()
if int(status, 0) == 1:
return False
else:
return True
else:
status = self._get_cpld_register(self.status_reg)
if status == 'ERR':
return False
if int(status, 0) == 1:
return True
else:
return False
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.
"""
if not self.is_psu_fan:
val = self._get_cpld_register(self.dir_reg)
direction = 'exhaust' if val == 'F2B' else 'intake'
if direction == 'ERR':
return None
else:
try:
val = open(self.eeprom, "rb").read()[0xe1:0xe8]
except Exception:
return None
direction = 'exhaust' if val == 'FORWARD' else 'intake'
return direction
def get_speed(self):
"""
Retrieves the speed of the fan
Returns:
int: percentage of the max fan speed
"""
if self.max_speed == 0:
self.max_speed = 23500
fan_speed = 0
try:
if not self.is_psu_fan:
rpm_file = self.rpm_file
else:
dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0]
rpm_file = dps_dir + '/' + 'fan1_input'
fan_speed = int(open(rpm_file, "rb").read())
except Exception:
return None
speed = (100 * fan_speed)//self.max_speed
return speed
def get_speed_rpm(self):
"""
Retrieves the speed of the fan
Returns:
int: percentage of the max fan speed
"""
fan_speed = 0
try:
if not self.is_psu_fan:
rpm_file = self.rpm_file
else:
dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0]
rpm_file = dps_dir + '/' + 'fan1_input'
fan_speed = int(open(rpm_file, "rb").read())
except Exception:
return None
return fan_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.fan_index
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.
"""
# E3224F has led only on FanTray and not available for seperate fans
return True
def get_status_led(self):
"""
Gets the current system LED color
Returns:
A string that represents the supported color
"""
return None
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
"""
# Return current speed to avoid false thermalctld alarm.
return self.get_speed()

View File

@ -0,0 +1,158 @@
#!/usr/bin/env python
########################################################################
# DellEMC E3224F
#
# 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")
E3224F_FANS_PER_FANTRAY = 1
class FanDrawer(FanDrawerBase):
"""DellEMC Platform-specific Fan class"""
FANTRAY_LED_COLORS = {
"off",
"green",
"yellow"
}
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 1-based in DellEMC platforms
self.fantray_led_reg = "fan{}_led".format(fantray_index)
self.fantrayindex = fantray_index + 1
for i in range(E3224F_FANS_PER_FANTRAY):
self._fan_list.append(Fan(fantray_index, i))
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
rv = open(cpld_reg_file, 'r').read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# reg_name and on failure returns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception:
rv = 'ERR'
return rv
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex)
def get_status_led(self):
"""
Gets the current system LED color
Returns:
A string that represents the supported color
"""
color = self._get_cpld_register(self.fantray_led_reg)
#if color not in list(self.FANTRAY_LED_COLORS):
# return self.sys_ledcolor
return color
def set_status_led(self,color):
"""
Set system LED status based on the color type passed in the argument.
Argument: Color to be set
Returns:
bool: True is specified color is set, Otherwise return False
"""
if color not in list(self.FANTRAY_LED_COLORS):
return False
if(not self._set_cpld_register(self.fantray_led_reg, color)):
return False
return True
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 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 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 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.
"""
return 0.0

View File

@ -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()

View File

@ -0,0 +1,255 @@
#!/usr/bin/env python
########################################################################
# DellEMC E3224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs' information which are available in the platform
#
########################################################################
try:
import os
from sonic_platform_base.psu_base import PsuBase
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"""
def __init__(self, psu_index):
PsuBase.__init__(self)
self.index = psu_index + 1 # PSU is 1-based in DellEMC platforms
self.psu_presence_reg = "psu{}_prs".format(psu_index)
self.psu_status = "psu{}_status".format(psu_index)
self.eeprom = "/sys/bus/i2c/devices/{}-0056/eeprom".format(10+psu_index)
self.psu_voltage_reg = 'in3_input'
self.psu_current_reg = 'curr2_input'
self.psu_power_reg = 'power2_input'
self.dps_hwmon = "/sys/bus/i2c/devices/{}-005e/hwmon/".format(10 + psu_index)
self.dps_hwmon_exist = os.path.exists(self.dps_hwmon)
self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, dependency=self))
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'r') as fd:
rv = fd.read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
def _get_dps_register(self, reg_name):
try :
dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0]
dps_reg_file = dps_dir + '/' + reg_name
with open(dps_reg_file, 'r') as fd:
rv = fd.read()
except (IOError, OSError) : return 'ERR'
return rv
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return "PSU{}".format(self.index)
def _reload_dps_module(self):
try:
file = "/sys/bus/i2c/devices/i2c-{}/delete_device".format(10 + self.index - 1)
with open(file, 'w') as f:
f.write('0x56\n')
except (IOError, OSError):
pass
try:
file = "/sys/bus/i2c/devices/i2c-{}/delete_device".format(10 + self.index - 1)
with open(file, 'w') as f:
f.write('0x5e\n')
except (IOError, OSError):
pass
try:
file = "/sys/bus/i2c/devices/i2c-{}/new_device".format(10 + self.index - 1)
with open(file, 'w') as f:
f.write('24c02 0x56\n')
file = "/sys/bus/i2c/devices/i2c-{}/new_device".format(10 + self.index - 1)
with open(file, 'w') as f:
f.write('dps460 0x5e\n')
except (IOError, OSError):
pass
def get_presence(self):
"""
Retrieves the presence of the Power Supply Unit (PSU)
Returns:
bool: True if PSU is present, False if not
"""
presence = self._get_cpld_register(self.psu_presence_reg).strip()
if presence == 'ERR':
return False
status = self.get_status()
if int(presence, 0) and status == False:
return int(presence, 0)
if not self.dps_hwmon_exist and int(presence, 0):
self.dps_hwmon_exist = os.path.exists(self.dps_hwmon)
if not self.dps_hwmon_exist:
self._reload_dps_module()
if int(presence, 0) == 1:
return True
return False
def get_model(self):
"""
Retrieves the part number of the PSU
Returns:
string: Part number of PSU
"""
try: val = open(self.eeprom, "rb").read()[0x50:0x62]
except Exception:
val = None
return val.decode('ascii')
def get_serial(self):
"""
Retrieves the serial number of the PSU
Returns:
string: Serial number of PSU
"""
try: val = open(self.eeprom, "rb").read()[0xc4:0xd9]
except Exception:
val = None
return val.decode('ascii')
def get_revision(self):
"""
Retrieves the serial number of the PSU
Returns:
string: Serial number of PSU
"""
try: val = open(self.eeprom, "rb").read()[0xc4:0xd9]
except Exception:
val = None
if val != "NA" and len(val) == 23:
return val[-3:]
else:
return "NA"
def get_status(self):
"""
Retrieves the operational status of the PSU
Returns:
bool: True if PSU is operating properly, False if not
"""
status = self._get_cpld_register(self.psu_status).strip()
if status == 'ERR' : return False
if int(status, 0) == 1:
return True
return False
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
volt_reading = self._get_dps_register(self.psu_voltage_reg)
try:
voltage = int(volt_reading)/1000
except Exception:
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
"""
curr_reading = self._get_dps_register(self.psu_current_reg)
try:
current = int(curr_reading)/1000
except Exception:
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
"""
power_reading = self._get_dps_register(self.psu_power_reg)
try:
power = int(power_reading)/(1000*1000)
except Exception:
return None
return float(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.
"""
power_good = self._get_cpld_register(self.psu_status).strip()
if power_good == 'ERR' : return False
return int(power_good, 0)
def get_mfr_id(self):
"""
Retrives the Manufacturer Id of PSU
Returns:
A string, the manunfacturer id.
"""
return 'DELTA'
def get_type(self):
"""
Retrives the Power Type of PSU
Returns :
A string, PSU power type
"""
try: val = open(self.eeprom, "rb").read()[0xe8:0xea]
except Exception:
return None
return val.decode()
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 PSU is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True

View File

@ -0,0 +1,343 @@
#!/usr/bin/env python
#############################################################################
# DELLEMC E3224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import os
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")
SFP_PORT_START = 1
SFP_PORT_END = 24
SFPPLUS_PORT_START = 25
SFPPLUS_PORT_END = 28
PORT_END = 30
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
"""
_port_to_i2c_mapping = {
1: 27,
2: 28,
3: 29,
4: 30,
5: 31,
6: 32,
7: 33,
8: 34,
9: 35,
10: 36,
11: 37,
12: 38,
13: 39,
14: 40,
15: 41,
16: 42,
17: 43,
18: 44,
19: 45,
20: 46,
21: 47,
22: 48,
23: 49,
24: 50,
25: 20,
26: 21,
27: 22,
28: 23,
29: 24,
30: 25,
}
def __init__(self, index, sfp_type, eeprom_path):
SfpOptoeBase.__init__(self)
self.sfp_type = sfp_type
self.port_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):
if not (self.index >= SFP_PORT_START and self.index <= PORT_END):
return "N/A"
if self.index <= SFP_PORT_END:
return "SFP8"
elif self.index <= SFPPLUS_PORT_END:
return "SFP/SFP+/SFP28"
else:
return "QSFP or later"
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 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._port_to_i2c_mapping[self.index])
new_sfp_path = "/sys/class/i2c-adapter/i2c-{0}/new_device".format(self._port_to_i2c_mapping[self.index])
driver_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/name".format(self._port_to_i2c_mapping[self.index])
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']:
with open(del_sfp_path, 'w') as f:
f.write('0x50\n')
time.sleep(0.2)
with open(new_sfp_path, 'w') as f:
f.write('optoe2 0x50\n')
time.sleep(2)
elif self.sfp_type == 'QSFP' and driver_name in ['optoe2', 'optoe3']:
with open(del_sfp_path, 'w') as f:
f.write('0x50\n')
time.sleep(0.2)
with open(new_sfp_path, 'w') as f:
f.write('optoe1 0x50\n')
time.sleep(2)
elif self.sfp_type == 'QSFP_DD' and driver_name in ['optoe1', 'optoe2']:
with open(del_sfp_path, 'w') as f:
f.write('0x50\n')
time.sleep(0.2)
with open(new_sfp_path, 'w') as f:
f.write('optoe3 0x50\n')
time.sleep(2)
except IOError as e:
print("Error: Unable to open file: %s" % str(e))
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 _get_cpld_register(self, reg):
reg_file = '/sys/devices/platform/dell-e3224f-cpld.0/' + reg
try:
with open(reg_file, 'r') as fd:
rv = fd.read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# reg_name and on failure returns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception:
rv = 'ERR'
return rv
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
presence = False
if not (self.index >= SFP_PORT_START and self.index <= PORT_END):
return presence
try:
if self.index <= SFP_PORT_END:
bit_mask = 1 << (self.index - SFP_PORT_START)
sfp_mod_prs = self._get_cpld_register('sfp_modprs')
if sfp_mod_prs == 'ERR':
return presence
presence = ((int(sfp_mod_prs, 16) & bit_mask) == 0)
elif self.index <= SFPPLUS_PORT_END:
bit_mask = 1 << (self.index - SFPPLUS_PORT_START)
sfpplus_mod_prs = self._get_cpld_register('sfpplus_modprs')
if sfpplus_mod_prs == 'ERR':
return presence
presence = ((int(sfpplus_mod_prs, 16) & bit_mask) == 0)
else:
bit_mask = (1 << (self.index - (SFPPLUS_PORT_START+4)))
qsfp_mod_prs = self._get_cpld_register('qsfp_modprs')
if qsfp_mod_prs == 'ERR':
return presence
presence = ((int(qsfp_mod_prs, 16) & bit_mask) == 0)
except TypeError:
pass
return presence
def tx_disable(self, tx_disable):
"""
Enable/Disable the TX disable bit of the optics.
"""
rval = False
if not (self.index >= SFP_PORT_START and self.index <= SFPPLUS_PORT_END):
return rval
if self.sfp_type == 'SFP':
if self.index <= SFP_PORT_END:
sfp_txdis = int(self._get_cpld_register('sfp_txdis'), 16)
if sfp_txdis != 'ERR':
bit_mask = 1 << (self.index - SFP_PORT_START)
sfp_txdis = sfp_txdis | bit_mask if tx_disable \
else sfp_txdis & ~bit_mask
rval = (self._set_cpld_register('sfp_txdis', sfp_txdis) != 'ERR')
elif self.index <= SFPPLUS_PORT_END:
sfpplus_txdis = int(self._get_cpld_register('sfpplus_txdis'), 16)
if sfpplus_txdis != 'ERR':
bit_mask = 1 << (self.index - SFPPLUS_PORT_START)
sfpplus_txdis = sfpplus_txdis | bit_mask if tx_disable \
else sfpplus_txdis & ~bit_mask
rval = (self._set_cpld_register('sfpplus_txdis', sfpplus_txdis) != 'ERR')
return rval
def get_reset_status(self):
"""
Retrives the reset status of SFP
"""
reset_status = False
return reset_status
def get_lpmode(self):
"""
Retrieves the lpmode(low power mode) of this SFP
"""
lpmode_state = False
return lpmode_state
def reset(self):
"""
Reset the SFP and returns all user settings to their default state
"""
return False
def set_lpmode(self, lpmode):
"""
Sets the lpmode(low power mode) of this SFP
"""
return True
def get_status(self):
"""
Retrieves the operational status of the device
"""
reset = self.get_reset_status()
return (not reset)
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 is_replaceable(self):
"""
Indicate whether this device is replaceable.
Returns:
bool: True if it is replaceable.
"""
return True
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

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python
########################################################################
# DellEMC E3224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Thermals' information which are available in the platform
#
########################################################################
try:
import os
from sonic_platform_base.thermal_base import ThermalBase
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 = [
['Switch Near Temperature', '7-0049'],
['Switch Rear Temperature', '7-004a'],
['Front Panel PHY Temperature', '7-004b'],
['Near Front Panel Temperature', '7-004c'],
['Middle Fan Tray Temperature', '7-004f'],
]
def __init__(self, thermal_index):
ThermalBase.__init__(self)
self.index = thermal_index + 1
temp_hwmon = '/sys/bus/i2c/devices/' + self.SENSOR_MAPPING[thermal_index][1] + '/hwmon'
self.temp_file = temp_hwmon + '/' + os.listdir(temp_hwmon)[0] + '/' + 'temp1_input'
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
"""
temperature = 0.0
try :
temperature = float(open(self.temp_file).read()) / 1000.0
except Exception:
pass
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
"""
return 75.0
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
"""
return 0.0
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

View File

@ -0,0 +1,207 @@
#!/usr/bin/env python
########################################################################
#
# DELLEMC E3224F
#
# Abstract base class for implementing a platform-specific class with
# which to interact with a hardware watchdog module in SONiC
#
########################################################################
try:
import ctypes
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):
WatchdogBase.__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)]
self.watchdog_reg = "watchdog"
def _get_cpld_register(self, reg_name):
# On successful read, returns the value read from given
# reg name and on failure rethrns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'r') as fd:
rv = fd.read()
except IOError : return 'ERR'
return rv.strip('\r\n').lstrip(' ')
def _set_cpld_register(self, reg_name, value):
# On successful write, returns the value will be written on
# reg_name and on failure returns 'ERR'
cpld_dir = "/sys/devices/platform/dell-e3224f-cpld.0/"
cpld_reg_file = cpld_dir + '/' + reg_name
try:
with open(cpld_reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception:
rv = 'ERR'
return rv
def _get_reg_val(self):
value = self._get_cpld_register(self.watchdog_reg).strip()
if value == 'ERR': return False
return int(value,16)
def _set_reg_val(self,val):
value = self._set_cpld_register(self.watchdog_reg, 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
# 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 8th bits
# value from timer_offset
self.disarm()
self._set_reg_val((reg_val & 0x0F) | (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.
E3224F 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

View File

@ -0,0 +1,13 @@
[Unit]
Description=Dell E3224F Platform mux ctrl
Before=pmon.service
After=platform-modules-e3224f.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/local/bin/mux_controller.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,14 @@
[Unit]
Description=Dell E3224F Platform modules
Before=pmon.service
After=platform-init.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/local/bin/e3224f_platform.sh init
ExecStop=/usr/local/bin/e3224f_platform.sh deinit
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target