1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging, os, re
6from autotest_lib.client.bin import test, utils
7from autotest_lib.client.common_lib import error
8
9
10class hardware_StorageWearoutDetect(test.test):
11    """
12    Check wear out status for storage device available in SMART for SSD and
13    in ext_csd for eMMC version 5.0 or later. For previous version of eMMC,
14    it will be treat as data not available.
15
16    The test will be failed if:
17    - At least one SMART variable has value under its threshold
18      or
19    - eMMC wear out status variable is in 90-100% band or higher (
20      DEVICE_LIFE_TIME_EST_TYP_A). Seeing this consistently means the lab
21      device may have to be replaced.
22    """
23
24    version = 1
25    STORAGE_INFO_PATH = '/var/log/storage_info.txt'
26    STORAGE_INFO_COMMON_PATH = '/usr/share/misc/storage-info-common.sh'
27
28    # Example     "   Model Number:    LITEONIT LSS-32L6G-HP"
29    SSD_DETECT = r"\s*Model Number:\s*(?P<model>.*)\s*$"
30
31    # Example     "   Extended CSD rev 1.7 (MMC 5.0)"
32    MMC_DETECT = r"\s*Extended CSD rev.*MMC (?P<version>\d+.\d+)"
33
34    # Field meaning and example line that have failing attribute
35    # ID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE
36    # 184 End-to-End_Error        PO--CK   001   001   097    NOW  135
37    SSD_FAIL = r"""\s*(?P<param>\S+\s\S+)      # ID and attribute name
38                   \s+[P-][O-][S-][R-][C-][K-] # flags
39                   (\s+\d{3}){3}               # three 3-digits numbers
40                   \s+NOW                      # fail indicator"""
41
42    # Ex "Device life time estimation type A [DEVICE_LIFE_TIME_EST_TYP_A: 0x01]"
43    # 0x0a means 90-100% band, 0x0b means over 100% band -> find not digit
44    MMC_FAIL = r".*(?P<param>DEVICE_LIFE_TIME_EST_TYP_.): 0x0\D"
45
46
47    def run_once(self, use_cached_result=True):
48        """
49        Run the test
50
51        @param use_cached_result: Use the result that generated when machine
52                                  booted or generate new one.
53        """
54
55        if not use_cached_result:
56            if not os.path.exists(self.STORAGE_INFO_COMMON_PATH):
57                msg = str('Test failed with error: %s not exist'
58                          % self.STORAGE_INFO_COMMON_PATH)
59                raise error.TestFail(msg)
60            cmd = ' '.join(['. %s;' % (self.STORAGE_INFO_COMMON_PATH, ),
61                            'get_storage_info'])
62            utils.run(cmd, stdout_tee=open(self.STORAGE_INFO_PATH, 'w'),
63                      stderr_tee=utils.TEE_TO_LOGS)
64
65        # Check that storage_info file exist.
66        if not os.path.exists(self.STORAGE_INFO_PATH):
67            msg = str('Test failed with error: %s not exist'
68                      % self.STORAGE_INFO_PATH)
69            raise error.TestFail(msg)
70
71        mmc_detect = False
72        ssd_detect = False
73        legacy_mmc = False
74        fail_msg = ''
75
76        with open(self.STORAGE_INFO_PATH) as f:
77            for line in f:
78                m = re.match(self.SSD_DETECT, line)
79                if m:
80                    model = m.group('model')
81                    ssd_detect = True
82                    logging.info('Found SSD model %s', model)
83
84                m = re.match(self.MMC_DETECT, line)
85                if m:
86                    version = m.group('version')
87                    if float(version) < 5.0:
88                        legacy_mmc = True
89                    mmc_detect = True
90                    logging.info('Found eMMC version %s', version)
91
92                m = re.match(self.SSD_FAIL, line, re.X)
93                if m:
94                    param = m.group('param')
95                    fail_msg += 'SSD failure ' + param
96
97                m = re.match(self.MMC_FAIL, line)
98                if m:
99                    param = m.group('param')
100                    fail_msg += 'MMC failure ' + param
101
102        if not ssd_detect and not mmc_detect:
103            raise error.TestFail('Can not detect storage device.')
104
105        if fail_msg:
106            msg = 'Detected wearout parameter:%s' % fail_msg
107            raise error.TestFail(msg)
108
109        if legacy_mmc:
110            msg = 'eMMC version %s detected. ' % version
111            msg += 'Wearout attributes are supported in eMMC 5.0 and later.'
112            logging.info(msg)
113