blob: fa13a393fc6e3034b483d0ad46ca0433b13bf8a9 [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')
Simon Glassddba5202025-02-09 09:07:14 -070077def test_ums(ubman, 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:
Simon Glassddba5202025-02-09 09:07:14 -070083 ubman: A U-Boot console connection.
Stephen Warrend46df832016-01-22 12:30:13 -070084 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.
Simon Glassddba5202025-02-09 09:07:14 -070099 ubman.log.warning(
Stephen Warrend46df832016-01-22 12:30:13 -0700100 '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:
Simon Glassddba5202025-02-09 09:07:14 -0700112 mount_point = ubman.config.env['env__mount_points'][0]
Stephen Warrend46df832016-01-22 12:30:13 -0700113 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)
Simon Glassddba5202025-02-09 09:07:14 -0700116 test_f = u_boot_utils.PersistentRandomFile(ubman, 'ums.bin',
Tom Rini76b09e02025-02-12 16:24:00 -0600117 1024 * 1024);
118 mounted_test_fn = mount_point + '/' + mount_subdir + test_f.fn
Stephen Warrend46df832016-01-22 12:30:13 -0700119 else:
120 host_ums_part_node = host_ums_dev_node
121
Stephen Warrend46df832016-01-22 12:30:13 -0700122 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
Simon Glassddba5202025-02-09 09:07:14 -0700134 ubman.log.action(
Stephen Warrend46df832016-01-22 12:30:13 -0700135 'Starting long-running U-Boot ums shell command')
136 cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
Simon Glassddba5202025-02-09 09:07:14 -0700137 ubman.run_command(cmd, wait_for_prompt=False)
138 ubman.wait_for(re.compile('UMS: LUN.*[\r\n]'))
Stephen Warrend46df832016-01-22 12:30:13 -0700139 fh = u_boot_utils.wait_until_open_succeeds(host_ums_part_node)
Simon Glassddba5202025-02-09 09:07:14 -0700140 ubman.log.action('Reading raw data from UMS device')
Stephen Warrend46df832016-01-22 12:30:13 -0700141 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
Simon Glassddba5202025-02-09 09:07:14 -0700154 ubman.log.action('Mounting exported UMS device')
Stephen Warrend46df832016-01-22 12:30:13 -0700155 cmd = ('/bin/mount', host_ums_part_node)
Simon Glassddba5202025-02-09 09:07:14 -0700156 u_boot_utils.run_and_log(ubman, cmd)
Stephen Warrend46df832016-01-22 12:30:13 -0700157
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
Simon Glassddba5202025-02-09 09:07:14 -0700171 ubman.log.action('Unmounting UMS device')
Stephen Warrend46df832016-01-22 12:30:13 -0700172 cmd = ('/bin/umount', host_ums_part_node)
Simon Glassddba5202025-02-09 09:07:14 -0700173 u_boot_utils.run_and_log(ubman, cmd, ignore_errors)
Stephen Warrend46df832016-01-22 12:30:13 -0700174
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
Simon Glassddba5202025-02-09 09:07:14 -0700191 ubman.log.action(
Stephen Warrend46df832016-01-22 12:30:13 -0700192 'Stopping long-running U-Boot ums shell command')
Simon Glassddba5202025-02-09 09:07:14 -0700193 ubman.ctrlc()
Stephen Warrend46df832016-01-22 12:30:13 -0700194 u_boot_utils.wait_until_file_open_fails(host_ums_part_node,
195 ignore_errors)
196
197 ignore_cleanup_errors = True
Tom Rini76b09e02025-02-12 16:24:00 -0600198 if have_writable_fs_partition:
Stephen Warrend46df832016-01-22 12:30:13 -0700199 try:
Tom Rini76b09e02025-02-12 16:24:00 -0600200 start_ums()
201 try:
202 mount()
Simon Glassddba5202025-02-09 09:07:14 -0700203 ubman.log.action('Writing test file via UMS')
Tom Rini76b09e02025-02-12 16:24:00 -0600204 cmd = ('rm', '-f', mounted_test_fn)
Simon Glassddba5202025-02-09 09:07:14 -0700205 u_boot_utils.run_and_log(ubman, cmd)
Tom Rini76b09e02025-02-12 16:24:00 -0600206 if os.path.exists(mounted_test_fn):
207 raise Exception('Could not rm target UMS test file')
208 cmd = ('cp', test_f.abs_fn, mounted_test_fn)
Simon Glassddba5202025-02-09 09:07:14 -0700209 u_boot_utils.run_and_log(ubman, cmd)
Tom Rini76b09e02025-02-12 16:24:00 -0600210 ignore_cleanup_errors = False
211 finally:
212 umount(ignore_errors=ignore_cleanup_errors)
Stephen Warrend46df832016-01-22 12:30:13 -0700213 finally:
Tom Rini76b09e02025-02-12 16:24:00 -0600214 stop_ums(ignore_errors=ignore_cleanup_errors)
Stephen Warrend46df832016-01-22 12:30:13 -0700215
216 ignore_cleanup_errors = True
217 try:
218 start_ums()
219 try:
220 mount()
Simon Glassddba5202025-02-09 09:07:14 -0700221 ubman.log.action('Reading test file back via UMS')
Stephen Warrend46df832016-01-22 12:30:13 -0700222 read_back_hash = u_boot_utils.md5sum_file(mounted_test_fn)
223 cmd = ('rm', '-f', mounted_test_fn)
Simon Glassddba5202025-02-09 09:07:14 -0700224 u_boot_utils.run_and_log(ubman, cmd)
Stephen Warrend46df832016-01-22 12:30:13 -0700225 ignore_cleanup_errors = False
226 finally:
227 umount(ignore_errors=ignore_cleanup_errors)
228 finally:
229 stop_ums(ignore_errors=ignore_cleanup_errors)
Stephen Warrendf278bb2016-01-15 11:15:30 -0700230
Stephen Warrend46df832016-01-22 12:30:13 -0700231 written_hash = test_f.content_hash
232 assert(written_hash == read_back_hash)