From 4c8a2bc3ac3bfc453455815527d775a521e80f37 Mon Sep 17 00:00:00 2001 From: Erik Schilling Date: Tue, 18 Apr 2023 10:09:14 +0200 Subject: [PATCH] scsi: Advertise support for CONFIG The config that we send is based on the current QEMU defaults (as of 60ca584b8af0de525656f959991a440f8c191f12). This allows testing using Alex Bennee's vhost-user-generic series and will be required for hypervisors that do not come with the stubs that QEMU has (eg: Xen). Signed-off-by: Erik Schilling Link: https://lore.kernel.org/all/20230414160433.2096866-1-alex.bennee@linaro.org/ --- crates/scsi/src/vhu_scsi.rs | 65 +++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/crates/scsi/src/vhu_scsi.rs b/crates/scsi/src/vhu_scsi.rs index 915419e..8567654 100644 --- a/crates/scsi/src/vhu_scsi.rs +++ b/crates/scsi/src/vhu_scsi.rs @@ -1,11 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause -use std::convert::TryFrom; +use core::slice; +use std::convert::{TryFrom, TryInto}; use std::io::{self, ErrorKind}; +use std::mem; use log::{debug, error, info, warn}; use vhost::vhost_user::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; use vhost_user_backend::{VhostUserBackendMut, VringRwLock, VringT}; +use virtio_bindings::virtio_scsi::{virtio_scsi_config, virtio_scsi_event}; use virtio_bindings::{ virtio_config::VIRTIO_F_VERSION_1, virtio_ring::{VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC}, @@ -19,6 +22,7 @@ use vmm_sys_util::{ }; use crate::scsi::Target; +use crate::virtio::CDB_SIZE; use crate::{ scsi::{self, CmdError, TaskAttr}, virtio::{self, Request, RequestParseError, Response, ResponseCode, VirtioScsiLun, SENSE_SIZE}, @@ -211,7 +215,7 @@ impl VhostUserBackendMut for VhostUserScsiBackend { } fn protocol_features(&self) -> VhostUserProtocolFeatures { - VhostUserProtocolFeatures::MQ + VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIG } fn set_event_idx(&mut self, enabled: bool) { @@ -267,9 +271,38 @@ impl VhostUserBackendMut for VhostUserScsiBackend { Ok(false) } - fn get_config(&self, _offset: u32, _size: u32) -> Vec { - // QEMU handles config space itself - panic!("Access to configuration space is not supported."); + fn get_config(&self, offset: u32, size: u32) -> Vec { + let config = virtio_scsi_config { + num_queues: 1, + seg_max: 128 - 2, + max_sectors: 0xFFFF, + cmd_per_lun: 128, + event_info_size: mem::size_of::() + .try_into() + .expect("event info size should fit 32bit"), + sense_size: SENSE_SIZE.try_into().expect("SENSE_SIZE should fit 32bit"), + cdb_size: CDB_SIZE.try_into().expect("CDB_SIZE should fit 32bit"), + max_channel: 0, + max_target: 255, + max_lun: u32::from(!u16::from(VirtioScsiLun::ADDRESS_METHOD_PATTERN) << 8 | 0xff), + }; + + // SAFETY: + // Pointer is aligned (points to start of struct), valid and we only + // access up to the size of the struct. + let config_slice = unsafe { + slice::from_raw_parts( + &config as *const virtio_scsi_config as *const u8, + mem::size_of::(), + ) + }; + + config_slice + .iter() + .skip(offset as usize) + .take(size as usize) + .cloned() + .collect() } fn set_config(&mut self, _offset: u32, _buf: &[u8]) -> std::result::Result<(), std::io::Error> { @@ -294,7 +327,8 @@ mod tests { use virtio_bindings::{ virtio_ring::VRING_DESC_F_WRITE, virtio_scsi::{ - virtio_scsi_cmd_req, VIRTIO_SCSI_S_BAD_TARGET, VIRTIO_SCSI_S_FAILURE, VIRTIO_SCSI_S_OK, + virtio_scsi_cmd_req, virtio_scsi_config, VIRTIO_SCSI_S_BAD_TARGET, + VIRTIO_SCSI_S_FAILURE, VIRTIO_SCSI_S_OK, }, }; use virtio_queue::{mock::MockSplitQueue, Descriptor}; @@ -565,4 +599,23 @@ mod tests { "expect no command to make it to the target" ); } + + #[test] + fn test_reading_config() { + let backend = VhostUserScsiBackend::new(); + + // 0 len slice + assert_eq!(vec![0_u8; 0], backend.get_config(0, 0)); + // overly long slice + assert_eq!( + std::mem::size_of::(), + backend.get_config(0, 2000).len() + ); + // subslice + assert_eq!(1, backend.get_config(4, 1).len()); + // overly long subslice + assert_eq!(28, backend.get_config(8, 10000).len()); + // offset after end + assert_eq!(0, backend.get_config(100000, 10).len()); + } }