# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import os from autotest_lib.client.bin import test, utils from autotest_lib.client.common_lib import error DEFAULT_MIN_GB = 16 # Allowable amount of bits eMMC vendor can use in firmware to support bad block # replacement and metadata. EMMC_VENDOR_ALLOWED_GB = 0.25 # Amount of data available for user data in device, the rest is left for # over provisioning. # Typically a SATA device will use 7% over provisioning [the difference # between GB and GiB], but some eMMC device can use 9%. # With Flash becoming more error prone as lithography shrinks, the trend # is to increase over provisioning. DEFAULT_USER_DENSITY = 0.9 class hardware_DiskSize(test.test): """ Check that disk size is around 16GB at least. """ version = 1 def _is_emmc(self): path = os.path.join("/sys/class/block/", self._device, "device", "type") if not os.path.exists(path): return False return utils.read_one_line(path) == 'MMC' @classmethod def _gib_to_gb(cls, gib): return float(gib) * (1 << 30) / (10 ** 9) def _compute_min_gb(self): """Computes minimum size allowed primary storage device. TODO(tbroch): Add computation of raw bytes in eMMC using 'Chip Specific Data' (CSD & EXT_CSD) defined by JEDEC JESD84-A44.pdf if possible. CSD :: /sys/class/block//device/csd EXT_CSD :: debugfs Algorithm should look something like this: CSD[C_SIZE] = 0xfff == eMMC > 2GB EXT_CSD[SEC_COUNT] = # of 512byte sectors Now for existing eMMC I've examined I do see the C_SIZE == 0xfff. Unfortunately the SEC_COUNT appears to have excluded the sectors reserved for metadata & repair. Perhaps thats by design in which case there is no mechanism to determine the actual raw sectors. For now I use 0.25GB as an acceptable fudge. Returns: integer, in GB of minimum storage size. """ min_gb = DEFAULT_MIN_GB if self._is_emmc(): min_gb -= EMMC_VENDOR_ALLOWED_GB min_gb *= DEFAULT_USER_DENSITY return self._gib_to_gb(min_gb) def run_once(self): root_dev = utils.get_root_device() self._device = os.path.basename(root_dev) disk_size = utils.get_disk_size(root_dev) if not disk_size: raise error.TestError('Unable to determine main disk size') # Capacity of a hard disk is quoted with SI prefixes, incrementing by # powers of 1000, instead of powers of 1024. gb = float(disk_size) / (10 ** 9) self.write_perf_keyval({"gb_main_disk_size": gb}) min_gb = self._compute_min_gb() logging.info("DiskSize: %.3f GB MinDiskSize: %.3f GB", gb, min_gb) if (gb < min_gb): raise error.TestError("DiskSize %.3f GB below minimum (%.3f GB)" \ % (gb, min_gb))