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