Skip to content

Commit

Permalink
[sonic_ssd] Nokia-7215: "show platform ssdhealth" not showing health …
Browse files Browse the repository at this point in the history
…percent (sonic-net#279)

Description
The command is not showing the correct value for ssd health.

admin@sonic:~$ show platform ssdhealth
Device Model : M.2 (S42) 3IE4
Health       : N/A
Temperature  : 25C
Motivation and Context
SSD health percentage not displayed on Nokia-7215 platform.

How Has This Been Tested?
"show platform ssdhealth" cli command
Output after fix:

admin@sonic:~$ show platform ssdhealth 
Device Model : M.2 (S42) 3IE4
Health       : 100%
Temperature  : 25C
  • Loading branch information
bill-nokia authored May 11, 2022
1 parent d62d3d6 commit b043372
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 11 deletions.
36 changes: 25 additions & 11 deletions sonic_platform_base/sonic_ssd/ssd_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

NOT_AVAILABLE = "N/A"

# Set Vendor Specific IDs
INNODISK_HEALTH_ID = 169
INNODISK_TEMPERATURE_ID = 194

class SsdUtil(SsdBase):
"""
Expand Down Expand Up @@ -109,24 +112,32 @@ def parse_generic_ssd_info(self):
self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info)

def parse_innodisk_info(self):
self.health = self._parse_re('Health:\s*(.+?)%?', self.vendor_ssd_info)
self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info)
if self.vendor_ssd_info:
self.health = self._parse_re('Health:\s*(.+?)%?', self.vendor_ssd_info)
self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info)
else:
if self.health == NOT_AVAILABLE:
health_raw = self.parse_id_number(INNODISK_HEALTH_ID)
self.health = health_raw.split()[-1]
if self.temperature == NOT_AVAILABLE:
temp_raw = self.parse_id_number(INNODISK_TEMPERATURE_ID)
self.temperature = temp_raw.split()[-6]

def parse_virtium_info(self):
self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info)
nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info)
avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info)
try:
self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance))
except ValueError:
pass
if self.vendor_ssd_info:
self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info)
nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info)
avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info)
try:
self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance))
except (ValueError, ZeroDivisionError):
pass

def fetch_vendor_ssd_info(self, diskdev, model):
self.vendor_ssd_info = self._execute_shell(self.vendor_ssd_utility[model]["utility"].format(diskdev))

def parse_vendor_ssd_info(self, model):
if self.vendor_ssd_info:
self.vendor_ssd_utility[model]["parser"]()
self.vendor_ssd_utility[model]["parser"]()

def get_health(self):
"""
Expand Down Expand Up @@ -183,3 +194,6 @@ def get_vendor_output(self):
A string holding some vendor specific disk information
"""
return self.vendor_ssd_info

def parse_id_number(self, id):
return self._parse_re('{}\s*(.+?)\n'.format(id), self.ssd_info)
87 changes: 87 additions & 0 deletions tests/ssd_generic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,84 @@
0 5275 0 0x0001 0x0004 - 0 1 -"""

output_Innodisk_missing_names_ssd = """smartctl 6.6 2017-11-05 r4594 [armv7l-linux-4.19.0-12-2-armmp] (local build)
Copyright (C) 2002-17, Bruce Allen, Christian Franke, www.smartmontools.org
=== START OF INFORMATION SECTION ===
Model Family: Innodisk 3IE3/3ME3/3ME4 SSDs
Device Model: M.2 (S42) 3ME4
Serial Number: YCA12003110020080
LU WWN Device Id: 5 02b2a2 01d1c1b1a
Firmware Version: L17606
User Capacity: 16,013,942,784 bytes [16.0 GB]
Sector Size: 512 bytes logical/physical
Rotation Rate: Solid State Device
Device is: In smartctl database [for details use: -P show]
ATA Version is: ACS-3 T13/2161-D revision 4
SATA Version is: SATA 3.2, 6.0 Gb/s (current: 6.0 Gb/s)
Local Time is: Tue Apr 26 00:57:00 2022 UTC
SMART support is: Available - device has SMART capability.
SMART support is: Enabled
=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
General SMART Values:
Offline data collection status: (0x02) Offline data collection activity
was completed without error.
Auto Offline Data Collection: Disabled.
Total time to complete Offline
data collection: ( 32) seconds.
Offline data collection
capabilities: (0x00) Offline data collection not supported.
SMART capabilities: (0x0002) Does not save SMART data before
entering power-saving mode.
Supports SMART auto save timer.
Error logging capability: (0x00) Error logging NOT supported.
General Purpose Logging supported.
SMART Attributes Data Structure revision number: 16
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
1 Raw_Read_Error_Rate 0x0000 000 000 000 Old_age Offline - 0
2 Throughput_Performance 0x0000 000 000 000 Old_age Offline - 0
5 Later_Bad_Block 0x0012 100 100 001 Old_age Always - 0
7 Seek_Error_Rate 0x0000 000 000 000 Old_age Offline - 0
8 Seek_Time_Performance 0x0000 000 000 000 Old_age Offline - 0
9 Power_On_Hours 0x0012 253 000 000 Old_age Always - 14151
10 Spin_Retry_Count 0x0000 000 000 000 Old_age Offline - 0
12 Power_Cycle_Count 0x0012 036 000 000 Old_age Always - 36
163 Total_Bad_Block_Count 0x0000 000 000 000 Old_age Offline - 9
168 SATA_PHY_Error_Count 0x0000 000 000 000 Old_age Offline - 0
169 Unknown Attribute 0x0000 094 000 000 Old_age Offline - 94
175 Bad_Cluster_Table_Count 0x0000 000 000 000 Old_age Offline - 0
192 Power-Off_Retract_Count 0x0012 000 000 000 Old_age Always - 3
194 Unknown Attribute 0x0002 039 100 000 Old_age Always - 39 (3 42 0 33 0)
197 Current_Pending_Sector 0x0000 000 000 000 Old_age Offline - 0
225 Data_Log_Write_Count 0x0000 000 000 000 Old_age Offline - 0
240 Write_Head 0x0000 000 000 000 Old_age Offline - 0
165 Max_Erase_Count 0x0012 223 100 000 Old_age Always - 223
167 Average_Erase_Count 0x0012 000 100 000 Old_age Always - 187
170 Spare_Block_Count 0x0013 100 100 010 Pre-fail Always - 72
171 Program_Fail_Count 0x0012 000 100 000 Old_age Always - 0
172 Erase_Fail_Count 0x0012 000 100 000 Old_age Always - 0
176 RANGE_RECORD_Count 0x0000 000 000 000 Old_age Offline - 0
184 End-to-End_Error 0x0012 000 000 000 Old_age Always - 0
187 Reported_Uncorrect 0x0012 000 000 000 Old_age Always - 0
229 Flash_ID 0x0000 100 100 000 Old_age Offline - 0x51769394de98
232 Spares_Remaining_Perc 0x0013 000 000 000 Pre-fail Always - 0
235 Later_Bad_Blk_Inf_R/W/E 0x0002 000 000 000 Old_age Always - 0 0 0
241 Host_Writes_32MiB 0x0002 100 100 000 Old_age Always - 14452
242 Host_Reads_32MiB 0x0002 100 100 000 Old_age Always - 42566
SMART Error Log not supported
SMART Self-test Log not supported
Selective Self-tests/Logging not supported
"""

class TestSsdGeneric:
@mock.patch('sonic_platform_base.sonic_ssd.ssd_generic.SsdUtil._execute_shell', mock.MagicMock(return_value=output_nvme_ssd))
def test_nvme_ssd(self):
Expand Down Expand Up @@ -325,3 +403,12 @@ def test_Innodisk_ssd(self):
assert(Innodisk_ssd.get_temperature() == '0')
assert(Innodisk_ssd.get_serial() == "20171126AAAA11730156")

@mock.patch('sonic_platform_base.sonic_ssd.ssd_generic.SsdUtil._execute_shell', mock.MagicMock(return_value=output_Innodisk_missing_names_ssd))
def test_Innodisk_missing_names_ssd(self):
# Test parsing Innodisk ssd info
Innodisk_ssd = SsdUtil('/dev/sda')
Innodisk_ssd.vendor_ssd_info = ''
Innodisk_ssd.parse_vendor_ssd_info('InnoDisk')
assert(Innodisk_ssd.get_health() == '94')
assert(Innodisk_ssd.get_temperature() == '39')

0 comments on commit b043372

Please sign in to comment.