blob: 749b1606235c78e88e84b311f636657e08a4fb60 [file] [log] [blame]
Stephen Warrendf278bb2016-01-15 11:15:30 -07001# SPDX-License-Identifier: GPL-2.0
Tom Rini10e47792018-05-06 17:58:06 -04002# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
Stephen Warrendf278bb2016-01-15 11:15:30 -07003
Stephen Warrend46df832016-01-22 12:30:13 -07004# 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.
Stephen Warrendf278bb2016-01-15 11:15:30 -07008
9import os
Stephen Warrend46df832016-01-22 12:30:13 -070010import os.path
Stephen Warrendf278bb2016-01-15 11:15:30 -070011import pytest
Stephen Warrend46df832016-01-22 12:30:13 -070012import re
Stephen Warrendf278bb2016-01-15 11:15:30 -070013import time
Stephen Warrend46df832016-01-22 12:30:13 -070014import u_boot_utils
Stephen Warrendf278bb2016-01-15 11:15:30 -070015
Stephen Warren75e731e2016-01-26 13:41:30 -070016"""
Stephen Warrendf278bb2016-01-15 11:15:30 -070017Note: This test relies on:
18
19a) boardenv_* to contain configuration values to define which USB ports are
20available for testing. Without this, this test will be automatically skipped.
21For example:
22
Stephen Warrend46df832016-01-22 12:30:13 -070023# Leave this list empty if you have no block_devs below with writable
24# partitions defined.
25env__mount_points = (
Simon Glasse9f4d872018-12-27 08:11:13 -070026 '/mnt/ubtest-mnt-p2371-2180-na',
Stephen Warrend46df832016-01-22 12:30:13 -070027)
28
Stephen Warrendf278bb2016-01-15 11:15:30 -070029env__usb_dev_ports = (
Stephen Warrend46df832016-01-22 12:30:13 -070030 {
Simon Glasse9f4d872018-12-27 08:11:13 -070031 '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',
Stephen Warrend46df832016-01-22 12:30:13 -070034 },
Stephen Warrendf278bb2016-01-15 11:15:30 -070035)
36
37env__block_devs = (
Stephen Warrend46df832016-01-22 12:30:13 -070038 # eMMC; always present
39 {
Simon Glasse9f4d872018-12-27 08:11:13 -070040 'fixture_id': 'emmc',
41 'type': 'mmc',
42 'id': '0',
Stephen Warrend46df832016-01-22 12:30:13 -070043 # 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.
Simon Glasse9f4d872018-12-27 08:11:13 -070047 'writable_fs_partition': 1,
48 'writable_fs_subdir': 'tmp/',
Stephen Warrend46df832016-01-22 12:30:13 -070049 },
50 # SD card; present since I plugged one in
51 {
Simon Glasse9f4d872018-12-27 08:11:13 -070052 'fixture_id': 'sd',
53 'type': 'mmc',
54 'id': '1'
Stephen Warrend46df832016-01-22 12:30:13 -070055 },
Stephen Warrendf278bb2016-01-15 11:15:30 -070056)
57
58b) udev rules to set permissions on devices nodes, so that sudo is not
59required. For example:
60
61ACTION=="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
64open. All that matters is that the user ID running the test can access the
65device.)
Stephen Warrendf278bb2016-01-15 11:15:30 -070066
Stephen Warrend46df832016-01-22 12:30:13 -070067c) /etc/fstab entries to allow the block device to be mounted without requiring
68root permissions. For example:
Stephen Warrendf278bb2016-01-15 11:15:30 -070069
Stephen Warrend46df832016-01-22 12:30:13 -070070/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 -070071
Stephen Warrend46df832016-01-22 12:30:13 -070072This entry is only needed if any block_devs above contain a
73writable_fs_partition value.
Stephen Warren75e731e2016-01-26 13:41:30 -070074"""
Stephen Warrendf278bb2016-01-15 11:15:30 -070075
76@pytest.mark.buildconfigspec('cmd_usb_mass_storage')
77def test_ums(u_boot_console, env__usb_dev_port, env__block_devs):
Stephen Warren75e731e2016-01-26 13:41:30 -070078 """Test the "ums" command; the host system must be able to enumerate a UMS
Stephen Warrend46df832016-01-22 12:30:13 -070079 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.
Stephen Warren75e731e2016-01-26 13:41:30 -070093 """
Stephen Warrend46df832016-01-22 12:30:13 -070094
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.')
Stephen Warrendf278bb2016-01-15 11:15:30 -0700102
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']
Stephen Warrend46df832016-01-22 12:30:13 -0700111 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():
Stephen Warren75e731e2016-01-26 13:41:30 -0700125 """Start U-Boot's ums shell command.
Stephen Warrend46df832016-01-22 12:30:13 -0700126
127 This also waits for the host-side USB enumeration process to complete.
128
129 Args:
130 None.
131
132 Returns:
133 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700134 """
Stephen Warrend46df832016-01-22 12:30:13 -0700135
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():
Stephen Warren75e731e2016-01-26 13:41:30 -0700147 """Mount the block device that U-Boot exports.
Stephen Warrend46df832016-01-22 12:30:13 -0700148
149 Args:
150 None.
151
152 Returns:
153 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700154 """
Stephen Warrend46df832016-01-22 12:30:13 -0700155
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):
Stephen Warren75e731e2016-01-26 13:41:30 -0700161 """Unmount the block device that U-Boot exports.
Stephen Warrend46df832016-01-22 12:30:13 -0700162
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.
Stephen Warren75e731e2016-01-26 13:41:30 -0700171 """
Stephen Warrend46df832016-01-22 12:30:13 -0700172
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):
Stephen Warren75e731e2016-01-26 13:41:30 -0700178 """Stop U-Boot's ums shell command from executing.
Stephen Warrend46df832016-01-22 12:30:13 -0700179
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.
Stephen Warren75e731e2016-01-26 13:41:30 -0700191 """
Stephen Warrend46df832016-01-22 12:30:13 -0700192
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)
Stephen Warrendf278bb2016-01-15 11:15:30 -0700234
Stephen Warrend46df832016-01-22 12:30:13 -0700235 written_hash = test_f.content_hash
236 assert(written_hash == read_back_hash)