]> git.sur5r.net Git - u-boot/blob - test/py/tests/test_ums.py
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / test / py / tests / test_ums.py
1 # SPDX-License-Identifier: GPL-2.0
2 # Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
3
4 # Test U-Boot's "ums" command. The test starts UMS in U-Boot, waits for USB
5 # device enumeration on the host, reads a small block of data from the UMS
6 # block device, optionally mounts a partition and performs filesystem-based
7 # read/write tests, and finally aborts the "ums" command in U-Boot.
8
9 import os
10 import os.path
11 import pytest
12 import re
13 import time
14 import u_boot_utils
15
16 """
17 Note: This test relies on:
18
19 a) boardenv_* to contain configuration values to define which USB ports are
20 available for testing. Without this, this test will be automatically skipped.
21 For example:
22
23 # Leave this list empty if you have no block_devs below with writable
24 # partitions defined.
25 env__mount_points = (
26     "/mnt/ubtest-mnt-p2371-2180-na",
27 )
28
29 env__usb_dev_ports = (
30     {
31         "fixture_id": "micro_b",
32         "tgt_usb_ctlr": "0",
33         "host_ums_dev_node": "/dev/disk/by-path/pci-0000:00:14.0-usb-0:13:1.0-scsi-0:0:0:0",
34     },
35 )
36
37 env__block_devs = (
38     # eMMC; always present
39     {
40         "fixture_id": "emmc",
41         "type": "mmc",
42         "id": "0",
43         # The following two properties are optional.
44         # If present, the partition will be mounted and a file written-to and
45         # read-from it. If missing, only a simple block read test will be
46         # performed.
47         "writable_fs_partition": 1,
48         "writable_fs_subdir": "tmp/",
49     },
50     # SD card; present since I plugged one in
51     {
52         "fixture_id": "sd",
53         "type": "mmc",
54         "id": "1"
55     },
56 )
57
58 b) udev rules to set permissions on devices nodes, so that sudo is not
59 required. For example:
60
61 ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", KERNELS=="3-13", MODE:="666"
62
63 (You may wish to change the group ID instead of setting the permissions wide
64 open. All that matters is that the user ID running the test can access the
65 device.)
66
67 c) /etc/fstab entries to allow the block device to be mounted without requiring
68 root permissions. For example:
69
70 /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
71
72 This entry is only needed if any block_devs above contain a
73 writable_fs_partition value.
74 """
75
76 @pytest.mark.buildconfigspec('cmd_usb_mass_storage')
77 def test_ums(u_boot_console, env__usb_dev_port, env__block_devs):
78     """Test the "ums" command; the host system must be able to enumerate a UMS
79     device when "ums" is running, block and optionally file I/O are tested,
80     and this device must disappear when "ums" is aborted.
81
82     Args:
83         u_boot_console: A U-Boot console connection.
84         env__usb_dev_port: The single USB device-mode port specification on
85             which to run the test. See the file-level comment above for
86             details of the format.
87         env__block_devs: The list of block devices that the target U-Boot
88             device has attached. See the file-level comment above for details
89             of the format.
90
91     Returns:
92         Nothing.
93     """
94
95     have_writable_fs_partition = 'writable_fs_partition' in env__block_devs[0]
96     if not have_writable_fs_partition:
97         # If 'writable_fs_subdir' is missing, we'll skip all parts of the
98         # testing which mount filesystems.
99         u_boot_console.log.warning(
100             'boardenv missing "writable_fs_partition"; ' +
101             'UMS testing will be limited.')
102
103     tgt_usb_ctlr = env__usb_dev_port['tgt_usb_ctlr']
104     host_ums_dev_node = env__usb_dev_port['host_ums_dev_node']
105
106     # We're interested in testing USB device mode on each port, not the cross-
107     # product of that with each device. So, just pick the first entry in the
108     # device list here. We'll test each block device somewhere else.
109     tgt_dev_type = env__block_devs[0]['type']
110     tgt_dev_id = env__block_devs[0]['id']
111     if have_writable_fs_partition:
112         mount_point = u_boot_console.config.env['env__mount_points'][0]
113         mount_subdir = env__block_devs[0]['writable_fs_subdir']
114         part_num = env__block_devs[0]['writable_fs_partition']
115         host_ums_part_node = '%s-part%d' % (host_ums_dev_node, part_num)
116     else:
117         host_ums_part_node = host_ums_dev_node
118
119     test_f = u_boot_utils.PersistentRandomFile(u_boot_console, 'ums.bin',
120         1024 * 1024);
121     if have_writable_fs_partition:
122         mounted_test_fn = mount_point + '/' + mount_subdir + test_f.fn
123
124     def start_ums():
125         """Start U-Boot's ums shell command.
126
127         This also waits for the host-side USB enumeration process to complete.
128
129         Args:
130             None.
131
132         Returns:
133             Nothing.
134         """
135
136         u_boot_console.log.action(
137             'Starting long-running U-Boot ums shell command')
138         cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
139         u_boot_console.run_command(cmd, wait_for_prompt=False)
140         u_boot_console.wait_for(re.compile('UMS: LUN.*[\r\n]'))
141         fh = u_boot_utils.wait_until_open_succeeds(host_ums_part_node)
142         u_boot_console.log.action('Reading raw data from UMS device')
143         fh.read(4096)
144         fh.close()
145
146     def mount():
147         """Mount the block device that U-Boot exports.
148
149         Args:
150             None.
151
152         Returns:
153             Nothing.
154         """
155
156         u_boot_console.log.action('Mounting exported UMS device')
157         cmd = ('/bin/mount', host_ums_part_node)
158         u_boot_utils.run_and_log(u_boot_console, cmd)
159
160     def umount(ignore_errors):
161         """Unmount the block device that U-Boot exports.
162
163         Args:
164             ignore_errors: Ignore any errors. This is useful if an error has
165                 already been detected, and the code is performing best-effort
166                 cleanup. In this case, we do not want to mask the original
167                 error by "honoring" any new errors.
168
169         Returns:
170             Nothing.
171         """
172
173         u_boot_console.log.action('Unmounting UMS device')
174         cmd = ('/bin/umount', host_ums_part_node)
175         u_boot_utils.run_and_log(u_boot_console, cmd, ignore_errors)
176
177     def stop_ums(ignore_errors):
178         """Stop U-Boot's ums shell command from executing.
179
180         This also waits for the host-side USB de-enumeration process to
181         complete.
182
183         Args:
184             ignore_errors: Ignore any errors. This is useful if an error has
185                 already been detected, and the code is performing best-effort
186                 cleanup. In this case, we do not want to mask the original
187                 error by "honoring" any new errors.
188
189         Returns:
190             Nothing.
191         """
192
193         u_boot_console.log.action(
194             'Stopping long-running U-Boot ums shell command')
195         u_boot_console.ctrlc()
196         u_boot_utils.wait_until_file_open_fails(host_ums_part_node,
197             ignore_errors)
198
199     ignore_cleanup_errors = True
200     try:
201         start_ums()
202         if not have_writable_fs_partition:
203             # Skip filesystem-based testing if not configured
204             return
205         try:
206             mount()
207             u_boot_console.log.action('Writing test file via UMS')
208             cmd = ('rm', '-f', mounted_test_fn)
209             u_boot_utils.run_and_log(u_boot_console, cmd)
210             if os.path.exists(mounted_test_fn):
211                 raise Exception('Could not rm target UMS test file')
212             cmd = ('cp', test_f.abs_fn, mounted_test_fn)
213             u_boot_utils.run_and_log(u_boot_console, cmd)
214             ignore_cleanup_errors = False
215         finally:
216             umount(ignore_errors=ignore_cleanup_errors)
217     finally:
218         stop_ums(ignore_errors=ignore_cleanup_errors)
219
220     ignore_cleanup_errors = True
221     try:
222         start_ums()
223         try:
224             mount()
225             u_boot_console.log.action('Reading test file back via UMS')
226             read_back_hash = u_boot_utils.md5sum_file(mounted_test_fn)
227             cmd = ('rm', '-f', mounted_test_fn)
228             u_boot_utils.run_and_log(u_boot_console, cmd)
229             ignore_cleanup_errors = False
230         finally:
231             umount(ignore_errors=ignore_cleanup_errors)
232     finally:
233         stop_ums(ignore_errors=ignore_cleanup_errors)
234
235     written_hash = test_f.content_hash
236     assert(written_hash == read_back_hash)