From e19f69687d74e4860f7ccc12ed78df7b5e4a4906 Mon Sep 17 00:00:00 2001 From: Yuri Danilov Date: Thu, 23 Sep 2021 17:51:15 +0300 Subject: [PATCH 1/7] added support for WDC SDASN8Y1T00 SSD health --- sonic_platform_base/sonic_ssd/ssd_generic.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sonic_platform_base/sonic_ssd/ssd_generic.py b/sonic_platform_base/sonic_ssd/ssd_generic.py index 8d38d11e0..8a02bc8aa 100644 --- a/sonic_platform_base/sonic_ssd/ssd_generic.py +++ b/sonic_platform_base/sonic_ssd/ssd_generic.py @@ -42,7 +42,8 @@ def __init__(self, diskdev): "InnoDisk" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, "M.2" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, "StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, - "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info } + "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, + "WDC" : { "utility" : SMARTCTL, "parser" : self.parse_wdc_ssd_info } } self.dev = diskdev @@ -111,6 +112,21 @@ def parse_generic_ssd_info(self): self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) + def parse_wdc_ssd_info(self): + self.model = self._parse_re('Device Model:\s*(.+?)\n', self.ssd_info) + self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) + self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) + try: + if ("SDASN8Y1T00" == self.model.split(' ')[3]): + self.nand_endurance = 400 * 1000 + parsed_total_lbas_written = self._parse_re('Total_LBAs_Written\s*.*Offline\s*-\s*\d*', self.vendor_ssd_info) + total_lbas_written = int(self._parse_re('\s{7}\d*', parsed_total_lbas_written).split(' ')[7]) + self.health = int(100.0 - (total_lbas_written * 100) / self.nand_endurance) + celsius_str = self._parse_re('Temperature_Celsius\s*.*', self.vendor_ssd_info) + self.temperature = self._parse_re('\d*\s\(Min.*', celsius_str) + except (ValueError, IndexError): + pass + def parse_innodisk_info(self): if self.vendor_ssd_info: self.health = self._parse_re('Health:\s*(.+?)%', self.vendor_ssd_info) From a9b8721ef32179924882c5b08bd80acff471ab88 Mon Sep 17 00:00:00 2001 From: Eran Dahan Date: Thu, 15 Feb 2024 15:57:49 +0200 Subject: [PATCH 2/7] arrange order of ssd types after resolving merge conflict --- sonic_platform_base/sonic_ssd/ssd_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonic_platform_base/sonic_ssd/ssd_generic.py b/sonic_platform_base/sonic_ssd/ssd_generic.py index b93bd6be4..1ec2b4c11 100644 --- a/sonic_platform_base/sonic_ssd/ssd_generic.py +++ b/sonic_platform_base/sonic_ssd/ssd_generic.py @@ -49,8 +49,8 @@ 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 }, - "Transcend" : { "utility" : TRANSCEND, "parser" : self.parse_transcend_info } } self.dev = diskdev From 16d502062338e89a89436f6e2070186edb5339ff Mon Sep 17 00:00:00 2001 From: Eran Dahan Date: Thu, 15 Feb 2024 16:16:57 +0200 Subject: [PATCH 3/7] add test coverage for wdc ssd --- tests/ssd_generic_test.py | 100 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/ssd_generic_test.py b/tests/ssd_generic_test.py index 338e27fff..a3ac477a8 100644 --- a/tests/ssd_generic_test.py +++ b/tests/ssd_generic_test.py @@ -819,6 +819,96 @@ 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 + +=== START OF INFORMATION SECTION === +Device Model: WDC PC SA530 SDASN8Y1T00 +Serial Number: 2122FF441406 +LU WWN Device Id: 5 001b44 4a7dc5677 +Firmware Version: 40103000 +User Capacity: 1,024,209,543,168 bytes [1.02 TB] +Sector Size: 512 bytes logical/physical +Rotation Rate: Solid State Device +Form Factor: M.2 +TRIM Command: Available, deterministic, zeroed +Device is: Not in smartctl database [for details use: -P showall] +ATA Version is: ACS-4 T13/BSR INCITS 529 revision 5 +SATA Version is: SATA 3.3, 6.0 Gb/s (current: 6.0 Gb/s) +Local Time is: Thu Feb 15 14:12:34 2024 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: (0x00) Offline data collection activity + was never started. + Auto Offline Data Collection: Disabled. +Self-test execution status: ( 0) The previous self-test routine completed + without error or no self-test has ever + been run. +Total time to complete Offline +data collection: ( 0) seconds. +Offline data collection +capabilities: (0x11) SMART execute Offline immediate. + No Auto Offline data collection support. + Suspend Offline collection upon new + command. + No Offline surface scan supported. + Self-test supported. + No Conveyance Self-test supported. + No Selective Self-test supported. +SMART capabilities: (0x0003) Saves SMART data before entering + power-saving mode. + Supports SMART auto save timer. +Error logging capability: (0x01) Error logging supported. + General Purpose Logging supported. +Short self-test routine +recommended polling time: ( 2) minutes. +Extended self-test routine +recommended polling time: ( 10) minutes. + +SMART Attributes Data Structure revision number: 4 +Vendor Specific SMART Attributes with Thresholds: +ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE + 5 Reallocated_Sector_Ct 0x0032 100 100 --- Old_age Always - 0 + 9 Power_On_Hours 0x0032 100 100 --- Old_age Always - 18904 + 12 Power_Cycle_Count 0x0032 100 100 --- Old_age Always - 169 +165 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 28311878 +166 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 1 +167 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 54 +168 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 10 +169 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 361 +170 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 0 +171 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 0 +172 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 0 +173 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 5 +174 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 61 +184 End-to-End_Error 0x0032 100 100 --- Old_age Always - 0 +187 Reported_Uncorrect 0x0032 100 100 --- Old_age Always - 0 +188 Command_Timeout 0x0032 100 100 --- Old_age Always - 0 +194 Temperature_Celsius 0x0022 077 059 --- Old_age Always - 23 (Min/Max 16/59) +199 UDMA_CRC_Error_Count 0x0032 100 100 --- Old_age Always - 0 +230 Unknown_SSD_Attribute 0x0032 001 001 --- Old_age Always - 279176151105 +232 Available_Reservd_Space 0x0033 100 100 004 Pre-fail Always - 100 +233 Media_Wearout_Indicator 0x0032 100 100 --- Old_age Always - 5374 +234 Unknown_Attribute 0x0032 100 100 --- Old_age Always - 7530 +241 Total_LBAs_Written 0x0030 253 253 --- Old_age Offline - 6756 +242 Total_LBAs_Read 0x0030 253 253 --- Old_age Offline - 963 +244 Unknown_Attribute 0x0032 000 100 --- Old_age Always - 0 + +SMART Error Log Version: 1 +No Errors Logged + +SMART Self-test log structure revision number 1 +No self-tests have been logged. [To run self-tests, use: smartctl -t] + +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): @@ -948,3 +1038,13 @@ def test_transcend_ssd(self, mock_exec): 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 + swissbit_ssd = SsdUtil('/dev/sda') + assert swissbit_ssd.get_health() == '100' + assert swissbit_ssd.get_model() == 'WDC PC SA530 SDASN8Y1T00' + assert swissbit_ssd.get_firmware() == "40103000" + assert swissbit_ssd.get_temperature() == '23' + assert swissbit_ssd.get_serial() == "2122FF441406" From 0e67cd755ef51c5bdc11aa3dcfbd0cf8efefcdfe Mon Sep 17 00:00:00 2001 From: Eran Dahan Date: Thu, 15 Feb 2024 16:31:30 +0200 Subject: [PATCH 4/7] fix assert in test case --- tests/ssd_generic_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ssd_generic_test.py b/tests/ssd_generic_test.py index a3ac477a8..988800c53 100644 --- a/tests/ssd_generic_test.py +++ b/tests/ssd_generic_test.py @@ -1042,9 +1042,9 @@ def test_transcend_ssd(self, mock_exec): @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 - swissbit_ssd = SsdUtil('/dev/sda') - assert swissbit_ssd.get_health() == '100' - assert swissbit_ssd.get_model() == 'WDC PC SA530 SDASN8Y1T00' - assert swissbit_ssd.get_firmware() == "40103000" - assert swissbit_ssd.get_temperature() == '23' - assert swissbit_ssd.get_serial() == "2122FF441406" + wdc_ssd = SsdUtil('/dev/sda') + assert wdc_ssd.get_health() == '98' + 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" From 8e8188fe89924bbdbc73fec2a279404d7a0a9cbb Mon Sep 17 00:00:00 2001 From: Eran Dahan Date: Thu, 15 Feb 2024 16:42:56 +0200 Subject: [PATCH 5/7] fix test case, change string to int --- tests/ssd_generic_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ssd_generic_test.py b/tests/ssd_generic_test.py index 988800c53..3a6e27e1e 100644 --- a/tests/ssd_generic_test.py +++ b/tests/ssd_generic_test.py @@ -1043,7 +1043,7 @@ def test_transcend_ssd(self, mock_exec): def test_wdc_ssd(self, mock_exec): mock_exec.return_value = output_wdc_vendor wdc_ssd = SsdUtil('/dev/sda') - assert wdc_ssd.get_health() == '98' + assert wdc_ssd.get_health() == 98 assert wdc_ssd.get_model() == 'WDC PC SA530 SDASN8Y1T00' assert wdc_ssd.get_firmware() == "40103000" assert wdc_ssd.get_temperature() == '23' From 67952e2666a2f28a3a3b8c1f0a44a9f5b63ca6f5 Mon Sep 17 00:00:00 2001 From: Eran Dahan Date: Thu, 15 Feb 2024 16:54:55 +0200 Subject: [PATCH 6/7] fix test - get temperature --- tests/ssd_generic_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ssd_generic_test.py b/tests/ssd_generic_test.py index 3a6e27e1e..5c19c7c34 100644 --- a/tests/ssd_generic_test.py +++ b/tests/ssd_generic_test.py @@ -1046,5 +1046,5 @@ def test_wdc_ssd(self, mock_exec): assert wdc_ssd.get_health() == 98 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_temperature() == '23 (Min/Max 16/59)' assert wdc_ssd.get_serial() == "2122FF441406" From 8c089613b231cdc8b3aa6f613b20385c824301cb Mon Sep 17 00:00:00 2001 From: Eran Dahan Date: Thu, 2 May 2024 09:47:34 +0300 Subject: [PATCH 7/7] change temprature regex to return scalar value only --- sonic_platform_base/sonic_ssd/ssd_generic.py | 2 +- tests/ssd_generic_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sonic_platform_base/sonic_ssd/ssd_generic.py b/sonic_platform_base/sonic_ssd/ssd_generic.py index 1ec2b4c11..0945d7a11 100644 --- a/sonic_platform_base/sonic_ssd/ssd_generic.py +++ b/sonic_platform_base/sonic_ssd/ssd_generic.py @@ -143,7 +143,7 @@ def parse_wdc_ssd_info(self): total_lbas_written = int(self._parse_re('\s{7}\d*', parsed_total_lbas_written).split(' ')[7]) self.health = int(100.0 - (total_lbas_written * 100) / self.nand_endurance) celsius_str = self._parse_re('Temperature_Celsius\s*.*', self.vendor_ssd_info) - self.temperature = self._parse_re('\d*\s\(Min.*', celsius_str) + self.temperature = self._parse_re('(\d*)\s\(Min.*', celsius_str) except (ValueError, IndexError): pass diff --git a/tests/ssd_generic_test.py b/tests/ssd_generic_test.py index 5c19c7c34..3a6e27e1e 100644 --- a/tests/ssd_generic_test.py +++ b/tests/ssd_generic_test.py @@ -1046,5 +1046,5 @@ def test_wdc_ssd(self, mock_exec): assert wdc_ssd.get_health() == 98 assert wdc_ssd.get_model() == 'WDC PC SA530 SDASN8Y1T00' assert wdc_ssd.get_firmware() == "40103000" - assert wdc_ssd.get_temperature() == '23 (Min/Max 16/59)' + assert wdc_ssd.get_temperature() == '23' assert wdc_ssd.get_serial() == "2122FF441406"