blob: caf6c0a72701bc39d09a9da72c3457c446fefb12 [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
Simon Glassfb916372025-02-09 09:07:15 -070014import 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 Glassfb916372025-02-09 09:07:15 -0700116 test_f = utils.PersistentRandomFile(ubman, 'ums.bin', 1024 * 1024);
Tom Rini76b09e02025-02-12 16:24:00 -0600117 mounted_test_fn = mount_point + '/' + mount_subdir + test_f.fn
Stephen Warrend46df832016-01-22 12:30:13 -0700118 else:
119 host_ums_part_node = host_ums_dev_node
120
Stephen Warrend46df832016-01-22 12:30:13 -0700121 def start_ums():
Stephen Warren75e731e2016-01-26 13:41:30 -0700122 """Start U-Boot's ums shell command.
Stephen Warrend46df832016-01-22 12:30:13 -0700123
124 This also waits for the host-side USB enumeration process to complete.
125
126 Args:
127 None.
128
129 Returns:
130 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700131 """
Stephen Warrend46df832016-01-22 12:30:13 -0700132
Simon Glassddba5202025-02-09 09:07:14 -0700133 ubman.log.action(
Stephen Warrend46df832016-01-22 12:30:13 -0700134 'Starting long-running U-Boot ums shell command')
135 cmd = 'ums %s %s %s' % (tgt_usb_ctlr, tgt_dev_type, tgt_dev_id)
Simon Glassddba5202025-02-09 09:07:14 -0700136 ubman.run_command(cmd, wait_for_prompt=False)
137 ubman.wait_for(re.compile('UMS: LUN.*[\r\n]'))
Simon Glassfb916372025-02-09 09:07:15 -0700138 fh = utils.wait_until_open_succeeds(host_ums_part_node)
Simon Glassddba5202025-02-09 09:07:14 -0700139 ubman.log.action('Reading raw data from UMS device')
Stephen Warrend46df832016-01-22 12:30:13 -0700140 fh.read(4096)
141 fh.close()
142
143 def mount():
Stephen Warren75e731e2016-01-26 13:41:30 -0700144 """Mount the block device that U-Boot exports.
Stephen Warrend46df832016-01-22 12:30:13 -0700145
146 Args:
147 None.
148
149 Returns:
150 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700151 """
Stephen Warrend46df832016-01-22 12:30:13 -0700152
Simon Glassddba5202025-02-09 09:07:14 -0700153 ubman.log.action('Mounting exported UMS device')
Stephen Warrend46df832016-01-22 12:30:13 -0700154 cmd = ('/bin/mount', host_ums_part_node)
Simon Glassfb916372025-02-09 09:07:15 -0700155 utils.run_and_log(ubman, cmd)
Stephen Warrend46df832016-01-22 12:30:13 -0700156
157 def umount(ignore_errors):
Stephen Warren75e731e2016-01-26 13:41:30 -0700158 """Unmount the block device that U-Boot exports.
Stephen Warrend46df832016-01-22 12:30:13 -0700159
160 Args:
161 ignore_errors: Ignore any errors. This is useful if an error has
162 already been detected, and the code is performing best-effort
163 cleanup. In this case, we do not want to mask the original
164 error by "honoring" any new errors.
165
166 Returns:
167 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700168 """
Stephen Warrend46df832016-01-22 12:30:13 -0700169
Simon Glassddba5202025-02-09 09:07:14 -0700170 ubman.log.action('Unmounting UMS device')
Stephen Warrend46df832016-01-22 12:30:13 -0700171 cmd = ('/bin/umount', host_ums_part_node)
Simon Glassfb916372025-02-09 09:07:15 -0700172 utils.run_and_log(ubman, cmd, ignore_errors)
Stephen Warrend46df832016-01-22 12:30:13 -0700173
174 def stop_ums(ignore_errors):
Stephen Warren75e731e2016-01-26 13:41:30 -0700175 """Stop U-Boot's ums shell command from executing.
Stephen Warrend46df832016-01-22 12:30:13 -0700176
177 This also waits for the host-side USB de-enumeration process to
178 complete.
179
180 Args:
181 ignore_errors: Ignore any errors. This is useful if an error has
182 already been detected, and the code is performing best-effort
183 cleanup. In this case, we do not want to mask the original
184 error by "honoring" any new errors.
185
186 Returns:
187 Nothing.
Stephen Warren75e731e2016-01-26 13:41:30 -0700188 """
Stephen Warrend46df832016-01-22 12:30:13 -0700189
Simon Glassddba5202025-02-09 09:07:14 -0700190 ubman.log.action(
Stephen Warrend46df832016-01-22 12:30:13 -0700191 'Stopping long-running U-Boot ums shell command')
Simon Glassddba5202025-02-09 09:07:14 -0700192 ubman.ctrlc()
Simon Glassfb916372025-02-09 09:07:15 -0700193 utils.wait_until_file_open_fails(host_ums_part_node,
Stephen Warrend46df832016-01-22 12:30:13 -0700194 ignore_errors)
195
196 ignore_cleanup_errors = True
Tom Rini76b09e02025-02-12 16:24:00 -0600197 if have_writable_fs_partition:
Stephen Warrend46df832016-01-22 12:30:13 -0700198 try:
Tom Rini76b09e02025-02-12 16:24:00 -0600199 start_ums()
200 try:
201 mount()
Simon Glassddba5202025-02-09 09:07:14 -0700202 ubman.log.action('Writing test file via UMS')
Tom Rini76b09e02025-02-12 16:24:00 -0600203 cmd = ('rm', '-f', mounted_test_fn)
Simon Glassfb916372025-02-09 09:07:15 -0700204 utils.run_and_log(ubman, cmd)
Tom Rini76b09e02025-02-12 16:24:00 -0600205 if os.path.exists(mounted_test_fn):
206 raise Exception('Could not rm target UMS test file')
207 cmd = ('cp', test_f.abs_fn, mounted_test_fn)
Simon Glassfb916372025-02-09 09:07:15 -0700208 utils.run_and_log(ubman, cmd)
Tom Rini76b09e02025-02-12 16:24:00 -0600209 ignore_cleanup_errors = False
210 finally:
211 umount(ignore_errors=ignore_cleanup_errors)
Stephen Warrend46df832016-01-22 12:30:13 -0700212 finally:
Tom Rini76b09e02025-02-12 16:24:00 -0600213 stop_ums(ignore_errors=ignore_cleanup_errors)
Stephen Warrend46df832016-01-22 12:30:13 -0700214
215 ignore_cleanup_errors = True
216 try:
217 start_ums()
218 try:
219 mount()
Simon Glassddba5202025-02-09 09:07:14 -0700220 ubman.log.action('Reading test file back via UMS')
Simon Glassfb916372025-02-09 09:07:15 -0700221 read_back_hash = utils.md5sum_file(mounted_test_fn)
Stephen Warrend46df832016-01-22 12:30:13 -0700222 cmd = ('rm', '-f', mounted_test_fn)
Simon Glassfb916372025-02-09 09:07:15 -0700223 utils.run_and_log(ubman, cmd)
Stephen Warrend46df832016-01-22 12:30:13 -0700224 ignore_cleanup_errors = False
225 finally:
226 umount(ignore_errors=ignore_cleanup_errors)
227 finally:
228 stop_ums(ignore_errors=ignore_cleanup_errors)
Stephen Warrendf278bb2016-01-15 11:15:30 -0700229
Stephen Warrend46df832016-01-22 12:30:13 -0700230 written_hash = test_f.content_hash
231 assert(written_hash == read_back_hash)