xref: /rk3399_rockchip-uboot/test/py/tests/test_ums.py (revision 8a36287a019f5d7532a8a1a7da6aa96e490dbb8a)
13045d7f0SStephen Warren# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
23045d7f0SStephen Warren#
33045d7f0SStephen Warren# SPDX-License-Identifier: GPL-2.0
43045d7f0SStephen Warren
5d054f4c2SStephen Warren# Test U-Boot's "ums" command. The test starts UMS in U-Boot, waits for USB
6d054f4c2SStephen Warren# device enumeration on the host, reads a small block of data from the UMS
7d054f4c2SStephen Warren# block device, optionally mounts a partition and performs filesystem-based
8d054f4c2SStephen Warren# read/write tests, and finally aborts the "ums" command in U-Boot.
93045d7f0SStephen Warren
103045d7f0SStephen Warrenimport os
11d054f4c2SStephen Warrenimport os.path
123045d7f0SStephen Warrenimport pytest
13d054f4c2SStephen Warrenimport re
143045d7f0SStephen Warrenimport time
15d054f4c2SStephen Warrenimport u_boot_utils
163045d7f0SStephen Warren
17e8debf39SStephen Warren"""
183045d7f0SStephen WarrenNote: This test relies on:
193045d7f0SStephen Warren
203045d7f0SStephen Warrena) boardenv_* to contain configuration values to define which USB ports are
213045d7f0SStephen Warrenavailable for testing. Without this, this test will be automatically skipped.
223045d7f0SStephen WarrenFor example:
233045d7f0SStephen Warren
24d054f4c2SStephen Warren# Leave this list empty if you have no block_devs below with writable
25d054f4c2SStephen Warren# partitions defined.
26d054f4c2SStephen Warrenenv__mount_points = (
27d054f4c2SStephen Warren    "/mnt/ubtest-mnt-p2371-2180-na",
28d054f4c2SStephen Warren)
29d054f4c2SStephen Warren
303045d7f0SStephen Warrenenv__usb_dev_ports = (
31d054f4c2SStephen Warren    {
32*d20e5e97SStephen Warren        "fixture_id": "micro_b",
33d054f4c2SStephen Warren        "tgt_usb_ctlr": "0",
34d054f4c2SStephen Warren        "host_ums_dev_node": "/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0",
35d054f4c2SStephen Warren    },
363045d7f0SStephen Warren)
373045d7f0SStephen Warren
383045d7f0SStephen Warrenenv__block_devs = (
39d054f4c2SStephen Warren    # eMMC; always present
40d054f4c2SStephen Warren    {
41*d20e5e97SStephen Warren        "fixture_id": "emmc",
42d054f4c2SStephen Warren        "type": "mmc",
43d054f4c2SStephen Warren        "id": "0",
44d054f4c2SStephen Warren        # The following two properties are optional.
45d054f4c2SStephen Warren        # If present, the partition will be mounted and a file written-to and
46d054f4c2SStephen Warren        # read-from it. If missing, only a simple block read test will be
47d054f4c2SStephen Warren        # performed.
48d054f4c2SStephen Warren        "writable_fs_partition": 1,
49d054f4c2SStephen Warren        "writable_fs_subdir": "tmp/",
50d054f4c2SStephen Warren    },
51d054f4c2SStephen Warren    # SD card; present since I plugged one in
52d054f4c2SStephen Warren    {
53*d20e5e97SStephen Warren        "fixture_id": "sd",
54d054f4c2SStephen Warren        "type": "mmc",
55d054f4c2SStephen Warren        "id": "1"
56d054f4c2SStephen Warren    },
573045d7f0SStephen Warren)
583045d7f0SStephen Warren
593045d7f0SStephen Warrenb) udev rules to set permissions on devices nodes, so that sudo is not
603045d7f0SStephen Warrenrequired. For example:
613045d7f0SStephen Warren
623045d7f0SStephen WarrenACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", KERNELS=="3-13", MODE:="666"
633045d7f0SStephen Warren
643045d7f0SStephen Warren(You may wish to change the group ID instead of setting the permissions wide
653045d7f0SStephen Warrenopen. All that matters is that the user ID running the test can access the
663045d7f0SStephen Warrendevice.)
67d054f4c2SStephen Warren
68d054f4c2SStephen Warrenc) /etc/fstab entries to allow the block device to be mounted without requiring
69d054f4c2SStephen Warrenroot permissions. For example:
70d054f4c2SStephen Warren
71d054f4c2SStephen Warren/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0-part1 /mnt/ubtest-mnt-p2371-2180-na ext4 noauto,user,nosuid,nodev
72d054f4c2SStephen Warren
73d054f4c2SStephen WarrenThis entry is only needed if any block_devs above contain a
74d054f4c2SStephen Warrenwritable_fs_partition value.
75e8debf39SStephen Warren"""
763045d7f0SStephen Warren
773045d7f0SStephen Warren@pytest.mark.buildconfigspec('cmd_usb_mass_storage')
783045d7f0SStephen Warrendef test_ums(u_boot_console, env__usb_dev_port, env__block_devs):
79e8debf39SStephen Warren    """Test the "ums" command; the host system must be able to enumerate a UMS
80d054f4c2SStephen Warren    device when "ums" is running, block and optionally file I/O are tested,
81d054f4c2SStephen Warren    and this device must disappear when "ums" is aborted.
82d054f4c2SStephen Warren
83d054f4c2SStephen Warren    Args:
84d054f4c2SStephen Warren        u_boot_console: A U-Boot console connection.
85d054f4c2SStephen Warren        env__usb_dev_port: The single USB device-mode port specification on
86d054f4c2SStephen Warren            which to run the test. See the file-level comment above for
87d054f4c2SStephen Warren            details of the format.
88d054f4c2SStephen Warren        env__block_devs: The list of block devices that the target U-Boot
89d054f4c2SStephen Warren            device has attached. See the file-level comment above for details
90d054f4c2SStephen Warren            of the format.
91d054f4c2SStephen Warren
92d054f4c2SStephen Warren    Returns:
93d054f4c2SStephen Warren        Nothing.
94e8debf39SStephen Warren    """
95d054f4c2SStephen Warren
96d054f4c2SStephen Warren    have_writable_fs_partition = 'writable_fs_partition' in env__block_devs[0]
97d054f4c2SStephen Warren    if not have_writable_fs_partition:
98d054f4c2SStephen Warren        # If 'writable_fs_subdir' is missing, we'll skip all parts of the
99d054f4c2SStephen Warren        # testing which mount filesystems.
100d054f4c2SStephen Warren        u_boot_console.log.warning(
101d054f4c2SStephen Warren            'boardenv missing "writable_fs_partition"; ' +
102d054f4c2SStephen Warren            'UMS testing will be limited.')
1033045d7f0SStephen Warren
1043045d7f0SStephen Warren    tgt_usb_ctlr = env__usb_dev_port['tgt_usb_ctlr']
1053045d7f0SStephen Warren    host_ums_dev_node = env__usb_dev_port['host_ums_dev_node']
1063045d7f0SStephen Warren
1073045d7f0SStephen Warren    # We're interested in testing USB device mode on each port, not the cross-
1083045d7f0SStephen Warren    # product of that with each device. So, just pick the first entry in the
1093045d7f0SStephen Warren    # device list here. We'll test each block device somewhere else.
1103045d7f0SStephen Warren    tgt_dev_type = env__block_devs[0]['type']
1113045d7f0SStephen Warren    tgt_dev_id = env__block_devs[0]['id']
112d054f4c2SStephen Warren    if have_writable_fs_partition:
113d054f4c2SStephen Warren        mount_point = u_boot_console.config.env['env__mount_points'][0]
114d054f4c2SStephen Warren        mount_subdir = env__block_devs[0]['writable_fs_subdir']
115d054f4c2SStephen Warren        part_num = env__block_devs[0]['writable_fs_partition']
116d054f4c2SStephen Warren        host_ums_part_node = '%s-part%d' % (host_ums_dev_node, part_num)
117d054f4c2SStephen Warren    else:
118d054f4c2SStephen Warren        host_ums_part_node = host_ums_dev_node
1193045d7f0SStephen Warren
120d054f4c2SStephen Warren    test_f = u_boot_utils.PersistentRandomFile(u_boot_console, 'ums.bin',
121d054f4c2SStephen Warren        1024 * 1024);
122d054f4c2SStephen Warren    if have_writable_fs_partition:
123d054f4c2SStephen Warren        mounted_test_fn = mount_point + '/' + mount_subdir + test_f.fn
124d054f4c2SStephen Warren
125d054f4c2SStephen Warren    def start_ums():
126e8debf39SStephen Warren        """Start U-Boot's ums shell command.
127d054f4c2SStephen Warren
128d054f4c2SStephen Warren        This also waits for the host-side USB enumeration process to complete.
129d054f4c2SStephen Warren
130d054f4c2SStephen Warren        Args:
131d054f4c2SStephen Warren            None.
132d054f4c2SStephen Warren
133d054f4c2SStephen Warren        Returns:
134d054f4c2SStephen Warren            Nothing.
135e8debf39SStephen Warren        """
136d054f4c2SStephen Warren
137d054f4c2SStephen Warren        u_boot_console.log.action(
138d054f4c2SStephen Warren            'Starting long-running U-Boot ums shell command')
1393045d7f0SStephen Warren        cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
140d054f4c2SStephen Warren        u_boot_console.run_command(cmd, wait_for_prompt=False)
141d054f4c2SStephen Warren        u_boot_console.wait_for(re.compile('UMS: LUN.*[\r\n]'))
142d054f4c2SStephen Warren        fh = u_boot_utils.wait_until_open_succeeds(host_ums_part_node)
143d054f4c2SStephen Warren        u_boot_console.log.action('Reading raw data from UMS device')
1443045d7f0SStephen Warren        fh.read(4096)
1453045d7f0SStephen Warren        fh.close()
146d054f4c2SStephen Warren
147d054f4c2SStephen Warren    def mount():
148e8debf39SStephen Warren        """Mount the block device that U-Boot exports.
149d054f4c2SStephen Warren
150d054f4c2SStephen Warren        Args:
151d054f4c2SStephen Warren            None.
152d054f4c2SStephen Warren
153d054f4c2SStephen Warren        Returns:
154d054f4c2SStephen Warren            Nothing.
155e8debf39SStephen Warren        """
156d054f4c2SStephen Warren
157d054f4c2SStephen Warren        u_boot_console.log.action('Mounting exported UMS device')
158d054f4c2SStephen Warren        cmd = ('/bin/mount', host_ums_part_node)
159d054f4c2SStephen Warren        u_boot_utils.run_and_log(u_boot_console, cmd)
160d054f4c2SStephen Warren
161d054f4c2SStephen Warren    def umount(ignore_errors):
162e8debf39SStephen Warren        """Unmount the block device that U-Boot exports.
163d054f4c2SStephen Warren
164d054f4c2SStephen Warren        Args:
165d054f4c2SStephen Warren            ignore_errors: Ignore any errors. This is useful if an error has
166d054f4c2SStephen Warren                already been detected, and the code is performing best-effort
167d054f4c2SStephen Warren                cleanup. In this case, we do not want to mask the original
168d054f4c2SStephen Warren                error by "honoring" any new errors.
169d054f4c2SStephen Warren
170d054f4c2SStephen Warren        Returns:
171d054f4c2SStephen Warren            Nothing.
172e8debf39SStephen Warren        """
173d054f4c2SStephen Warren
174d054f4c2SStephen Warren        u_boot_console.log.action('Unmounting UMS device')
175d054f4c2SStephen Warren        cmd = ('/bin/umount', host_ums_part_node)
176d054f4c2SStephen Warren        u_boot_utils.run_and_log(u_boot_console, cmd, ignore_errors)
177d054f4c2SStephen Warren
178d054f4c2SStephen Warren    def stop_ums(ignore_errors):
179e8debf39SStephen Warren        """Stop U-Boot's ums shell command from executing.
180d054f4c2SStephen Warren
181d054f4c2SStephen Warren        This also waits for the host-side USB de-enumeration process to
182d054f4c2SStephen Warren        complete.
183d054f4c2SStephen Warren
184d054f4c2SStephen Warren        Args:
185d054f4c2SStephen Warren            ignore_errors: Ignore any errors. This is useful if an error has
186d054f4c2SStephen Warren                already been detected, and the code is performing best-effort
187d054f4c2SStephen Warren                cleanup. In this case, we do not want to mask the original
188d054f4c2SStephen Warren                error by "honoring" any new errors.
189d054f4c2SStephen Warren
190d054f4c2SStephen Warren        Returns:
191d054f4c2SStephen Warren            Nothing.
192e8debf39SStephen Warren        """
193d054f4c2SStephen Warren
194d054f4c2SStephen Warren        u_boot_console.log.action(
195d054f4c2SStephen Warren            'Stopping long-running U-Boot ums shell command')
1963045d7f0SStephen Warren        u_boot_console.ctrlc()
197d054f4c2SStephen Warren        u_boot_utils.wait_until_file_open_fails(host_ums_part_node,
198d054f4c2SStephen Warren            ignore_errors)
199d054f4c2SStephen Warren
200d054f4c2SStephen Warren    ignore_cleanup_errors = True
201d054f4c2SStephen Warren    try:
202d054f4c2SStephen Warren        start_ums()
203d054f4c2SStephen Warren        if not have_writable_fs_partition:
204d054f4c2SStephen Warren            # Skip filesystem-based testing if not configured
205d054f4c2SStephen Warren            return
206d054f4c2SStephen Warren        try:
207d054f4c2SStephen Warren            mount()
208d054f4c2SStephen Warren            u_boot_console.log.action('Writing test file via UMS')
209d054f4c2SStephen Warren            cmd = ('rm', '-f', mounted_test_fn)
210d054f4c2SStephen Warren            u_boot_utils.run_and_log(u_boot_console, cmd)
211d054f4c2SStephen Warren            if os.path.exists(mounted_test_fn):
212d054f4c2SStephen Warren                raise Exception('Could not rm target UMS test file')
213d054f4c2SStephen Warren            cmd = ('cp', test_f.abs_fn, mounted_test_fn)
214d054f4c2SStephen Warren            u_boot_utils.run_and_log(u_boot_console, cmd)
215d054f4c2SStephen Warren            ignore_cleanup_errors = False
216d054f4c2SStephen Warren        finally:
217d054f4c2SStephen Warren            umount(ignore_errors=ignore_cleanup_errors)
218d054f4c2SStephen Warren    finally:
219d054f4c2SStephen Warren        stop_ums(ignore_errors=ignore_cleanup_errors)
220d054f4c2SStephen Warren
221d054f4c2SStephen Warren    ignore_cleanup_errors = True
222d054f4c2SStephen Warren    try:
223d054f4c2SStephen Warren        start_ums()
224d054f4c2SStephen Warren        try:
225d054f4c2SStephen Warren            mount()
226d054f4c2SStephen Warren            u_boot_console.log.action('Reading test file back via UMS')
227d054f4c2SStephen Warren            read_back_hash = u_boot_utils.md5sum_file(mounted_test_fn)
228d054f4c2SStephen Warren            cmd = ('rm', '-f', mounted_test_fn)
229d054f4c2SStephen Warren            u_boot_utils.run_and_log(u_boot_console, cmd)
230d054f4c2SStephen Warren            ignore_cleanup_errors = False
231d054f4c2SStephen Warren        finally:
232d054f4c2SStephen Warren            umount(ignore_errors=ignore_cleanup_errors)
233d054f4c2SStephen Warren    finally:
234d054f4c2SStephen Warren        stop_ums(ignore_errors=ignore_cleanup_errors)
235d054f4c2SStephen Warren
236d054f4c2SStephen Warren    written_hash = test_f.content_hash
237d054f4c2SStephen Warren    assert(written_hash == read_back_hash)
238