xref: /aosp_15_r20/external/crosvm/e2e_tests/tests/scsi.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Integration test for scsi devices as virtio-scsi.
6 
7 use std::path::Path;
8 
9 use fixture::utils::prepare_disk_img;
10 use fixture::vm::Config;
11 use fixture::vm::TestVm;
12 
13 // Mount the scsi device, and then check if simple read, write, and sync operations work.
mount_scsi_devices(mut config: Config, count: usize) -> anyhow::Result<()>14 fn mount_scsi_devices(mut config: Config, count: usize) -> anyhow::Result<()> {
15     let disks = (0..count).map(|_| prepare_disk_img()).collect::<Vec<_>>();
16     for disk in &disks {
17         let scsi_disk = disk.path().to_str().unwrap();
18         println!("scsi-disk={scsi_disk}");
19         config = config.extra_args(vec!["--scsi-block".to_string(), scsi_disk.to_string()]);
20     }
21 
22     let mut vm = TestVm::new(config).unwrap();
23     for (i, disk) in disks.iter().enumerate() {
24         let dev = format!("/dev/sd{}", char::from(b'a' + i as u8));
25         let dest = Path::new("/mnt").join(disk.path().file_name().unwrap());
26         vm.exec_in_guest("mount -t tmpfs none /mnt")?;
27         vm.exec_in_guest(&format!("mkdir -p {}", dest.display()))?;
28         vm.exec_in_guest(&format!("mount -t ext4 {dev} {}", dest.display()))?;
29 
30         let output = dest.join("tmp");
31         vm.exec_in_guest(&format!("echo 42 > {}", output.display()))?;
32         vm.exec_in_guest(&format!("sync -d {}", output.display()))?;
33         assert_eq!(
34             vm.exec_in_guest(&format!("cat {}", output.display()))?
35                 .stdout
36                 .trim(),
37             "42"
38         );
39     }
40     Ok(())
41 }
42 
43 #[test]
test_scsi_mount()44 fn test_scsi_mount() {
45     let config = Config::new();
46     mount_scsi_devices(config, 1).unwrap();
47 }
48 
49 #[test]
test_scsi_mount_disable_sandbox()50 fn test_scsi_mount_disable_sandbox() {
51     let config = Config::new().disable_sandbox();
52     mount_scsi_devices(config, 1).unwrap();
53 }
54 
55 #[test]
test_scsi_mount_multi_devices()56 fn test_scsi_mount_multi_devices() {
57     let config = Config::new();
58     mount_scsi_devices(config, 3).unwrap();
59 }
60 
61 #[test]
test_scsi_mount_multi_devices_disable_sandbox()62 fn test_scsi_mount_multi_devices_disable_sandbox() {
63     let config = Config::new().disable_sandbox();
64     mount_scsi_devices(config, 3).unwrap();
65 }
66 
67 // This test is for commands in controlq.
68 // First check if the resetting behavior is supported by `sg_opcodes` commands, and then issue the
69 // `sg_reset` command.
reset_scsi(config: Config) -> anyhow::Result<()>70 fn reset_scsi(config: Config) -> anyhow::Result<()> {
71     let disk = prepare_disk_img();
72     let scsi_disk = disk.path().to_str().unwrap();
73     let config = config.extra_args(vec!["--scsi-block".to_string(), scsi_disk.to_string()]);
74     println!("scsi-disk={scsi_disk}");
75 
76     let mut vm = TestVm::new(config).unwrap();
77     let cmd = vm.exec_in_guest("sg_opcodes --tmf /dev/sda")?;
78     let stdout = cmd.stdout.trim();
79     assert!(stdout.contains("Logical unit reset"));
80     assert!(stdout.contains("Target reset"));
81 
82     assert!(vm.exec_in_guest("sg_reset -d /dev/sda").is_ok());
83     Ok(())
84 }
85 
86 #[test]
test_scsi_reset()87 fn test_scsi_reset() {
88     let config = Config::new();
89     reset_scsi(config).unwrap();
90 }
91 
92 #[test]
test_scsi_reset_disable_sandbox()93 fn test_scsi_reset_disable_sandbox() {
94     let config = Config::new().disable_sandbox();
95     reset_scsi(config).unwrap();
96 }
97 
write_same_scsi(config: Config) -> anyhow::Result<()>98 fn write_same_scsi(config: Config) -> anyhow::Result<()> {
99     let disk = prepare_disk_img();
100     let scsi_disk = disk.path().to_str().unwrap();
101     let config = config.extra_args(vec!["--scsi-block".to_string(), scsi_disk.to_string()]);
102     println!("scsi-disk={scsi_disk}");
103 
104     let mut vm = TestVm::new(config)?;
105     assert!(vm
106         .exec_in_guest("sg_write_same --16 --lba=0 --num=1 --unmap /dev/sda")
107         .is_ok());
108     assert!(vm
109         .exec_in_guest("sg_write_same --16 --lba=0 --num=1 /dev/sda")
110         .is_ok());
111     Ok(())
112 }
113 
114 #[test]
test_scsi_write_same()115 fn test_scsi_write_same() {
116     let config = Config::new();
117     write_same_scsi(config).unwrap();
118 }
119 
120 #[test]
test_scsi_write_same_disable_sandbox()121 fn test_scsi_write_same_disable_sandbox() {
122     let config = Config::new().disable_sandbox();
123     write_same_scsi(config).unwrap();
124 }
125 
unmap_scsi(config: Config) -> anyhow::Result<()>126 fn unmap_scsi(config: Config) -> anyhow::Result<()> {
127     let disk = prepare_disk_img();
128     let scsi_disk = disk.path().to_str().unwrap();
129     let config = config.extra_args(vec!["--scsi-block".to_string(), scsi_disk.to_string()]);
130     println!("scsi-disk={scsi_disk}");
131 
132     let mut vm = TestVm::new(config)?;
133     assert!(vm
134         .exec_in_guest("sg_unmap --lba=0 --num=1 -f /dev/sda")
135         .is_ok());
136     Ok(())
137 }
138 
139 #[test]
test_scsi_unmap()140 fn test_scsi_unmap() {
141     let config = Config::new();
142     unmap_scsi(config).unwrap();
143 }
144 
145 #[test]
test_scsi_unmap_disable_sandbox()146 fn test_scsi_unmap_disable_sandbox() {
147     let config = Config::new().disable_sandbox();
148     unmap_scsi(config).unwrap();
149 }
150