1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker #![deny(missing_docs)]
6*bb4ee6a4SAndroid Build Coastguard Worker //! A SCSI controller has SCSI target(s), a SCSI target has logical unit(s).
7*bb4ee6a4SAndroid Build Coastguard Worker //! crosvm currently supports only one logical unit in a target (LUN0), therefore a SCSI target is
8*bb4ee6a4SAndroid Build Coastguard Worker //! tied to a logical unit and a disk image belongs to a logical unit in crosvm.
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::RefCell;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeSet;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::rc::Rc;
17*bb4ee6a4SAndroid Build Coastguard Worker
18*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
23*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::EventAsync;
24*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::Executor;
25*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::ExecutorKind;
26*bb4ee6a4SAndroid Build Coastguard Worker use disk::AsyncDisk;
27*bb4ee6a4SAndroid Build Coastguard Worker use disk::DiskFile;
28*bb4ee6a4SAndroid Build Coastguard Worker use futures::pin_mut;
29*bb4ee6a4SAndroid Build Coastguard Worker use futures::stream::FuturesUnordered;
30*bb4ee6a4SAndroid Build Coastguard Worker use futures::FutureExt;
31*bb4ee6a4SAndroid Build Coastguard Worker use futures::StreamExt;
32*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
33*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
34*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_config;
35*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_ctrl_an_resp;
36*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_ctrl_tmf_req;
37*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_ctrl_tmf_resp;
38*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_event;
39*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_CDB_DEFAULT_SIZE;
40*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
41*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_S_BAD_TARGET;
42*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_S_FUNCTION_REJECTED;
43*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
44*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_S_INCORRECT_LUN;
45*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_S_OK;
46*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_T_AN_QUERY;
47*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_T_AN_SUBSCRIBE;
48*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_T_TMF;
49*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET;
50*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET;
51*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
52*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
53*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
54*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
55*bb4ee6a4SAndroid Build Coastguard Worker
56*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::async_utils;
57*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::block::sys::get_seg_max;
58*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::copy_config;
59*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::scsi::commands::Command;
60*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::scsi::constants::CHECK_CONDITION;
61*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::scsi::constants::GOOD;
62*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::scsi::constants::ILLEGAL_REQUEST;
63*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::scsi::constants::MEDIUM_ERROR;
64*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::DescriptorChain;
65*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::DeviceType as VirtioDeviceType;
66*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Interrupt;
67*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Queue;
68*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Reader;
69*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::VirtioDevice;
70*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Writer;
71*bb4ee6a4SAndroid Build Coastguard Worker
72*bb4ee6a4SAndroid Build Coastguard Worker // The following values reflects the virtio v1.2 spec:
73*bb4ee6a4SAndroid Build Coastguard Worker // <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-3470004>
74*bb4ee6a4SAndroid Build Coastguard Worker
75*bb4ee6a4SAndroid Build Coastguard Worker // Should have one controlq, one eventq, and at least one request queue.
76*bb4ee6a4SAndroid Build Coastguard Worker const MIN_NUM_QUEUES: usize = 3;
77*bb4ee6a4SAndroid Build Coastguard Worker // The number of queues exposed by the device.
78*bb4ee6a4SAndroid Build Coastguard Worker // First crosvm pass this value through `VirtioDevice::read_config`, and then the driver determines
79*bb4ee6a4SAndroid Build Coastguard Worker // the number of queues which does not exceed the passed value. The determined value eventually
80*bb4ee6a4SAndroid Build Coastguard Worker // shows as the length of `queues` in `VirtioDevice::activate`.
81*bb4ee6a4SAndroid Build Coastguard Worker const MAX_NUM_QUEUES: usize = 16;
82*bb4ee6a4SAndroid Build Coastguard Worker // Max channel should be 0.
83*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_MAX_CHANNEL: u16 = 0;
84*bb4ee6a4SAndroid Build Coastguard Worker // Max target should be less than or equal to 255.
85*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_MAX_TARGET: u16 = 255;
86*bb4ee6a4SAndroid Build Coastguard Worker // Max lun should be less than or equal to 16383
87*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_MAX_LUN: u32 = 16383;
88*bb4ee6a4SAndroid Build Coastguard Worker
89*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_QUEUE_SIZE: u16 = 1024;
90*bb4ee6a4SAndroid Build Coastguard Worker
91*bb4ee6a4SAndroid Build Coastguard Worker // The maximum number of linked commands.
92*bb4ee6a4SAndroid Build Coastguard Worker const MAX_CMD_PER_LUN: u32 = 1024;
93*bb4ee6a4SAndroid Build Coastguard Worker // We do not set a limit on the transfer size.
94*bb4ee6a4SAndroid Build Coastguard Worker const MAX_SECTORS: u32 = u32::MAX;
95*bb4ee6a4SAndroid Build Coastguard Worker
96*bb4ee6a4SAndroid Build Coastguard Worker // The length of sense data in fixed format. Details are in SPC-3 t10 revision 23:
97*bb4ee6a4SAndroid Build Coastguard Worker // <https://www.t10.org/cgi-bin/ac.pl?t=f&f=spc3r23.pdf>
98*bb4ee6a4SAndroid Build Coastguard Worker const FIXED_FORMAT_SENSE_SIZE: u32 = 18;
99*bb4ee6a4SAndroid Build Coastguard Worker
100*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C, packed)]
101*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, FromZeroes, FromBytes, AsBytes)]
102*bb4ee6a4SAndroid Build Coastguard Worker struct VirtioScsiCmdReqHeader {
103*bb4ee6a4SAndroid Build Coastguard Worker lun: [u8; 8usize],
104*bb4ee6a4SAndroid Build Coastguard Worker tag: u64,
105*bb4ee6a4SAndroid Build Coastguard Worker task_attr: u8,
106*bb4ee6a4SAndroid Build Coastguard Worker prio: u8,
107*bb4ee6a4SAndroid Build Coastguard Worker crn: u8,
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker
110*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C, packed)]
111*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Default, Copy, Clone, FromZeroes, FromBytes, AsBytes)]
112*bb4ee6a4SAndroid Build Coastguard Worker struct VirtioScsiCmdRespHeader {
113*bb4ee6a4SAndroid Build Coastguard Worker sense_len: u32,
114*bb4ee6a4SAndroid Build Coastguard Worker resid: u32,
115*bb4ee6a4SAndroid Build Coastguard Worker status_qualifier: u16,
116*bb4ee6a4SAndroid Build Coastguard Worker status: u8,
117*bb4ee6a4SAndroid Build Coastguard Worker response: u8,
118*bb4ee6a4SAndroid Build Coastguard Worker }
119*bb4ee6a4SAndroid Build Coastguard Worker
120*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioScsiCmdRespHeader {
ok() -> Self121*bb4ee6a4SAndroid Build Coastguard Worker fn ok() -> Self {
122*bb4ee6a4SAndroid Build Coastguard Worker VirtioScsiCmdRespHeader {
123*bb4ee6a4SAndroid Build Coastguard Worker sense_len: 0,
124*bb4ee6a4SAndroid Build Coastguard Worker resid: 0,
125*bb4ee6a4SAndroid Build Coastguard Worker status_qualifier: 0,
126*bb4ee6a4SAndroid Build Coastguard Worker status: GOOD,
127*bb4ee6a4SAndroid Build Coastguard Worker response: VIRTIO_SCSI_S_OK as u8,
128*bb4ee6a4SAndroid Build Coastguard Worker }
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker }
131*bb4ee6a4SAndroid Build Coastguard Worker
132*bb4ee6a4SAndroid Build Coastguard Worker /// Errors that happen while handling scsi commands.
133*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
134*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
135*bb4ee6a4SAndroid Build Coastguard Worker pub enum ExecuteError {
136*bb4ee6a4SAndroid Build Coastguard Worker #[error("invalid cdb field")]
137*bb4ee6a4SAndroid Build Coastguard Worker InvalidField,
138*bb4ee6a4SAndroid Build Coastguard Worker #[error("invalid parameter length")]
139*bb4ee6a4SAndroid Build Coastguard Worker InvalidParamLen,
140*bb4ee6a4SAndroid Build Coastguard Worker #[error("{length} bytes from sector {sector} exceeds end of this device {max_lba}")]
141*bb4ee6a4SAndroid Build Coastguard Worker LbaOutOfRange {
142*bb4ee6a4SAndroid Build Coastguard Worker length: usize,
143*bb4ee6a4SAndroid Build Coastguard Worker sector: u64,
144*bb4ee6a4SAndroid Build Coastguard Worker max_lba: u64,
145*bb4ee6a4SAndroid Build Coastguard Worker },
146*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to read message: {0}")]
147*bb4ee6a4SAndroid Build Coastguard Worker Read(io::Error),
148*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to read command from cdb")]
149*bb4ee6a4SAndroid Build Coastguard Worker ReadCommand,
150*bb4ee6a4SAndroid Build Coastguard Worker #[error("io error {resid} bytes remained to be read: {desc_error}")]
151*bb4ee6a4SAndroid Build Coastguard Worker ReadIo {
152*bb4ee6a4SAndroid Build Coastguard Worker resid: usize,
153*bb4ee6a4SAndroid Build Coastguard Worker desc_error: disk::Error,
154*bb4ee6a4SAndroid Build Coastguard Worker },
155*bb4ee6a4SAndroid Build Coastguard Worker #[error("writing to a read only device")]
156*bb4ee6a4SAndroid Build Coastguard Worker ReadOnly,
157*bb4ee6a4SAndroid Build Coastguard Worker #[error("saving parameters not supported")]
158*bb4ee6a4SAndroid Build Coastguard Worker SavingParamNotSupported,
159*bb4ee6a4SAndroid Build Coastguard Worker #[error("synchronization error")]
160*bb4ee6a4SAndroid Build Coastguard Worker SynchronizationError,
161*bb4ee6a4SAndroid Build Coastguard Worker #[error("unsupported scsi command: {0}")]
162*bb4ee6a4SAndroid Build Coastguard Worker Unsupported(u8),
163*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to write message: {0}")]
164*bb4ee6a4SAndroid Build Coastguard Worker Write(io::Error),
165*bb4ee6a4SAndroid Build Coastguard Worker #[error("io error {resid} bytes remained to be written: {desc_error}")]
166*bb4ee6a4SAndroid Build Coastguard Worker WriteIo {
167*bb4ee6a4SAndroid Build Coastguard Worker resid: usize,
168*bb4ee6a4SAndroid Build Coastguard Worker desc_error: disk::Error,
169*bb4ee6a4SAndroid Build Coastguard Worker },
170*bb4ee6a4SAndroid Build Coastguard Worker }
171*bb4ee6a4SAndroid Build Coastguard Worker
172*bb4ee6a4SAndroid Build Coastguard Worker impl ExecuteError {
173*bb4ee6a4SAndroid Build Coastguard Worker // converts ExecuteError to (VirtioScsiCmdReqHeader, Sense)
as_resp(&self) -> (VirtioScsiCmdRespHeader, Sense)174*bb4ee6a4SAndroid Build Coastguard Worker fn as_resp(&self) -> (VirtioScsiCmdRespHeader, Sense) {
175*bb4ee6a4SAndroid Build Coastguard Worker let resp = VirtioScsiCmdRespHeader::ok();
176*bb4ee6a4SAndroid Build Coastguard Worker // The asc and ascq assignments are taken from the t10 SPC spec.
177*bb4ee6a4SAndroid Build Coastguard Worker // cf) Table 28 of <https://www.t10.org/cgi-bin/ac.pl?t=f&f=spc3r23.pdf>
178*bb4ee6a4SAndroid Build Coastguard Worker let sense = match self {
179*bb4ee6a4SAndroid Build Coastguard Worker Self::Read(_) | Self::ReadCommand => {
180*bb4ee6a4SAndroid Build Coastguard Worker // UNRECOVERED READ ERROR
181*bb4ee6a4SAndroid Build Coastguard Worker Sense {
182*bb4ee6a4SAndroid Build Coastguard Worker key: MEDIUM_ERROR,
183*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x11,
184*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker }
187*bb4ee6a4SAndroid Build Coastguard Worker Self::Write(_) => {
188*bb4ee6a4SAndroid Build Coastguard Worker // WRITE ERROR
189*bb4ee6a4SAndroid Build Coastguard Worker Sense {
190*bb4ee6a4SAndroid Build Coastguard Worker key: MEDIUM_ERROR,
191*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x0c,
192*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
193*bb4ee6a4SAndroid Build Coastguard Worker }
194*bb4ee6a4SAndroid Build Coastguard Worker }
195*bb4ee6a4SAndroid Build Coastguard Worker Self::InvalidField => {
196*bb4ee6a4SAndroid Build Coastguard Worker // INVALID FIELD IN CDB
197*bb4ee6a4SAndroid Build Coastguard Worker Sense {
198*bb4ee6a4SAndroid Build Coastguard Worker key: ILLEGAL_REQUEST,
199*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x24,
200*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
201*bb4ee6a4SAndroid Build Coastguard Worker }
202*bb4ee6a4SAndroid Build Coastguard Worker }
203*bb4ee6a4SAndroid Build Coastguard Worker Self::InvalidParamLen => {
204*bb4ee6a4SAndroid Build Coastguard Worker // INVALID PARAMETER LENGTH
205*bb4ee6a4SAndroid Build Coastguard Worker Sense {
206*bb4ee6a4SAndroid Build Coastguard Worker key: ILLEGAL_REQUEST,
207*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x1a,
208*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
209*bb4ee6a4SAndroid Build Coastguard Worker }
210*bb4ee6a4SAndroid Build Coastguard Worker }
211*bb4ee6a4SAndroid Build Coastguard Worker Self::Unsupported(_) => {
212*bb4ee6a4SAndroid Build Coastguard Worker // INVALID COMMAND OPERATION CODE
213*bb4ee6a4SAndroid Build Coastguard Worker Sense {
214*bb4ee6a4SAndroid Build Coastguard Worker key: ILLEGAL_REQUEST,
215*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x20,
216*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker }
219*bb4ee6a4SAndroid Build Coastguard Worker Self::ReadOnly | Self::LbaOutOfRange { .. } => {
220*bb4ee6a4SAndroid Build Coastguard Worker // LOGICAL BLOCK ADDRESS OUT OF RANGE
221*bb4ee6a4SAndroid Build Coastguard Worker Sense {
222*bb4ee6a4SAndroid Build Coastguard Worker key: ILLEGAL_REQUEST,
223*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x21,
224*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
225*bb4ee6a4SAndroid Build Coastguard Worker }
226*bb4ee6a4SAndroid Build Coastguard Worker }
227*bb4ee6a4SAndroid Build Coastguard Worker Self::SavingParamNotSupported => Sense {
228*bb4ee6a4SAndroid Build Coastguard Worker // SAVING PARAMETERS NOT SUPPORTED
229*bb4ee6a4SAndroid Build Coastguard Worker key: ILLEGAL_REQUEST,
230*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x39,
231*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
232*bb4ee6a4SAndroid Build Coastguard Worker },
233*bb4ee6a4SAndroid Build Coastguard Worker Self::SynchronizationError => Sense {
234*bb4ee6a4SAndroid Build Coastguard Worker // SYNCHRONIZATION ERROR
235*bb4ee6a4SAndroid Build Coastguard Worker key: MEDIUM_ERROR,
236*bb4ee6a4SAndroid Build Coastguard Worker asc: 0x16,
237*bb4ee6a4SAndroid Build Coastguard Worker ascq: 0x00,
238*bb4ee6a4SAndroid Build Coastguard Worker },
239*bb4ee6a4SAndroid Build Coastguard Worker // Ignore these errors.
240*bb4ee6a4SAndroid Build Coastguard Worker Self::ReadIo { resid, desc_error } | Self::WriteIo { resid, desc_error } => {
241*bb4ee6a4SAndroid Build Coastguard Worker warn!("error while performing I/O {}", desc_error);
242*bb4ee6a4SAndroid Build Coastguard Worker let hdr = VirtioScsiCmdRespHeader {
243*bb4ee6a4SAndroid Build Coastguard Worker resid: (*resid).try_into().unwrap_or(u32::MAX).to_be(),
244*bb4ee6a4SAndroid Build Coastguard Worker ..resp
245*bb4ee6a4SAndroid Build Coastguard Worker };
246*bb4ee6a4SAndroid Build Coastguard Worker return (hdr, Sense::default());
247*bb4ee6a4SAndroid Build Coastguard Worker }
248*bb4ee6a4SAndroid Build Coastguard Worker };
249*bb4ee6a4SAndroid Build Coastguard Worker (
250*bb4ee6a4SAndroid Build Coastguard Worker VirtioScsiCmdRespHeader {
251*bb4ee6a4SAndroid Build Coastguard Worker sense_len: FIXED_FORMAT_SENSE_SIZE,
252*bb4ee6a4SAndroid Build Coastguard Worker status: CHECK_CONDITION,
253*bb4ee6a4SAndroid Build Coastguard Worker ..resp
254*bb4ee6a4SAndroid Build Coastguard Worker },
255*bb4ee6a4SAndroid Build Coastguard Worker sense,
256*bb4ee6a4SAndroid Build Coastguard Worker )
257*bb4ee6a4SAndroid Build Coastguard Worker }
258*bb4ee6a4SAndroid Build Coastguard Worker }
259*bb4ee6a4SAndroid Build Coastguard Worker
260*bb4ee6a4SAndroid Build Coastguard Worker /// Sense code representation
261*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
262*bb4ee6a4SAndroid Build Coastguard Worker pub struct Sense {
263*bb4ee6a4SAndroid Build Coastguard Worker /// Provides generic information describing an error or exception condition.
264*bb4ee6a4SAndroid Build Coastguard Worker pub key: u8,
265*bb4ee6a4SAndroid Build Coastguard Worker /// Additional Sense Code.
266*bb4ee6a4SAndroid Build Coastguard Worker /// Indicates further information related to the error or exception reported in the key field.
267*bb4ee6a4SAndroid Build Coastguard Worker pub asc: u8,
268*bb4ee6a4SAndroid Build Coastguard Worker /// Additional Sense Code Qualifier.
269*bb4ee6a4SAndroid Build Coastguard Worker /// Indicates further detailed information related to the additional sense code.
270*bb4ee6a4SAndroid Build Coastguard Worker pub ascq: u8,
271*bb4ee6a4SAndroid Build Coastguard Worker }
272*bb4ee6a4SAndroid Build Coastguard Worker
273*bb4ee6a4SAndroid Build Coastguard Worker impl Sense {
write_to(&self, writer: &mut Writer, sense_size: u32) -> Result<(), ExecuteError>274*bb4ee6a4SAndroid Build Coastguard Worker fn write_to(&self, writer: &mut Writer, sense_size: u32) -> Result<(), ExecuteError> {
275*bb4ee6a4SAndroid Build Coastguard Worker let mut sense_data = [0u8; FIXED_FORMAT_SENSE_SIZE as usize];
276*bb4ee6a4SAndroid Build Coastguard Worker // Fixed format sense data has response code:
277*bb4ee6a4SAndroid Build Coastguard Worker // 1) 0x70 for current errors
278*bb4ee6a4SAndroid Build Coastguard Worker // 2) 0x71 for deferred errors
279*bb4ee6a4SAndroid Build Coastguard Worker sense_data[0] = 0x70;
280*bb4ee6a4SAndroid Build Coastguard Worker // sense_data[1]: Obsolete
281*bb4ee6a4SAndroid Build Coastguard Worker // Sense key
282*bb4ee6a4SAndroid Build Coastguard Worker sense_data[2] = self.key;
283*bb4ee6a4SAndroid Build Coastguard Worker // sense_data[3..7]: Information field, which we do not support.
284*bb4ee6a4SAndroid Build Coastguard Worker // Additional length. The data is 18 bytes, and this byte is 8th.
285*bb4ee6a4SAndroid Build Coastguard Worker sense_data[7] = 10;
286*bb4ee6a4SAndroid Build Coastguard Worker // sense_data[8..12]: Command specific information, which we do not support.
287*bb4ee6a4SAndroid Build Coastguard Worker // Additional sense code
288*bb4ee6a4SAndroid Build Coastguard Worker sense_data[12] = self.asc;
289*bb4ee6a4SAndroid Build Coastguard Worker // Additional sense code qualifier
290*bb4ee6a4SAndroid Build Coastguard Worker sense_data[13] = self.ascq;
291*bb4ee6a4SAndroid Build Coastguard Worker // sense_data[14]: Field replaceable unit code, which we do not support.
292*bb4ee6a4SAndroid Build Coastguard Worker // sense_data[15..18]: Field replaceable unit code, which we do not support.
293*bb4ee6a4SAndroid Build Coastguard Worker writer.write_all(&sense_data).map_err(ExecuteError::Write)?;
294*bb4ee6a4SAndroid Build Coastguard Worker writer.consume_bytes(sense_size as usize - sense_data.len());
295*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker }
298*bb4ee6a4SAndroid Build Coastguard Worker
299*bb4ee6a4SAndroid Build Coastguard Worker /// Describes each SCSI logical unit.
300*bb4ee6a4SAndroid Build Coastguard Worker struct LogicalUnit {
301*bb4ee6a4SAndroid Build Coastguard Worker /// The maximum logical block address of the target device.
302*bb4ee6a4SAndroid Build Coastguard Worker max_lba: u64,
303*bb4ee6a4SAndroid Build Coastguard Worker /// Block size of the target device.
304*bb4ee6a4SAndroid Build Coastguard Worker block_size: u32,
305*bb4ee6a4SAndroid Build Coastguard Worker read_only: bool,
306*bb4ee6a4SAndroid Build Coastguard Worker // Represents the image on disk.
307*bb4ee6a4SAndroid Build Coastguard Worker disk_image: Box<dyn DiskFile>,
308*bb4ee6a4SAndroid Build Coastguard Worker }
309*bb4ee6a4SAndroid Build Coastguard Worker
310*bb4ee6a4SAndroid Build Coastguard Worker impl LogicalUnit {
make_async(self, ex: &Executor) -> anyhow::Result<AsyncLogicalUnit>311*bb4ee6a4SAndroid Build Coastguard Worker fn make_async(self, ex: &Executor) -> anyhow::Result<AsyncLogicalUnit> {
312*bb4ee6a4SAndroid Build Coastguard Worker let disk_image = self
313*bb4ee6a4SAndroid Build Coastguard Worker .disk_image
314*bb4ee6a4SAndroid Build Coastguard Worker .to_async_disk(ex)
315*bb4ee6a4SAndroid Build Coastguard Worker .context("Failed to create async disk")?;
316*bb4ee6a4SAndroid Build Coastguard Worker Ok(AsyncLogicalUnit {
317*bb4ee6a4SAndroid Build Coastguard Worker max_lba: self.max_lba,
318*bb4ee6a4SAndroid Build Coastguard Worker block_size: self.block_size,
319*bb4ee6a4SAndroid Build Coastguard Worker read_only: self.read_only,
320*bb4ee6a4SAndroid Build Coastguard Worker disk_image,
321*bb4ee6a4SAndroid Build Coastguard Worker })
322*bb4ee6a4SAndroid Build Coastguard Worker }
323*bb4ee6a4SAndroid Build Coastguard Worker }
324*bb4ee6a4SAndroid Build Coastguard Worker
325*bb4ee6a4SAndroid Build Coastguard Worker /// A logical unit with an AsyncDisk as the disk.
326*bb4ee6a4SAndroid Build Coastguard Worker pub struct AsyncLogicalUnit {
327*bb4ee6a4SAndroid Build Coastguard Worker pub max_lba: u64,
328*bb4ee6a4SAndroid Build Coastguard Worker pub block_size: u32,
329*bb4ee6a4SAndroid Build Coastguard Worker pub read_only: bool,
330*bb4ee6a4SAndroid Build Coastguard Worker // Represents the async image on disk.
331*bb4ee6a4SAndroid Build Coastguard Worker pub disk_image: Box<dyn AsyncDisk>,
332*bb4ee6a4SAndroid Build Coastguard Worker }
333*bb4ee6a4SAndroid Build Coastguard Worker
334*bb4ee6a4SAndroid Build Coastguard Worker type TargetId = u8;
335*bb4ee6a4SAndroid Build Coastguard Worker struct Targets(BTreeMap<TargetId, LogicalUnit>);
336*bb4ee6a4SAndroid Build Coastguard Worker
337*bb4ee6a4SAndroid Build Coastguard Worker impl Targets {
try_clone(&self) -> io::Result<Self>338*bb4ee6a4SAndroid Build Coastguard Worker fn try_clone(&self) -> io::Result<Self> {
339*bb4ee6a4SAndroid Build Coastguard Worker let logical_units = self
340*bb4ee6a4SAndroid Build Coastguard Worker .0
341*bb4ee6a4SAndroid Build Coastguard Worker .iter()
342*bb4ee6a4SAndroid Build Coastguard Worker .map(|(id, logical_unit)| {
343*bb4ee6a4SAndroid Build Coastguard Worker let disk_image = logical_unit.disk_image.try_clone()?;
344*bb4ee6a4SAndroid Build Coastguard Worker Ok((
345*bb4ee6a4SAndroid Build Coastguard Worker *id,
346*bb4ee6a4SAndroid Build Coastguard Worker LogicalUnit {
347*bb4ee6a4SAndroid Build Coastguard Worker disk_image,
348*bb4ee6a4SAndroid Build Coastguard Worker max_lba: logical_unit.max_lba,
349*bb4ee6a4SAndroid Build Coastguard Worker block_size: logical_unit.block_size,
350*bb4ee6a4SAndroid Build Coastguard Worker read_only: logical_unit.read_only,
351*bb4ee6a4SAndroid Build Coastguard Worker },
352*bb4ee6a4SAndroid Build Coastguard Worker ))
353*bb4ee6a4SAndroid Build Coastguard Worker })
354*bb4ee6a4SAndroid Build Coastguard Worker .collect::<io::Result<_>>()?;
355*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self(logical_units))
356*bb4ee6a4SAndroid Build Coastguard Worker }
357*bb4ee6a4SAndroid Build Coastguard Worker
target_ids(&self) -> BTreeSet<TargetId>358*bb4ee6a4SAndroid Build Coastguard Worker fn target_ids(&self) -> BTreeSet<TargetId> {
359*bb4ee6a4SAndroid Build Coastguard Worker self.0.keys().cloned().collect()
360*bb4ee6a4SAndroid Build Coastguard Worker }
361*bb4ee6a4SAndroid Build Coastguard Worker }
362*bb4ee6a4SAndroid Build Coastguard Worker
363*bb4ee6a4SAndroid Build Coastguard Worker /// Configuration of each SCSI device.
364*bb4ee6a4SAndroid Build Coastguard Worker pub struct DiskConfig {
365*bb4ee6a4SAndroid Build Coastguard Worker /// The disk file of the device.
366*bb4ee6a4SAndroid Build Coastguard Worker pub file: Box<dyn DiskFile>,
367*bb4ee6a4SAndroid Build Coastguard Worker /// The block size of the SCSI disk.
368*bb4ee6a4SAndroid Build Coastguard Worker pub block_size: u32,
369*bb4ee6a4SAndroid Build Coastguard Worker /// Indicates whether the SCSI disk is read only.
370*bb4ee6a4SAndroid Build Coastguard Worker pub read_only: bool,
371*bb4ee6a4SAndroid Build Coastguard Worker }
372*bb4ee6a4SAndroid Build Coastguard Worker
373*bb4ee6a4SAndroid Build Coastguard Worker /// Vitio device for exposing SCSI command operations on a host file.
374*bb4ee6a4SAndroid Build Coastguard Worker pub struct Controller {
375*bb4ee6a4SAndroid Build Coastguard Worker // Bitmap of virtio-scsi feature bits.
376*bb4ee6a4SAndroid Build Coastguard Worker avail_features: u64,
377*bb4ee6a4SAndroid Build Coastguard Worker // Sizes for the virtqueue.
378*bb4ee6a4SAndroid Build Coastguard Worker queue_sizes: Vec<u16>,
379*bb4ee6a4SAndroid Build Coastguard Worker // The maximum number of segments that can be in a command.
380*bb4ee6a4SAndroid Build Coastguard Worker seg_max: u32,
381*bb4ee6a4SAndroid Build Coastguard Worker // The size of the sense data.
382*bb4ee6a4SAndroid Build Coastguard Worker sense_size: u32,
383*bb4ee6a4SAndroid Build Coastguard Worker // The byte size of the CDB that the driver will write.
384*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: u32,
385*bb4ee6a4SAndroid Build Coastguard Worker executor_kind: ExecutorKind,
386*bb4ee6a4SAndroid Build Coastguard Worker worker_threads: Vec<WorkerThread<()>>,
387*bb4ee6a4SAndroid Build Coastguard Worker // Stores target devices by its target id. Currently we only support bus id 0.
388*bb4ee6a4SAndroid Build Coastguard Worker targets: Option<Targets>,
389*bb4ee6a4SAndroid Build Coastguard Worker // Whether the devices handles requests in multiple request queues.
390*bb4ee6a4SAndroid Build Coastguard Worker // If true, each virtqueue will be handled in a separate worker thread.
391*bb4ee6a4SAndroid Build Coastguard Worker multi_queue: bool,
392*bb4ee6a4SAndroid Build Coastguard Worker }
393*bb4ee6a4SAndroid Build Coastguard Worker
394*bb4ee6a4SAndroid Build Coastguard Worker impl Controller {
395*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a virtio-scsi device.
new(base_features: u64, disks: Vec<DiskConfig>) -> anyhow::Result<Self>396*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(base_features: u64, disks: Vec<DiskConfig>) -> anyhow::Result<Self> {
397*bb4ee6a4SAndroid Build Coastguard Worker let multi_queue = disks.iter().all(|disk| disk.file.try_clone().is_ok());
398*bb4ee6a4SAndroid Build Coastguard Worker let num_queues = if multi_queue {
399*bb4ee6a4SAndroid Build Coastguard Worker MAX_NUM_QUEUES
400*bb4ee6a4SAndroid Build Coastguard Worker } else {
401*bb4ee6a4SAndroid Build Coastguard Worker MIN_NUM_QUEUES
402*bb4ee6a4SAndroid Build Coastguard Worker };
403*bb4ee6a4SAndroid Build Coastguard Worker let logical_units = disks
404*bb4ee6a4SAndroid Build Coastguard Worker .into_iter()
405*bb4ee6a4SAndroid Build Coastguard Worker .enumerate()
406*bb4ee6a4SAndroid Build Coastguard Worker .map(|(i, disk)| {
407*bb4ee6a4SAndroid Build Coastguard Worker let max_lba = disk
408*bb4ee6a4SAndroid Build Coastguard Worker .file
409*bb4ee6a4SAndroid Build Coastguard Worker .get_len()
410*bb4ee6a4SAndroid Build Coastguard Worker .context("Failed to get the length of the disk image")?
411*bb4ee6a4SAndroid Build Coastguard Worker / disk.block_size as u64;
412*bb4ee6a4SAndroid Build Coastguard Worker let target = LogicalUnit {
413*bb4ee6a4SAndroid Build Coastguard Worker max_lba,
414*bb4ee6a4SAndroid Build Coastguard Worker block_size: disk.block_size,
415*bb4ee6a4SAndroid Build Coastguard Worker read_only: disk.read_only,
416*bb4ee6a4SAndroid Build Coastguard Worker disk_image: disk.file,
417*bb4ee6a4SAndroid Build Coastguard Worker };
418*bb4ee6a4SAndroid Build Coastguard Worker Ok((i as TargetId, target))
419*bb4ee6a4SAndroid Build Coastguard Worker })
420*bb4ee6a4SAndroid Build Coastguard Worker .collect::<anyhow::Result<_>>()?;
421*bb4ee6a4SAndroid Build Coastguard Worker // b/300560198: Support feature bits in virtio-scsi.
422*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self {
423*bb4ee6a4SAndroid Build Coastguard Worker avail_features: base_features,
424*bb4ee6a4SAndroid Build Coastguard Worker queue_sizes: vec![DEFAULT_QUEUE_SIZE; num_queues],
425*bb4ee6a4SAndroid Build Coastguard Worker seg_max: get_seg_max(DEFAULT_QUEUE_SIZE),
426*bb4ee6a4SAndroid Build Coastguard Worker sense_size: VIRTIO_SCSI_SENSE_DEFAULT_SIZE,
427*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: VIRTIO_SCSI_CDB_DEFAULT_SIZE,
428*bb4ee6a4SAndroid Build Coastguard Worker executor_kind: ExecutorKind::default(),
429*bb4ee6a4SAndroid Build Coastguard Worker worker_threads: vec![],
430*bb4ee6a4SAndroid Build Coastguard Worker targets: Some(Targets(logical_units)),
431*bb4ee6a4SAndroid Build Coastguard Worker multi_queue,
432*bb4ee6a4SAndroid Build Coastguard Worker })
433*bb4ee6a4SAndroid Build Coastguard Worker }
434*bb4ee6a4SAndroid Build Coastguard Worker
build_config_space(&self) -> virtio_scsi_config435*bb4ee6a4SAndroid Build Coastguard Worker fn build_config_space(&self) -> virtio_scsi_config {
436*bb4ee6a4SAndroid Build Coastguard Worker virtio_scsi_config {
437*bb4ee6a4SAndroid Build Coastguard Worker // num_queues is the number of request queues only so we subtract 2 for the control
438*bb4ee6a4SAndroid Build Coastguard Worker // queue and the event queue.
439*bb4ee6a4SAndroid Build Coastguard Worker num_queues: self.queue_sizes.len() as u32 - 2,
440*bb4ee6a4SAndroid Build Coastguard Worker seg_max: self.seg_max,
441*bb4ee6a4SAndroid Build Coastguard Worker max_sectors: MAX_SECTORS,
442*bb4ee6a4SAndroid Build Coastguard Worker cmd_per_lun: MAX_CMD_PER_LUN,
443*bb4ee6a4SAndroid Build Coastguard Worker event_info_size: std::mem::size_of::<virtio_scsi_event>() as u32,
444*bb4ee6a4SAndroid Build Coastguard Worker sense_size: self.sense_size,
445*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: self.cdb_size,
446*bb4ee6a4SAndroid Build Coastguard Worker max_channel: DEFAULT_MAX_CHANNEL,
447*bb4ee6a4SAndroid Build Coastguard Worker max_target: DEFAULT_MAX_TARGET,
448*bb4ee6a4SAndroid Build Coastguard Worker max_lun: DEFAULT_MAX_LUN,
449*bb4ee6a4SAndroid Build Coastguard Worker }
450*bb4ee6a4SAndroid Build Coastguard Worker }
451*bb4ee6a4SAndroid Build Coastguard Worker
452*bb4ee6a4SAndroid Build Coastguard Worker // Executes a request in the controlq.
execute_control( reader: &mut Reader, writer: &mut Writer, target_ids: &BTreeSet<TargetId>, ) -> Result<(), ExecuteError>453*bb4ee6a4SAndroid Build Coastguard Worker fn execute_control(
454*bb4ee6a4SAndroid Build Coastguard Worker reader: &mut Reader,
455*bb4ee6a4SAndroid Build Coastguard Worker writer: &mut Writer,
456*bb4ee6a4SAndroid Build Coastguard Worker target_ids: &BTreeSet<TargetId>,
457*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(), ExecuteError> {
458*bb4ee6a4SAndroid Build Coastguard Worker let typ = reader.peek_obj::<u32>().map_err(ExecuteError::Read)?;
459*bb4ee6a4SAndroid Build Coastguard Worker match typ {
460*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_T_TMF => {
461*bb4ee6a4SAndroid Build Coastguard Worker let tmf = reader
462*bb4ee6a4SAndroid Build Coastguard Worker .read_obj::<virtio_scsi_ctrl_tmf_req>()
463*bb4ee6a4SAndroid Build Coastguard Worker .map_err(ExecuteError::Read)?;
464*bb4ee6a4SAndroid Build Coastguard Worker let resp = Self::execute_tmf(tmf, target_ids);
465*bb4ee6a4SAndroid Build Coastguard Worker writer.write_obj(resp).map_err(ExecuteError::Write)?;
466*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
467*bb4ee6a4SAndroid Build Coastguard Worker }
468*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_T_AN_QUERY | VIRTIO_SCSI_T_AN_SUBSCRIBE => {
469*bb4ee6a4SAndroid Build Coastguard Worker // We do not support any asynchronous notification queries hence `event_actual`
470*bb4ee6a4SAndroid Build Coastguard Worker // will be 0.
471*bb4ee6a4SAndroid Build Coastguard Worker let resp = virtio_scsi_ctrl_an_resp {
472*bb4ee6a4SAndroid Build Coastguard Worker event_actual: 0,
473*bb4ee6a4SAndroid Build Coastguard Worker response: VIRTIO_SCSI_S_OK as u8,
474*bb4ee6a4SAndroid Build Coastguard Worker };
475*bb4ee6a4SAndroid Build Coastguard Worker writer.write_obj(resp).map_err(ExecuteError::Write)?;
476*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
477*bb4ee6a4SAndroid Build Coastguard Worker }
478*bb4ee6a4SAndroid Build Coastguard Worker _ => {
479*bb4ee6a4SAndroid Build Coastguard Worker error!("invalid type of a control request: {typ}");
480*bb4ee6a4SAndroid Build Coastguard Worker Err(ExecuteError::InvalidField)
481*bb4ee6a4SAndroid Build Coastguard Worker }
482*bb4ee6a4SAndroid Build Coastguard Worker }
483*bb4ee6a4SAndroid Build Coastguard Worker }
484*bb4ee6a4SAndroid Build Coastguard Worker
485*bb4ee6a4SAndroid Build Coastguard Worker // Executes a TMF (task management function) request.
execute_tmf( tmf: virtio_scsi_ctrl_tmf_req, target_ids: &BTreeSet<TargetId>, ) -> virtio_scsi_ctrl_tmf_resp486*bb4ee6a4SAndroid Build Coastguard Worker fn execute_tmf(
487*bb4ee6a4SAndroid Build Coastguard Worker tmf: virtio_scsi_ctrl_tmf_req,
488*bb4ee6a4SAndroid Build Coastguard Worker target_ids: &BTreeSet<TargetId>,
489*bb4ee6a4SAndroid Build Coastguard Worker ) -> virtio_scsi_ctrl_tmf_resp {
490*bb4ee6a4SAndroid Build Coastguard Worker match tmf.subtype {
491*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET | VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET => {
492*bb4ee6a4SAndroid Build Coastguard Worker // We only have LUN0.
493*bb4ee6a4SAndroid Build Coastguard Worker let lun = tmf.lun;
494*bb4ee6a4SAndroid Build Coastguard Worker let target_id = lun[1];
495*bb4ee6a4SAndroid Build Coastguard Worker let response = if target_ids.contains(&target_id) {
496*bb4ee6a4SAndroid Build Coastguard Worker let is_lun0 = u16::from_be_bytes([lun[2], lun[3]]) & 0x3fff == 0;
497*bb4ee6a4SAndroid Build Coastguard Worker if is_lun0 {
498*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_S_FUNCTION_SUCCEEDED as u8
499*bb4ee6a4SAndroid Build Coastguard Worker } else {
500*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_S_INCORRECT_LUN as u8
501*bb4ee6a4SAndroid Build Coastguard Worker }
502*bb4ee6a4SAndroid Build Coastguard Worker } else {
503*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_S_BAD_TARGET as u8
504*bb4ee6a4SAndroid Build Coastguard Worker };
505*bb4ee6a4SAndroid Build Coastguard Worker virtio_scsi_ctrl_tmf_resp { response }
506*bb4ee6a4SAndroid Build Coastguard Worker }
507*bb4ee6a4SAndroid Build Coastguard Worker subtype => {
508*bb4ee6a4SAndroid Build Coastguard Worker error!("TMF request {subtype} is not supported");
509*bb4ee6a4SAndroid Build Coastguard Worker virtio_scsi_ctrl_tmf_resp {
510*bb4ee6a4SAndroid Build Coastguard Worker response: VIRTIO_SCSI_S_FUNCTION_REJECTED as u8,
511*bb4ee6a4SAndroid Build Coastguard Worker }
512*bb4ee6a4SAndroid Build Coastguard Worker }
513*bb4ee6a4SAndroid Build Coastguard Worker }
514*bb4ee6a4SAndroid Build Coastguard Worker }
515*bb4ee6a4SAndroid Build Coastguard Worker
execute_request( reader: &mut Reader, resp_writer: &mut Writer, data_writer: &mut Writer, targets: &BTreeMap<TargetId, AsyncLogicalUnit>, sense_size: u32, cdb_size: u32, ) -> Result<(), ExecuteError>516*bb4ee6a4SAndroid Build Coastguard Worker async fn execute_request(
517*bb4ee6a4SAndroid Build Coastguard Worker reader: &mut Reader,
518*bb4ee6a4SAndroid Build Coastguard Worker resp_writer: &mut Writer,
519*bb4ee6a4SAndroid Build Coastguard Worker data_writer: &mut Writer,
520*bb4ee6a4SAndroid Build Coastguard Worker targets: &BTreeMap<TargetId, AsyncLogicalUnit>,
521*bb4ee6a4SAndroid Build Coastguard Worker sense_size: u32,
522*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: u32,
523*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<(), ExecuteError> {
524*bb4ee6a4SAndroid Build Coastguard Worker let req_header = reader
525*bb4ee6a4SAndroid Build Coastguard Worker .read_obj::<VirtioScsiCmdReqHeader>()
526*bb4ee6a4SAndroid Build Coastguard Worker .map_err(ExecuteError::Read)?;
527*bb4ee6a4SAndroid Build Coastguard Worker match Self::get_logical_unit(req_header.lun, targets) {
528*bb4ee6a4SAndroid Build Coastguard Worker Some(target) => {
529*bb4ee6a4SAndroid Build Coastguard Worker let mut cdb = vec![0; cdb_size as usize];
530*bb4ee6a4SAndroid Build Coastguard Worker reader.read_exact(&mut cdb).map_err(ExecuteError::Read)?;
531*bb4ee6a4SAndroid Build Coastguard Worker let command = Command::new(&cdb)?;
532*bb4ee6a4SAndroid Build Coastguard Worker match command.execute(reader, data_writer, target).await {
533*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => {
534*bb4ee6a4SAndroid Build Coastguard Worker let hdr = VirtioScsiCmdRespHeader {
535*bb4ee6a4SAndroid Build Coastguard Worker sense_len: 0,
536*bb4ee6a4SAndroid Build Coastguard Worker resid: 0,
537*bb4ee6a4SAndroid Build Coastguard Worker status_qualifier: 0,
538*bb4ee6a4SAndroid Build Coastguard Worker status: GOOD,
539*bb4ee6a4SAndroid Build Coastguard Worker response: VIRTIO_SCSI_S_OK as u8,
540*bb4ee6a4SAndroid Build Coastguard Worker };
541*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.write_obj(hdr).map_err(ExecuteError::Write)?;
542*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.consume_bytes(sense_size as usize);
543*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
544*bb4ee6a4SAndroid Build Coastguard Worker }
545*bb4ee6a4SAndroid Build Coastguard Worker Err(err) => {
546*bb4ee6a4SAndroid Build Coastguard Worker error!("error while executing a scsi request: {err}");
547*bb4ee6a4SAndroid Build Coastguard Worker let (hdr, sense) = err.as_resp();
548*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.write_obj(hdr).map_err(ExecuteError::Write)?;
549*bb4ee6a4SAndroid Build Coastguard Worker sense.write_to(resp_writer, sense_size)
550*bb4ee6a4SAndroid Build Coastguard Worker }
551*bb4ee6a4SAndroid Build Coastguard Worker }
552*bb4ee6a4SAndroid Build Coastguard Worker }
553*bb4ee6a4SAndroid Build Coastguard Worker None => {
554*bb4ee6a4SAndroid Build Coastguard Worker let hdr = VirtioScsiCmdRespHeader {
555*bb4ee6a4SAndroid Build Coastguard Worker response: VIRTIO_SCSI_S_BAD_TARGET as u8,
556*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
557*bb4ee6a4SAndroid Build Coastguard Worker };
558*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.write_obj(hdr).map_err(ExecuteError::Write)?;
559*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.consume_bytes(sense_size as usize);
560*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
561*bb4ee6a4SAndroid Build Coastguard Worker }
562*bb4ee6a4SAndroid Build Coastguard Worker }
563*bb4ee6a4SAndroid Build Coastguard Worker }
564*bb4ee6a4SAndroid Build Coastguard Worker
get_logical_unit( lun: [u8; 8], targets: &BTreeMap<TargetId, AsyncLogicalUnit>, ) -> Option<&AsyncLogicalUnit>565*bb4ee6a4SAndroid Build Coastguard Worker fn get_logical_unit(
566*bb4ee6a4SAndroid Build Coastguard Worker lun: [u8; 8],
567*bb4ee6a4SAndroid Build Coastguard Worker targets: &BTreeMap<TargetId, AsyncLogicalUnit>,
568*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<&AsyncLogicalUnit> {
569*bb4ee6a4SAndroid Build Coastguard Worker // First byte should be 1.
570*bb4ee6a4SAndroid Build Coastguard Worker if lun[0] != 1 {
571*bb4ee6a4SAndroid Build Coastguard Worker return None;
572*bb4ee6a4SAndroid Build Coastguard Worker }
573*bb4ee6a4SAndroid Build Coastguard Worker // General search strategy for scsi devices is as follows:
574*bb4ee6a4SAndroid Build Coastguard Worker // 1) Look for a device which has the same bus id and lun indicated by the given lun. If
575*bb4ee6a4SAndroid Build Coastguard Worker // there is one, that is the target device.
576*bb4ee6a4SAndroid Build Coastguard Worker // 2) If we cannot find such device, then we return the first device that has the same bus
577*bb4ee6a4SAndroid Build Coastguard Worker // id.
578*bb4ee6a4SAndroid Build Coastguard Worker // Since we only support one LUN per target, we only need to use the target id.
579*bb4ee6a4SAndroid Build Coastguard Worker let target_id = lun[1];
580*bb4ee6a4SAndroid Build Coastguard Worker targets.get(&target_id)
581*bb4ee6a4SAndroid Build Coastguard Worker }
582*bb4ee6a4SAndroid Build Coastguard Worker }
583*bb4ee6a4SAndroid Build Coastguard Worker
584*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioDevice for Controller {
keep_rds(&self) -> Vec<base::RawDescriptor>585*bb4ee6a4SAndroid Build Coastguard Worker fn keep_rds(&self) -> Vec<base::RawDescriptor> {
586*bb4ee6a4SAndroid Build Coastguard Worker match &self.targets {
587*bb4ee6a4SAndroid Build Coastguard Worker Some(targets) => targets
588*bb4ee6a4SAndroid Build Coastguard Worker .0
589*bb4ee6a4SAndroid Build Coastguard Worker .values()
590*bb4ee6a4SAndroid Build Coastguard Worker .flat_map(|t| t.disk_image.as_raw_descriptors())
591*bb4ee6a4SAndroid Build Coastguard Worker .collect(),
592*bb4ee6a4SAndroid Build Coastguard Worker None => vec![],
593*bb4ee6a4SAndroid Build Coastguard Worker }
594*bb4ee6a4SAndroid Build Coastguard Worker }
595*bb4ee6a4SAndroid Build Coastguard Worker
features(&self) -> u64596*bb4ee6a4SAndroid Build Coastguard Worker fn features(&self) -> u64 {
597*bb4ee6a4SAndroid Build Coastguard Worker self.avail_features
598*bb4ee6a4SAndroid Build Coastguard Worker }
599*bb4ee6a4SAndroid Build Coastguard Worker
device_type(&self) -> VirtioDeviceType600*bb4ee6a4SAndroid Build Coastguard Worker fn device_type(&self) -> VirtioDeviceType {
601*bb4ee6a4SAndroid Build Coastguard Worker VirtioDeviceType::Scsi
602*bb4ee6a4SAndroid Build Coastguard Worker }
603*bb4ee6a4SAndroid Build Coastguard Worker
queue_max_sizes(&self) -> &[u16]604*bb4ee6a4SAndroid Build Coastguard Worker fn queue_max_sizes(&self) -> &[u16] {
605*bb4ee6a4SAndroid Build Coastguard Worker &self.queue_sizes
606*bb4ee6a4SAndroid Build Coastguard Worker }
607*bb4ee6a4SAndroid Build Coastguard Worker
read_config(&self, offset: u64, data: &mut [u8])608*bb4ee6a4SAndroid Build Coastguard Worker fn read_config(&self, offset: u64, data: &mut [u8]) {
609*bb4ee6a4SAndroid Build Coastguard Worker let config_space = self.build_config_space();
610*bb4ee6a4SAndroid Build Coastguard Worker copy_config(data, 0, config_space.as_bytes(), offset);
611*bb4ee6a4SAndroid Build Coastguard Worker }
612*bb4ee6a4SAndroid Build Coastguard Worker
write_config(&mut self, offset: u64, data: &[u8])613*bb4ee6a4SAndroid Build Coastguard Worker fn write_config(&mut self, offset: u64, data: &[u8]) {
614*bb4ee6a4SAndroid Build Coastguard Worker let mut config = [0; std::mem::size_of::<virtio_scsi_config>()];
615*bb4ee6a4SAndroid Build Coastguard Worker copy_config(&mut config, offset, data, 0);
616*bb4ee6a4SAndroid Build Coastguard Worker let config = match virtio_scsi_config::read_from(&config) {
617*bb4ee6a4SAndroid Build Coastguard Worker Some(cfg) => cfg,
618*bb4ee6a4SAndroid Build Coastguard Worker None => {
619*bb4ee6a4SAndroid Build Coastguard Worker warn!("failed to parse virtio_scsi_config");
620*bb4ee6a4SAndroid Build Coastguard Worker return;
621*bb4ee6a4SAndroid Build Coastguard Worker }
622*bb4ee6a4SAndroid Build Coastguard Worker };
623*bb4ee6a4SAndroid Build Coastguard Worker
624*bb4ee6a4SAndroid Build Coastguard Worker let mut updated = [0; std::mem::size_of::<virtio_scsi_config>()];
625*bb4ee6a4SAndroid Build Coastguard Worker updated[offset as usize..offset as usize + data.len()].fill(1);
626*bb4ee6a4SAndroid Build Coastguard Worker let updated = match virtio_scsi_config::read_from(&updated) {
627*bb4ee6a4SAndroid Build Coastguard Worker Some(cfg) => cfg,
628*bb4ee6a4SAndroid Build Coastguard Worker None => {
629*bb4ee6a4SAndroid Build Coastguard Worker warn!("failed to parse virtio_scsi_config");
630*bb4ee6a4SAndroid Build Coastguard Worker return;
631*bb4ee6a4SAndroid Build Coastguard Worker }
632*bb4ee6a4SAndroid Build Coastguard Worker };
633*bb4ee6a4SAndroid Build Coastguard Worker
634*bb4ee6a4SAndroid Build Coastguard Worker if updated.sense_size != 0 {
635*bb4ee6a4SAndroid Build Coastguard Worker self.sense_size = config.sense_size;
636*bb4ee6a4SAndroid Build Coastguard Worker }
637*bb4ee6a4SAndroid Build Coastguard Worker if updated.cdb_size != 0 {
638*bb4ee6a4SAndroid Build Coastguard Worker self.cdb_size = config.cdb_size;
639*bb4ee6a4SAndroid Build Coastguard Worker }
640*bb4ee6a4SAndroid Build Coastguard Worker }
641*bb4ee6a4SAndroid Build Coastguard Worker
activate( &mut self, _mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>642*bb4ee6a4SAndroid Build Coastguard Worker fn activate(
643*bb4ee6a4SAndroid Build Coastguard Worker &mut self,
644*bb4ee6a4SAndroid Build Coastguard Worker _mem: GuestMemory,
645*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt,
646*bb4ee6a4SAndroid Build Coastguard Worker mut queues: BTreeMap<usize, Queue>,
647*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
648*bb4ee6a4SAndroid Build Coastguard Worker let executor_kind = self.executor_kind;
649*bb4ee6a4SAndroid Build Coastguard Worker // 0th virtqueue is the controlq.
650*bb4ee6a4SAndroid Build Coastguard Worker let controlq = queues.remove(&0).context("controlq should be present")?;
651*bb4ee6a4SAndroid Build Coastguard Worker // 1st virtqueue is the eventq.
652*bb4ee6a4SAndroid Build Coastguard Worker // We do not send any events through eventq.
653*bb4ee6a4SAndroid Build Coastguard Worker let _eventq = queues.remove(&1).context("eventq should be present")?;
654*bb4ee6a4SAndroid Build Coastguard Worker let targets = self.targets.take().context("failed to take SCSI targets")?;
655*bb4ee6a4SAndroid Build Coastguard Worker let target_ids = targets.target_ids();
656*bb4ee6a4SAndroid Build Coastguard Worker let sense_size = self.sense_size;
657*bb4ee6a4SAndroid Build Coastguard Worker let cdb_size = self.cdb_size;
658*bb4ee6a4SAndroid Build Coastguard Worker // The rest of the queues are request queues.
659*bb4ee6a4SAndroid Build Coastguard Worker let request_queues = if self.multi_queue {
660*bb4ee6a4SAndroid Build Coastguard Worker queues
661*bb4ee6a4SAndroid Build Coastguard Worker .into_values()
662*bb4ee6a4SAndroid Build Coastguard Worker .map(|queue| {
663*bb4ee6a4SAndroid Build Coastguard Worker let targets = targets
664*bb4ee6a4SAndroid Build Coastguard Worker .try_clone()
665*bb4ee6a4SAndroid Build Coastguard Worker .context("Failed to clone a disk image")?;
666*bb4ee6a4SAndroid Build Coastguard Worker Ok((queue, targets))
667*bb4ee6a4SAndroid Build Coastguard Worker })
668*bb4ee6a4SAndroid Build Coastguard Worker .collect::<anyhow::Result<_>>()?
669*bb4ee6a4SAndroid Build Coastguard Worker } else {
670*bb4ee6a4SAndroid Build Coastguard Worker // Handle all virtio requests with one thread.
671*bb4ee6a4SAndroid Build Coastguard Worker vec![(
672*bb4ee6a4SAndroid Build Coastguard Worker queues
673*bb4ee6a4SAndroid Build Coastguard Worker .remove(&2)
674*bb4ee6a4SAndroid Build Coastguard Worker .context("request queue should be present")?,
675*bb4ee6a4SAndroid Build Coastguard Worker targets,
676*bb4ee6a4SAndroid Build Coastguard Worker )]
677*bb4ee6a4SAndroid Build Coastguard Worker };
678*bb4ee6a4SAndroid Build Coastguard Worker
679*bb4ee6a4SAndroid Build Coastguard Worker let intr = interrupt.clone();
680*bb4ee6a4SAndroid Build Coastguard Worker let worker_thread = WorkerThread::start("v_scsi_ctrlq", move |kill_evt| {
681*bb4ee6a4SAndroid Build Coastguard Worker let ex =
682*bb4ee6a4SAndroid Build Coastguard Worker Executor::with_executor_kind(executor_kind).expect("Failed to create an executor");
683*bb4ee6a4SAndroid Build Coastguard Worker if let Err(err) = ex
684*bb4ee6a4SAndroid Build Coastguard Worker .run_until(run_worker(
685*bb4ee6a4SAndroid Build Coastguard Worker &ex,
686*bb4ee6a4SAndroid Build Coastguard Worker intr,
687*bb4ee6a4SAndroid Build Coastguard Worker controlq,
688*bb4ee6a4SAndroid Build Coastguard Worker kill_evt,
689*bb4ee6a4SAndroid Build Coastguard Worker QueueType::Control { target_ids },
690*bb4ee6a4SAndroid Build Coastguard Worker sense_size,
691*bb4ee6a4SAndroid Build Coastguard Worker cdb_size,
692*bb4ee6a4SAndroid Build Coastguard Worker ))
693*bb4ee6a4SAndroid Build Coastguard Worker .expect("run_until failed")
694*bb4ee6a4SAndroid Build Coastguard Worker {
695*bb4ee6a4SAndroid Build Coastguard Worker error!("run_worker failed: {err}");
696*bb4ee6a4SAndroid Build Coastguard Worker }
697*bb4ee6a4SAndroid Build Coastguard Worker });
698*bb4ee6a4SAndroid Build Coastguard Worker self.worker_threads.push(worker_thread);
699*bb4ee6a4SAndroid Build Coastguard Worker
700*bb4ee6a4SAndroid Build Coastguard Worker for (i, (queue, targets)) in request_queues.into_iter().enumerate() {
701*bb4ee6a4SAndroid Build Coastguard Worker let interrupt = interrupt.clone();
702*bb4ee6a4SAndroid Build Coastguard Worker let worker_thread =
703*bb4ee6a4SAndroid Build Coastguard Worker WorkerThread::start(format!("v_scsi_req_{}", i + 2), move |kill_evt| {
704*bb4ee6a4SAndroid Build Coastguard Worker let ex = Executor::with_executor_kind(executor_kind)
705*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to create an executor");
706*bb4ee6a4SAndroid Build Coastguard Worker let async_logical_unit = targets
707*bb4ee6a4SAndroid Build Coastguard Worker .0
708*bb4ee6a4SAndroid Build Coastguard Worker .into_iter()
709*bb4ee6a4SAndroid Build Coastguard Worker .map(|(idx, unit)| match unit.make_async(&ex) {
710*bb4ee6a4SAndroid Build Coastguard Worker Ok(async_unit) => (idx, async_unit),
711*bb4ee6a4SAndroid Build Coastguard Worker Err(err) => panic!("{err}"),
712*bb4ee6a4SAndroid Build Coastguard Worker })
713*bb4ee6a4SAndroid Build Coastguard Worker .collect();
714*bb4ee6a4SAndroid Build Coastguard Worker if let Err(err) = ex
715*bb4ee6a4SAndroid Build Coastguard Worker .run_until(run_worker(
716*bb4ee6a4SAndroid Build Coastguard Worker &ex,
717*bb4ee6a4SAndroid Build Coastguard Worker interrupt,
718*bb4ee6a4SAndroid Build Coastguard Worker queue,
719*bb4ee6a4SAndroid Build Coastguard Worker kill_evt,
720*bb4ee6a4SAndroid Build Coastguard Worker QueueType::Request(async_logical_unit),
721*bb4ee6a4SAndroid Build Coastguard Worker sense_size,
722*bb4ee6a4SAndroid Build Coastguard Worker cdb_size,
723*bb4ee6a4SAndroid Build Coastguard Worker ))
724*bb4ee6a4SAndroid Build Coastguard Worker .expect("run_until failed")
725*bb4ee6a4SAndroid Build Coastguard Worker {
726*bb4ee6a4SAndroid Build Coastguard Worker error!("run_worker failed: {err}");
727*bb4ee6a4SAndroid Build Coastguard Worker }
728*bb4ee6a4SAndroid Build Coastguard Worker });
729*bb4ee6a4SAndroid Build Coastguard Worker self.worker_threads.push(worker_thread);
730*bb4ee6a4SAndroid Build Coastguard Worker }
731*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
732*bb4ee6a4SAndroid Build Coastguard Worker }
733*bb4ee6a4SAndroid Build Coastguard Worker }
734*bb4ee6a4SAndroid Build Coastguard Worker
735*bb4ee6a4SAndroid Build Coastguard Worker enum QueueType {
736*bb4ee6a4SAndroid Build Coastguard Worker Control { target_ids: BTreeSet<TargetId> },
737*bb4ee6a4SAndroid Build Coastguard Worker Request(BTreeMap<TargetId, AsyncLogicalUnit>),
738*bb4ee6a4SAndroid Build Coastguard Worker }
739*bb4ee6a4SAndroid Build Coastguard Worker
run_worker( ex: &Executor, interrupt: Interrupt, queue: Queue, kill_evt: Event, queue_type: QueueType, sense_size: u32, cdb_size: u32, ) -> anyhow::Result<()>740*bb4ee6a4SAndroid Build Coastguard Worker async fn run_worker(
741*bb4ee6a4SAndroid Build Coastguard Worker ex: &Executor,
742*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt,
743*bb4ee6a4SAndroid Build Coastguard Worker queue: Queue,
744*bb4ee6a4SAndroid Build Coastguard Worker kill_evt: Event,
745*bb4ee6a4SAndroid Build Coastguard Worker queue_type: QueueType,
746*bb4ee6a4SAndroid Build Coastguard Worker sense_size: u32,
747*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: u32,
748*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
749*bb4ee6a4SAndroid Build Coastguard Worker let kill = async_utils::await_and_exit(ex, kill_evt).fuse();
750*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(kill);
751*bb4ee6a4SAndroid Build Coastguard Worker
752*bb4ee6a4SAndroid Build Coastguard Worker let resample = async_utils::handle_irq_resample(ex, interrupt.clone()).fuse();
753*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(resample);
754*bb4ee6a4SAndroid Build Coastguard Worker
755*bb4ee6a4SAndroid Build Coastguard Worker let kick_evt = queue
756*bb4ee6a4SAndroid Build Coastguard Worker .event()
757*bb4ee6a4SAndroid Build Coastguard Worker .try_clone()
758*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to clone queue event");
759*bb4ee6a4SAndroid Build Coastguard Worker let queue_handler = handle_queue(
760*bb4ee6a4SAndroid Build Coastguard Worker Rc::new(RefCell::new(queue)),
761*bb4ee6a4SAndroid Build Coastguard Worker EventAsync::new(kick_evt, ex).expect("Failed to create async event for queue"),
762*bb4ee6a4SAndroid Build Coastguard Worker queue_type,
763*bb4ee6a4SAndroid Build Coastguard Worker sense_size,
764*bb4ee6a4SAndroid Build Coastguard Worker cdb_size,
765*bb4ee6a4SAndroid Build Coastguard Worker )
766*bb4ee6a4SAndroid Build Coastguard Worker .fuse();
767*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(queue_handler);
768*bb4ee6a4SAndroid Build Coastguard Worker
769*bb4ee6a4SAndroid Build Coastguard Worker futures::select! {
770*bb4ee6a4SAndroid Build Coastguard Worker _ = queue_handler => anyhow::bail!("queue handler exited unexpectedly"),
771*bb4ee6a4SAndroid Build Coastguard Worker r = resample => r.context("failed to resample an irq value"),
772*bb4ee6a4SAndroid Build Coastguard Worker r = kill => r.context("failed to wait on the kill event"),
773*bb4ee6a4SAndroid Build Coastguard Worker }
774*bb4ee6a4SAndroid Build Coastguard Worker }
775*bb4ee6a4SAndroid Build Coastguard Worker
handle_queue( queue: Rc<RefCell<Queue>>, evt: EventAsync, queue_type: QueueType, sense_size: u32, cdb_size: u32, )776*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_queue(
777*bb4ee6a4SAndroid Build Coastguard Worker queue: Rc<RefCell<Queue>>,
778*bb4ee6a4SAndroid Build Coastguard Worker evt: EventAsync,
779*bb4ee6a4SAndroid Build Coastguard Worker queue_type: QueueType,
780*bb4ee6a4SAndroid Build Coastguard Worker sense_size: u32,
781*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: u32,
782*bb4ee6a4SAndroid Build Coastguard Worker ) {
783*bb4ee6a4SAndroid Build Coastguard Worker let mut background_tasks = FuturesUnordered::new();
784*bb4ee6a4SAndroid Build Coastguard Worker let evt_future = evt.next_val().fuse();
785*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(evt_future);
786*bb4ee6a4SAndroid Build Coastguard Worker loop {
787*bb4ee6a4SAndroid Build Coastguard Worker futures::select! {
788*bb4ee6a4SAndroid Build Coastguard Worker _ = background_tasks.next() => continue,
789*bb4ee6a4SAndroid Build Coastguard Worker res = evt_future => {
790*bb4ee6a4SAndroid Build Coastguard Worker evt_future.set(evt.next_val().fuse());
791*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = res {
792*bb4ee6a4SAndroid Build Coastguard Worker error!("Failed to read the next queue event: {e}");
793*bb4ee6a4SAndroid Build Coastguard Worker continue;
794*bb4ee6a4SAndroid Build Coastguard Worker }
795*bb4ee6a4SAndroid Build Coastguard Worker }
796*bb4ee6a4SAndroid Build Coastguard Worker }
797*bb4ee6a4SAndroid Build Coastguard Worker while let Some(chain) = queue.borrow_mut().pop() {
798*bb4ee6a4SAndroid Build Coastguard Worker background_tasks.push(process_one_chain(
799*bb4ee6a4SAndroid Build Coastguard Worker &queue,
800*bb4ee6a4SAndroid Build Coastguard Worker chain,
801*bb4ee6a4SAndroid Build Coastguard Worker &queue_type,
802*bb4ee6a4SAndroid Build Coastguard Worker sense_size,
803*bb4ee6a4SAndroid Build Coastguard Worker cdb_size,
804*bb4ee6a4SAndroid Build Coastguard Worker ));
805*bb4ee6a4SAndroid Build Coastguard Worker }
806*bb4ee6a4SAndroid Build Coastguard Worker }
807*bb4ee6a4SAndroid Build Coastguard Worker }
808*bb4ee6a4SAndroid Build Coastguard Worker
process_one_chain( queue: &RefCell<Queue>, mut avail_desc: DescriptorChain, queue_type: &QueueType, sense_size: u32, cdb_size: u32, )809*bb4ee6a4SAndroid Build Coastguard Worker async fn process_one_chain(
810*bb4ee6a4SAndroid Build Coastguard Worker queue: &RefCell<Queue>,
811*bb4ee6a4SAndroid Build Coastguard Worker mut avail_desc: DescriptorChain,
812*bb4ee6a4SAndroid Build Coastguard Worker queue_type: &QueueType,
813*bb4ee6a4SAndroid Build Coastguard Worker sense_size: u32,
814*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: u32,
815*bb4ee6a4SAndroid Build Coastguard Worker ) {
816*bb4ee6a4SAndroid Build Coastguard Worker let _trace = cros_tracing::trace_event!(VirtioScsi, "process_one_chain");
817*bb4ee6a4SAndroid Build Coastguard Worker let len = process_one_request(&mut avail_desc, queue_type, sense_size, cdb_size).await;
818*bb4ee6a4SAndroid Build Coastguard Worker let mut queue = queue.borrow_mut();
819*bb4ee6a4SAndroid Build Coastguard Worker queue.add_used(avail_desc, len as u32);
820*bb4ee6a4SAndroid Build Coastguard Worker queue.trigger_interrupt();
821*bb4ee6a4SAndroid Build Coastguard Worker }
822*bb4ee6a4SAndroid Build Coastguard Worker
process_one_request( avail_desc: &mut DescriptorChain, queue_type: &QueueType, sense_size: u32, cdb_size: u32, ) -> usize823*bb4ee6a4SAndroid Build Coastguard Worker async fn process_one_request(
824*bb4ee6a4SAndroid Build Coastguard Worker avail_desc: &mut DescriptorChain,
825*bb4ee6a4SAndroid Build Coastguard Worker queue_type: &QueueType,
826*bb4ee6a4SAndroid Build Coastguard Worker sense_size: u32,
827*bb4ee6a4SAndroid Build Coastguard Worker cdb_size: u32,
828*bb4ee6a4SAndroid Build Coastguard Worker ) -> usize {
829*bb4ee6a4SAndroid Build Coastguard Worker let reader = &mut avail_desc.reader;
830*bb4ee6a4SAndroid Build Coastguard Worker let resp_writer = &mut avail_desc.writer;
831*bb4ee6a4SAndroid Build Coastguard Worker match queue_type {
832*bb4ee6a4SAndroid Build Coastguard Worker QueueType::Control { target_ids } => {
833*bb4ee6a4SAndroid Build Coastguard Worker if let Err(err) = Controller::execute_control(reader, resp_writer, target_ids) {
834*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to execute control request: {err}");
835*bb4ee6a4SAndroid Build Coastguard Worker }
836*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.bytes_written()
837*bb4ee6a4SAndroid Build Coastguard Worker }
838*bb4ee6a4SAndroid Build Coastguard Worker QueueType::Request(async_targets) => {
839*bb4ee6a4SAndroid Build Coastguard Worker let mut data_writer = resp_writer
840*bb4ee6a4SAndroid Build Coastguard Worker .split_at(std::mem::size_of::<VirtioScsiCmdRespHeader>() + sense_size as usize);
841*bb4ee6a4SAndroid Build Coastguard Worker if let Err(err) = Controller::execute_request(
842*bb4ee6a4SAndroid Build Coastguard Worker reader,
843*bb4ee6a4SAndroid Build Coastguard Worker resp_writer,
844*bb4ee6a4SAndroid Build Coastguard Worker &mut data_writer,
845*bb4ee6a4SAndroid Build Coastguard Worker async_targets,
846*bb4ee6a4SAndroid Build Coastguard Worker sense_size,
847*bb4ee6a4SAndroid Build Coastguard Worker cdb_size,
848*bb4ee6a4SAndroid Build Coastguard Worker )
849*bb4ee6a4SAndroid Build Coastguard Worker .await
850*bb4ee6a4SAndroid Build Coastguard Worker {
851*bb4ee6a4SAndroid Build Coastguard Worker // If the write of the virtio_scsi_cmd_resp fails, there is nothing we can do to
852*bb4ee6a4SAndroid Build Coastguard Worker // inform the error to the guest driver (we usually propagate errors with sense
853*bb4ee6a4SAndroid Build Coastguard Worker // field, which is in the struct virtio_scsi_cmd_resp). The guest driver should
854*bb4ee6a4SAndroid Build Coastguard Worker // have at least sizeof(virtio_scsi_cmd_resp) bytes of device-writable part
855*bb4ee6a4SAndroid Build Coastguard Worker // regions. For now we simply emit an error message.
856*bb4ee6a4SAndroid Build Coastguard Worker let (hdr, sense) = err.as_resp();
857*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = resp_writer.write_obj(hdr) {
858*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to write VirtioScsiCmdRespHeader: {e}");
859*bb4ee6a4SAndroid Build Coastguard Worker }
860*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = sense.write_to(resp_writer, sense_size) {
861*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to write sense data: {e}");
862*bb4ee6a4SAndroid Build Coastguard Worker }
863*bb4ee6a4SAndroid Build Coastguard Worker }
864*bb4ee6a4SAndroid Build Coastguard Worker resp_writer.bytes_written() + data_writer.bytes_written()
865*bb4ee6a4SAndroid Build Coastguard Worker }
866*bb4ee6a4SAndroid Build Coastguard Worker }
867*bb4ee6a4SAndroid Build Coastguard Worker }
868*bb4ee6a4SAndroid Build Coastguard Worker
869*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
870*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
871*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
872*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of;
873*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of_val;
874*bb4ee6a4SAndroid Build Coastguard Worker use std::rc::Rc;
875*bb4ee6a4SAndroid Build Coastguard Worker
876*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::Executor;
877*bb4ee6a4SAndroid Build Coastguard Worker use disk::SingleFileDisk;
878*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::tempfile;
879*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_cmd_req;
880*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::virtio_scsi_cmd_resp;
881*bb4ee6a4SAndroid Build Coastguard Worker use virtio_sys::virtio_scsi::VIRTIO_SCSI_S_OK;
882*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
883*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
884*bb4ee6a4SAndroid Build Coastguard Worker
885*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
886*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::create_descriptor_chain;
887*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::scsi::constants::READ_10;
888*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::DescriptorType;
889*bb4ee6a4SAndroid Build Coastguard Worker
setup_disk(disk_size: u64) -> (File, Vec<u8>)890*bb4ee6a4SAndroid Build Coastguard Worker fn setup_disk(disk_size: u64) -> (File, Vec<u8>) {
891*bb4ee6a4SAndroid Build Coastguard Worker let mut file_content = vec![0; disk_size as usize];
892*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..disk_size {
893*bb4ee6a4SAndroid Build Coastguard Worker file_content[i as usize] = (i % 10) as u8;
894*bb4ee6a4SAndroid Build Coastguard Worker }
895*bb4ee6a4SAndroid Build Coastguard Worker let mut f = tempfile().unwrap();
896*bb4ee6a4SAndroid Build Coastguard Worker f.set_len(disk_size).unwrap();
897*bb4ee6a4SAndroid Build Coastguard Worker f.write_all(file_content.as_slice()).unwrap();
898*bb4ee6a4SAndroid Build Coastguard Worker (f, file_content)
899*bb4ee6a4SAndroid Build Coastguard Worker }
900*bb4ee6a4SAndroid Build Coastguard Worker
build_read_req_header(target_id: u8, start_lba: u8, xfer_blocks: u8) -> virtio_scsi_cmd_req901*bb4ee6a4SAndroid Build Coastguard Worker fn build_read_req_header(target_id: u8, start_lba: u8, xfer_blocks: u8) -> virtio_scsi_cmd_req {
902*bb4ee6a4SAndroid Build Coastguard Worker let mut cdb = [0; 32];
903*bb4ee6a4SAndroid Build Coastguard Worker cdb[0] = READ_10;
904*bb4ee6a4SAndroid Build Coastguard Worker cdb[5] = start_lba;
905*bb4ee6a4SAndroid Build Coastguard Worker cdb[8] = xfer_blocks;
906*bb4ee6a4SAndroid Build Coastguard Worker virtio_scsi_cmd_req {
907*bb4ee6a4SAndroid Build Coastguard Worker lun: [1, 0, 0, target_id, 0, 0, 0, 0],
908*bb4ee6a4SAndroid Build Coastguard Worker cdb,
909*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
910*bb4ee6a4SAndroid Build Coastguard Worker }
911*bb4ee6a4SAndroid Build Coastguard Worker }
912*bb4ee6a4SAndroid Build Coastguard Worker
setup_desciptor_chain( target_id: TargetId, start_lba: u8, xfer_blocks: u8, block_size: u32, mem: &Rc<GuestMemory>, ) -> DescriptorChain913*bb4ee6a4SAndroid Build Coastguard Worker fn setup_desciptor_chain(
914*bb4ee6a4SAndroid Build Coastguard Worker target_id: TargetId,
915*bb4ee6a4SAndroid Build Coastguard Worker start_lba: u8,
916*bb4ee6a4SAndroid Build Coastguard Worker xfer_blocks: u8,
917*bb4ee6a4SAndroid Build Coastguard Worker block_size: u32,
918*bb4ee6a4SAndroid Build Coastguard Worker mem: &Rc<GuestMemory>,
919*bb4ee6a4SAndroid Build Coastguard Worker ) -> DescriptorChain {
920*bb4ee6a4SAndroid Build Coastguard Worker let req_hdr = build_read_req_header(target_id, start_lba, xfer_blocks);
921*bb4ee6a4SAndroid Build Coastguard Worker let xfer_bytes = xfer_blocks as u32 * block_size;
922*bb4ee6a4SAndroid Build Coastguard Worker create_descriptor_chain(
923*bb4ee6a4SAndroid Build Coastguard Worker mem,
924*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress(0x100), // Place descriptor chain at 0x100.
925*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress(0x1000), // Describe buffer at 0x1000.
926*bb4ee6a4SAndroid Build Coastguard Worker vec![
927*bb4ee6a4SAndroid Build Coastguard Worker // Request header
928*bb4ee6a4SAndroid Build Coastguard Worker (DescriptorType::Readable, size_of_val(&req_hdr) as u32),
929*bb4ee6a4SAndroid Build Coastguard Worker // Response header
930*bb4ee6a4SAndroid Build Coastguard Worker (
931*bb4ee6a4SAndroid Build Coastguard Worker DescriptorType::Writable,
932*bb4ee6a4SAndroid Build Coastguard Worker size_of::<virtio_scsi_cmd_resp>() as u32,
933*bb4ee6a4SAndroid Build Coastguard Worker ),
934*bb4ee6a4SAndroid Build Coastguard Worker (DescriptorType::Writable, xfer_bytes),
935*bb4ee6a4SAndroid Build Coastguard Worker ],
936*bb4ee6a4SAndroid Build Coastguard Worker 0,
937*bb4ee6a4SAndroid Build Coastguard Worker )
938*bb4ee6a4SAndroid Build Coastguard Worker .expect("create_descriptor_chain failed")
939*bb4ee6a4SAndroid Build Coastguard Worker }
940*bb4ee6a4SAndroid Build Coastguard Worker
read_blocks( ex: &Executor, file_disks: &[File], target_id: u8, start_lba: u8, xfer_blocks: u8, block_size: u32, ) -> (virtio_scsi_cmd_resp, Vec<u8>)941*bb4ee6a4SAndroid Build Coastguard Worker fn read_blocks(
942*bb4ee6a4SAndroid Build Coastguard Worker ex: &Executor,
943*bb4ee6a4SAndroid Build Coastguard Worker file_disks: &[File],
944*bb4ee6a4SAndroid Build Coastguard Worker target_id: u8,
945*bb4ee6a4SAndroid Build Coastguard Worker start_lba: u8,
946*bb4ee6a4SAndroid Build Coastguard Worker xfer_blocks: u8,
947*bb4ee6a4SAndroid Build Coastguard Worker block_size: u32,
948*bb4ee6a4SAndroid Build Coastguard Worker ) -> (virtio_scsi_cmd_resp, Vec<u8>) {
949*bb4ee6a4SAndroid Build Coastguard Worker let xfer_bytes = xfer_blocks as u32 * block_size;
950*bb4ee6a4SAndroid Build Coastguard Worker let mem = Rc::new(
951*bb4ee6a4SAndroid Build Coastguard Worker GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
952*bb4ee6a4SAndroid Build Coastguard Worker .expect("Creating guest memory failed."),
953*bb4ee6a4SAndroid Build Coastguard Worker );
954*bb4ee6a4SAndroid Build Coastguard Worker let req_hdr = build_read_req_header(target_id, start_lba, xfer_blocks);
955*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(req_hdr, GuestAddress(0x1000))
956*bb4ee6a4SAndroid Build Coastguard Worker .expect("writing req failed");
957*bb4ee6a4SAndroid Build Coastguard Worker
958*bb4ee6a4SAndroid Build Coastguard Worker let mut avail_desc = setup_desciptor_chain(target_id, 0, xfer_blocks, block_size, &mem);
959*bb4ee6a4SAndroid Build Coastguard Worker
960*bb4ee6a4SAndroid Build Coastguard Worker let targets = file_disks
961*bb4ee6a4SAndroid Build Coastguard Worker .iter()
962*bb4ee6a4SAndroid Build Coastguard Worker .enumerate()
963*bb4ee6a4SAndroid Build Coastguard Worker .map(|(i, file)| {
964*bb4ee6a4SAndroid Build Coastguard Worker let file = file.try_clone().unwrap();
965*bb4ee6a4SAndroid Build Coastguard Worker let disk_image = Box::new(SingleFileDisk::new(file, ex).unwrap());
966*bb4ee6a4SAndroid Build Coastguard Worker let logical_unit = AsyncLogicalUnit {
967*bb4ee6a4SAndroid Build Coastguard Worker max_lba: 0x1000,
968*bb4ee6a4SAndroid Build Coastguard Worker block_size,
969*bb4ee6a4SAndroid Build Coastguard Worker read_only: false,
970*bb4ee6a4SAndroid Build Coastguard Worker disk_image,
971*bb4ee6a4SAndroid Build Coastguard Worker };
972*bb4ee6a4SAndroid Build Coastguard Worker (i as TargetId, logical_unit)
973*bb4ee6a4SAndroid Build Coastguard Worker })
974*bb4ee6a4SAndroid Build Coastguard Worker .collect();
975*bb4ee6a4SAndroid Build Coastguard Worker ex.run_until(process_one_request(
976*bb4ee6a4SAndroid Build Coastguard Worker &mut avail_desc,
977*bb4ee6a4SAndroid Build Coastguard Worker &QueueType::Request(targets),
978*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_SENSE_DEFAULT_SIZE,
979*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_SCSI_CDB_DEFAULT_SIZE,
980*bb4ee6a4SAndroid Build Coastguard Worker ))
981*bb4ee6a4SAndroid Build Coastguard Worker .expect("running executor failed");
982*bb4ee6a4SAndroid Build Coastguard Worker let resp_offset = GuestAddress((0x1000 + size_of::<virtio_scsi_cmd_resp>()) as u64);
983*bb4ee6a4SAndroid Build Coastguard Worker let resp = mem
984*bb4ee6a4SAndroid Build Coastguard Worker .read_obj_from_addr::<virtio_scsi_cmd_resp>(resp_offset)
985*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
986*bb4ee6a4SAndroid Build Coastguard Worker let dataout_offset = GuestAddress(
987*bb4ee6a4SAndroid Build Coastguard Worker (0x1000 + size_of::<virtio_scsi_cmd_req>() + size_of::<virtio_scsi_cmd_resp>()) as u64,
988*bb4ee6a4SAndroid Build Coastguard Worker );
989*bb4ee6a4SAndroid Build Coastguard Worker let dataout_slice = mem
990*bb4ee6a4SAndroid Build Coastguard Worker .get_slice_at_addr(dataout_offset, xfer_bytes as usize)
991*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
992*bb4ee6a4SAndroid Build Coastguard Worker let mut dataout = vec![0; xfer_bytes as usize];
993*bb4ee6a4SAndroid Build Coastguard Worker dataout_slice.copy_to(&mut dataout);
994*bb4ee6a4SAndroid Build Coastguard Worker (resp, dataout)
995*bb4ee6a4SAndroid Build Coastguard Worker }
996*bb4ee6a4SAndroid Build Coastguard Worker
test_read_blocks( num_targets: usize, blocks: u8, start_lba: u8, xfer_blocks: u8, block_size: u32, )997*bb4ee6a4SAndroid Build Coastguard Worker fn test_read_blocks(
998*bb4ee6a4SAndroid Build Coastguard Worker num_targets: usize,
999*bb4ee6a4SAndroid Build Coastguard Worker blocks: u8,
1000*bb4ee6a4SAndroid Build Coastguard Worker start_lba: u8,
1001*bb4ee6a4SAndroid Build Coastguard Worker xfer_blocks: u8,
1002*bb4ee6a4SAndroid Build Coastguard Worker block_size: u32,
1003*bb4ee6a4SAndroid Build Coastguard Worker ) {
1004*bb4ee6a4SAndroid Build Coastguard Worker let ex = Executor::new().expect("creating an executor failed");
1005*bb4ee6a4SAndroid Build Coastguard Worker let file_len = blocks as u64 * block_size as u64;
1006*bb4ee6a4SAndroid Build Coastguard Worker let xfer_bytes = xfer_blocks as usize * block_size as usize;
1007*bb4ee6a4SAndroid Build Coastguard Worker let start_off = start_lba as usize * block_size as usize;
1008*bb4ee6a4SAndroid Build Coastguard Worker
1009*bb4ee6a4SAndroid Build Coastguard Worker let (files, file_contents): (Vec<_>, Vec<_>) =
1010*bb4ee6a4SAndroid Build Coastguard Worker (0..num_targets).map(|_| setup_disk(file_len)).unzip();
1011*bb4ee6a4SAndroid Build Coastguard Worker for (target_id, file_content) in file_contents.iter().enumerate() {
1012*bb4ee6a4SAndroid Build Coastguard Worker let (resp, dataout) = read_blocks(
1013*bb4ee6a4SAndroid Build Coastguard Worker &ex,
1014*bb4ee6a4SAndroid Build Coastguard Worker &files,
1015*bb4ee6a4SAndroid Build Coastguard Worker target_id as TargetId,
1016*bb4ee6a4SAndroid Build Coastguard Worker start_lba,
1017*bb4ee6a4SAndroid Build Coastguard Worker xfer_blocks,
1018*bb4ee6a4SAndroid Build Coastguard Worker block_size,
1019*bb4ee6a4SAndroid Build Coastguard Worker );
1020*bb4ee6a4SAndroid Build Coastguard Worker
1021*bb4ee6a4SAndroid Build Coastguard Worker let sense_len = resp.sense_len;
1022*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(sense_len, 0);
1023*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(resp.status, VIRTIO_SCSI_S_OK as u8);
1024*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(resp.response, GOOD);
1025*bb4ee6a4SAndroid Build Coastguard Worker
1026*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&dataout, &file_content[start_off..(start_off + xfer_bytes)]);
1027*bb4ee6a4SAndroid Build Coastguard Worker }
1028*bb4ee6a4SAndroid Build Coastguard Worker }
1029*bb4ee6a4SAndroid Build Coastguard Worker
1030*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_first_blocks()1031*bb4ee6a4SAndroid Build Coastguard Worker fn read_first_blocks() {
1032*bb4ee6a4SAndroid Build Coastguard Worker // Read the first 3 blocks of a 8-block device.
1033*bb4ee6a4SAndroid Build Coastguard Worker let blocks = 8u8;
1034*bb4ee6a4SAndroid Build Coastguard Worker let start_lba = 0u8;
1035*bb4ee6a4SAndroid Build Coastguard Worker let xfer_blocks = 3u8;
1036*bb4ee6a4SAndroid Build Coastguard Worker
1037*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(1, blocks, start_lba, xfer_blocks, 64u32);
1038*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(1, blocks, start_lba, xfer_blocks, 128u32);
1039*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(1, blocks, start_lba, xfer_blocks, 512u32);
1040*bb4ee6a4SAndroid Build Coastguard Worker }
1041*bb4ee6a4SAndroid Build Coastguard Worker
1042*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_middle_blocks()1043*bb4ee6a4SAndroid Build Coastguard Worker fn read_middle_blocks() {
1044*bb4ee6a4SAndroid Build Coastguard Worker // Read 3 blocks from the 2nd block in the 8-block device.
1045*bb4ee6a4SAndroid Build Coastguard Worker let blocks = 8u8;
1046*bb4ee6a4SAndroid Build Coastguard Worker let start_lba = 1u8;
1047*bb4ee6a4SAndroid Build Coastguard Worker let xfer_blocks = 3u8;
1048*bb4ee6a4SAndroid Build Coastguard Worker
1049*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(1, blocks, start_lba, xfer_blocks, 64u32);
1050*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(1, blocks, start_lba, xfer_blocks, 128u32);
1051*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(1, blocks, start_lba, xfer_blocks, 512u32);
1052*bb4ee6a4SAndroid Build Coastguard Worker }
1053*bb4ee6a4SAndroid Build Coastguard Worker
1054*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_first_blocks_with_multiple_disks()1055*bb4ee6a4SAndroid Build Coastguard Worker fn read_first_blocks_with_multiple_disks() {
1056*bb4ee6a4SAndroid Build Coastguard Worker // Read the first 3 blocks of a 8-block device.
1057*bb4ee6a4SAndroid Build Coastguard Worker let blocks = 8u8;
1058*bb4ee6a4SAndroid Build Coastguard Worker let start_lba = 0u8;
1059*bb4ee6a4SAndroid Build Coastguard Worker let xfer_blocks = 3u8;
1060*bb4ee6a4SAndroid Build Coastguard Worker
1061*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(3, blocks, start_lba, xfer_blocks, 64u32);
1062*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(3, blocks, start_lba, xfer_blocks, 128u32);
1063*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(3, blocks, start_lba, xfer_blocks, 512u32);
1064*bb4ee6a4SAndroid Build Coastguard Worker }
1065*bb4ee6a4SAndroid Build Coastguard Worker
1066*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_middle_blocks_with_multiple_disks()1067*bb4ee6a4SAndroid Build Coastguard Worker fn read_middle_blocks_with_multiple_disks() {
1068*bb4ee6a4SAndroid Build Coastguard Worker // Read 3 blocks from the 2nd block in the 8-block device.
1069*bb4ee6a4SAndroid Build Coastguard Worker let blocks = 8u8;
1070*bb4ee6a4SAndroid Build Coastguard Worker let start_lba = 1u8;
1071*bb4ee6a4SAndroid Build Coastguard Worker let xfer_blocks = 3u8;
1072*bb4ee6a4SAndroid Build Coastguard Worker
1073*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(3, blocks, start_lba, xfer_blocks, 64u32);
1074*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(3, blocks, start_lba, xfer_blocks, 128u32);
1075*bb4ee6a4SAndroid Build Coastguard Worker test_read_blocks(3, blocks, start_lba, xfer_blocks, 512u32);
1076*bb4ee6a4SAndroid Build Coastguard Worker }
1077*bb4ee6a4SAndroid Build Coastguard Worker }
1078