blob: 21d40a972581b29e0f54708ef54e7f2a6868b838 [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 {
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 },
Stephen Warrendf278bb2016-01-15 11:15:30 -070035)
36
37env__block_devs = (
Stephen Warrend46df832016-01-22 12:30:13 -070038 # eMMC; always present
39 {
40 "type": "mmc",
41 "id": "0",
42 # The following two properties are optional.
43 # If present, the partition will be mounted and a file written-to and
44 # read-from it. If missing, only a simple block read test will be
45 # performed.
46 "writable_fs_partition": 1,
47 "writable_fs_subdir": "tmp/",
48 },
49 # SD card; present since I plugged one in
50 {
51 "type": "mmc",
52 "id": "1"
53 },
Stephen Warrendf278bb2016-01-15 11:15:30 -070054)
55
56b) udev rules to set permissions on devices nodes, so that sudo is not
57required. For example:
58
59ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", KERNELS=="3-13", MODE:="666"
60
61(You may wish to change the group ID instead of setting the permissions wide
62open. All that matters is that the user ID running the test can access the
63device.)
Stephen Warrendf278bb2016-01-15 11:15:30 -070064
Stephen Warrend46df832016-01-22 12:30:13 -070065c) /etc/fstab entries to allow the block device to be mounted without requiring
66root permissions. For example:
Stephen Warrendf278bb2016-01-15 11:15:30 -070067
Stephen Warrend46df832016-01-22 12:30:13 -070068/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 -070069
Stephen Warrend46df832016-01-22 12:30:13 -070070This entry is only needed if any block_devs above contain a
71writable_fs_partition value.
Stephen Warren75e731e2016-01-26 13:41:30 -070072"""
Stephen Warrendf278bb2016-01-15 11:15:30 -070073
74@pytest.mark.buildconfigspec('cmd_usb_mass_storage')
75def test_ums(u_boot_console, env__usb_dev_port, env__block_devs):
Stephen Warren75e731e2016-01-26 13:41:30 -070076 """Test the "ums" command; the host system must be able to enumerate a UMS
Stephen Warrend46df832016-01-22 12:30:13 -070077 device when "ums" is running, block and optionally file I/O are tested,
78 and this device must disappear when "ums" is aborted.
79
80 Args:
81 u_boot_console: A U-Boot console connection.
82 env__usb_dev_port: The single USB device-mode port specification on
83 which to run the test. See the file-level comment above for
84 details of the format.
85 env__block_devs: The list of block devices that the target U-Boot
86 device has attached. See the file-level comment above for details
87 of the format.
88
89 Returns:
90 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -070091 """
Stephen Warrend46df832016-01-22 12:30:13 -070092
93 have_writable_fs_partition = 'writable_fs_partition' in env__block_devs[0]
94 if not have_writable_fs_partition:
95 # If 'writable_fs_subdir' is missing, we'll skip all parts of the
96 # testing which mount filesystems.
97 u_boot_console.log.warning(
98 'boardenv missing "writable_fs_partition"; ' +
99 'UMS testing will be limited.')
Stephen Warrendf278bb2016-01-15 11:15:30 -0700100
101 tgt_usb_ctlr = env__usb_dev_port['tgt_usb_ctlr']
102 host_ums_dev_node = env__usb_dev_port['host_ums_dev_node']
103
104 # We're interested in testing USB device mode on each port, not the cross-
105 # product of that with each device. So, just pick the first entry in the
106 # device list here. We'll test each block device somewhere else.
107 tgt_dev_type = env__block_devs[0]['type']
108 tgt_dev_id = env__block_devs[0]['id']
Stephen Warrend46df832016-01-22 12:30:13 -0700109 if have_writable_fs_partition:
110 mount_point = u_boot_console.config.env['env__mount_points'][0]
111 mount_subdir = env__block_devs[0]['writable_fs_subdir']
112 part_num = env__block_devs[0]['writable_fs_partition']
113 host_ums_part_node = '%s-part%d' % (host_ums_dev_node, part_num)
114 else:
115 host_ums_part_node = host_ums_dev_node
116
117 test_f = u_boot_utils.PersistentRandomFile(u_boot_console, 'ums.bin',
118 1024 * 1024);
119 if have_writable_fs_partition:
120 mounted_test_fn = mount_point + '/' + mount_subdir + test_f.fn
121
122 def start_ums():
Stephen Warren75e731e2016-01-26 13:41:30 -0700123 """Start U-Boot's ums shell command.
Stephen Warrend46df832016-01-22 12:30:13 -0700124
125 This also waits for the host-side USB enumeration process to complete.
126
127 Args:
128 None.
129
130 Returns:
131 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700132 """
Stephen Warrend46df832016-01-22 12:30:13 -0700133
134 u_boot_console.log.action(
135 'Starting long-running U-Boot ums shell command')
136 cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
137 u_boot_console.run_command(cmd, wait_for_prompt=False)
138 u_boot_console.wait_for(re.compile('UMS: LUN.*[\r\n]'))
139 fh = u_boot_utils.wait_until_open_succeeds(host_ums_part_node)
140 u_boot_console.log.action('Reading raw data from UMS device')
141 fh.read(4096)
142 fh.close()
143
144 def mount():
Stephen Warren75e731e2016-01-26 13:41:30 -0700145 """Mount the block device that U-Boot exports.
Stephen Warrend46df832016-01-22 12:30:13 -0700146
147 Args:
148 None.
149
150 Returns:
151 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700152 """
Stephen Warrend46df832016-01-22 12:30:13 -0700153
154 u_boot_console.log.action('Mounting exported UMS device')
155 cmd = ('/bin/mount', host_ums_part_node)
156 u_boot_utils.run_and_log(u_boot_console, cmd)
157
158 def umount(ignore_errors):
Stephen Warren75e731e2016-01-26 13:41:30 -0700159 """Unmount the block device that U-Boot exports.
Stephen Warrend46df832016-01-22 12:30:13 -0700160
161 Args:
162 ignore_errors: Ignore any errors. This is useful if an error has
163 already been detected, and the code is performing best-effort
164 cleanup. In this case, we do not want to mask the original
165 error by "honoring" any new errors.
166
167 Returns:
168 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700169 """
Stephen Warrend46df832016-01-22 12:30:13 -0700170
171 u_boot_console.log.action('Unmounting UMS device')
172 cmd = ('/bin/umount', host_ums_part_node)
173 u_boot_utils.run_and_log(u_boot_console, cmd, ignore_errors)
174
175 def stop_ums(ignore_errors):
Stephen Warren75e731e2016-01-26 13:41:30 -0700176 """Stop U-Boot's ums shell command from executing.
Stephen Warrend46df832016-01-22 12:30:13 -0700177
178 This also waits for the host-side USB de-enumeration process to
179 complete.
180
181 Args:
182 ignore_errors: Ignore any errors. This is useful if an error has
183 already been detected, and the code is performing best-effort
184 cleanup. In this case, we do not want to mask the original
185 error by "honoring" any new errors.
186
187 Returns:
188 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700189 """
Stephen Warrend46df832016-01-22 12:30:13 -0700190
191 u_boot_console.log.action(
192 'Stopping long-running U-Boot ums shell command')
193 u_boot_console.ctrlc()
194 u_boot_utils.wait_until_file_open_fails(host_ums_part_node,
195 ignore_errors)
196
197 ignore_cleanup_errors = True
198 try:
199 start_ums()
200 if not have_writable_fs_partition:
201 # Skip filesystem-based testing if not configured
202 return
203 try:
204 mount()
205 u_boot_console.log.action('Writing test file via UMS')
206 cmd = ('rm', '-f', mounted_test_fn)
207 u_boot_utils.run_and_log(u_boot_console, cmd)
208 if os.path.exists(mounted_test_fn):
209 raise Exception('Could not rm target UMS test file')
210 cmd = ('cp', test_f.abs_fn, mounted_test_fn)
211 u_boot_utils.run_and_log(u_boot_console, cmd)
212 ignore_cleanup_errors = False
213 finally:
214 umount(ignore_errors=ignore_cleanup_errors)
215 finally:
216 stop_ums(ignore_errors=ignore_cleanup_errors)
217
218 ignore_cleanup_errors = True
219 try:
220 start_ums()
221 try:
222 mount()
223 u_boot_console.log.action('Reading test file back via UMS')
224 read_back_hash = u_boot_utils.md5sum_file(mounted_test_fn)
225 cmd = ('rm', '-f', mounted_test_fn)
226 u_boot_utils.run_and_log(u_boot_console, cmd)
227 ignore_cleanup_errors = False
228 finally:
229 umount(ignore_errors=ignore_cleanup_errors)
230 finally:
231 stop_ums(ignore_errors=ignore_cleanup_errors)
Stephen Warrendf278bb2016-01-15 11:15:30 -0700232
Stephen Warrend46df832016-01-22 12:30:13 -0700233 written_hash = test_f.content_hash
234 assert(written_hash == read_back_hash)