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