diff --git a/sonic_platform_base/sonic_ssd/ssd_generic.py b/sonic_platform_base/sonic_ssd/ssd_generic.py index 7c93005ec..5ba84fa61 100644 --- a/sonic_platform_base/sonic_ssd/ssd_generic.py +++ b/sonic_platform_base/sonic_ssd/ssd_generic.py @@ -17,6 +17,7 @@ SMARTCTL = "smartctl {} -a" INNODISK = "iSmart -d {}" VIRTIUM = "SmartCmd -m {}" +TRANSCEND = "scopepro -all {}" NOT_AVAILABLE = "N/A" @@ -25,6 +26,8 @@ INNODISK_TEMPERATURE_ID = 194 SWISSBIT_HEALTH_ID = 248 SWISSBIT_TEMPERATURE_ID = 194 +TRANSCEND_HEALTH_ID = 169 +TRANSCEND_TEMPERATURE_ID = 194 class SsdUtil(SsdBase): """ @@ -46,6 +49,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 }, } self.dev = diskdev @@ -83,6 +87,8 @@ def _parse_vendor(self): return 'Virtium' elif self.model.startswith('SFS'): return 'Swissbit' + elif self.model.startswith('TS'): + return 'Transcend' else: return None @@ -179,6 +185,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)) diff --git a/tests/ssd_generic_test.py b/tests/ssd_generic_test.py index a8ee71fec..338e27fff 100644 --- a/tests/ssd_generic_test.py +++ b/tests/ssd_generic_test.py @@ -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% +""" + 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): @@ -891,3 +936,15 @@ def test_swissbit_ssd(self, mock_exec): assert swissbit_ssd.get_firmware() == "SBR15004" 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"