Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions sonic_platform_base/sonic_ssd/ssd_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
SMARTCTL = "smartctl {} -a"
INNODISK = "iSmart -d {}"
VIRTIUM = "SmartCmd -m {}"
TRANSCEND = "scopepro -all {}"

NOT_AVAILABLE = "N/A"

Expand All @@ -26,6 +27,8 @@
INNODISK_TEMPERATURE_ID = 194
SWISSBIT_HEALTH_ID = 248
SWISSBIT_TEMPERATURE_ID = 194
TRANSCEND_HEALTH_ID = 169
TRANSCEND_TEMPERATURE_ID = 194

class SsdUtil(SsdBase):
"""
Expand All @@ -48,6 +51,7 @@ def __init__(self, diskdev):
"StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info },
"Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info },
"Swissbit" : { "utility" : SMARTCTL, "parser" : self.parse_swissbit_info },
"Transcend" : { "utility" : TRANSCEND, "parser" : self.parse_transcend_info },
"WDC" : { "utility" : SMARTCTL, "parser" : self.parse_wdc_ssd_info }
}

Expand Down Expand Up @@ -86,6 +90,8 @@ def _parse_vendor(self):
return 'Virtium'
elif self.model.startswith('SFS'):
return 'Swissbit'
elif self.model.startswith('TS'):
return 'Transcend'
elif self.model.startswith(('EPM3750', 'MPT160')):
return 'Phison'
else:
Expand Down Expand Up @@ -208,6 +214,22 @@ def parse_swissbit_info(self):
else:
self.temperature = temp_raw.split()[-3]

def parse_transcend_info(self):
if self.vendor_ssd_info:
self.model = self._parse_re('Model\s*:(.+?)\s*\n', self.vendor_ssd_info)
self.serial = self._parse_re('Serial No\s*:(.+?)\s*\n', self.vendor_ssd_info)
self.firmware = self._parse_re('FW Version\s*:(.+?)\s*\n', self.vendor_ssd_info)
health_raw = self._parse_re('{}\s*(.+?)\n'.format(hex(TRANSCEND_HEALTH_ID).upper()[2:]), self.vendor_ssd_info) #169 -> A9
if health_raw == NOT_AVAILABLE:
self.health = NOT_AVAILABLE
else:
self.health = health_raw.split()[-1]
temp_raw = self._parse_re('{}\s*(.+?)\n'.format(hex(TRANSCEND_TEMPERATURE_ID).upper()[2:]), self.vendor_ssd_info) #194 -> C2
if temp_raw == NOT_AVAILABLE:
self.temperature = NOT_AVAILABLE
else:
self.temperature = temp_raw.split()[-1]

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

Expand Down
59 changes: 58 additions & 1 deletion tests/ssd_generic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,51 @@
If Selective self-test is pending on power-up, resume after 0 minute delay.
"""

output_transcend_vendor = """
scopepro-cli 1.21 2023/11/24
Copyright (c) 2021-24, Transcend information, Inc. All rights reserved.

[/dev/sda]
---------- Disk Information ----------
Model :TS32XBTMM1600
FW Version :O0918B
Serial No :F318410080
Support Interface :SATA
---------------- S.M.A.R.T Information ----------------
01 Read Error Rate 0
05 Reallocated Sectors Count 0
09 Power-On Hour Count 2295
0C Power Cycle Count 2580
A0 Uncorrectable sectors count when read/write 0
A1 Number of Valid Spare Blocks 56
A3 Number of Initial Invalid Blocks 12
A4 Total Erase Count 924312
A5 Maximum Erase Count 931
A6 Minimum Erase Count 831
A7 Average Erase Count 898
A8 Max Erase Count of Spec 3000
A9 Remain Life (percentage) 71
AF Program fail count in worst die 0
B0 Erase fail count in worst die 0
B1 Total Wear Level Count 481
B2 Runtime Invalid Block Count 0
B5 Total Program Fail Count 0
B6 Total Erase Fail Count 0
C0 Power-Off Retract Count 59
C2 Controlled Temperature 40
C3 Hardware ECC Recovered 1668
C4 Reallocation Event Count 0
C5 Current Pending Sector Count 0
C6 Uncorrectable Error Count Off-Line 0
C7 Ultra DMA CRC Error Count 0
E8 Available Reserved Space 100
F1 Total LBA Written (each write unit=32MB) 671696
F2 Total LBA Read (each read unit=32MB) 393162
F5 Flash Write Sector Count 924312
---------------- Health Information ----------------
Health Percentage: 71%
"""

output_wdc_vendor = """
smartctl 7.2 2020-12-30 r5155 [x86_64-linux-5.10.0-18-2-amd64] (local build)
Copyright (C) 2002-20, Bruce Allen, Christian Franke, www.smartmontools.org
Expand Down Expand Up @@ -982,6 +1027,18 @@ def test_swissbit_ssd(self, mock_exec):
assert swissbit_ssd.get_temperature() == '25'
assert swissbit_ssd.get_serial() == "00006022750795000010"

@mock.patch('sonic_platform_base.sonic_ssd.ssd_generic.SsdUtil._execute_shell')
def test_transcend_ssd(self, mock_exec):
mock_exec.return_value = output_transcend_vendor
transcend_ssd = SsdUtil('/dev/sda')
transcend_ssd.vendor_ssd_info = mock_exec.return_value
transcend_ssd.parse_vendor_ssd_info('Transcend')
assert transcend_ssd.get_health() == '71'
assert transcend_ssd.get_model() == 'TS32XBTMM1600'
assert transcend_ssd.get_firmware() == "O0918B"
assert transcend_ssd.get_temperature() == '40'
assert transcend_ssd.get_serial() == "F318410080"

@mock.patch('sonic_platform_base.sonic_ssd.ssd_generic.SsdUtil._execute_shell')
def test_wdc_ssd(self, mock_exec):
mock_exec.return_value = output_wdc_vendor
Expand All @@ -990,4 +1047,4 @@ def test_wdc_ssd(self, mock_exec):
assert wdc_ssd.get_model() == 'WDC PC SA530 SDASN8Y1T00'
assert wdc_ssd.get_firmware() == "40103000"
assert wdc_ssd.get_temperature() == '23'
assert wdc_ssd.get_serial() == "2122FF441406"
assert wdc_ssd.get_serial() == "2122FF441406"