storvsp_protocol/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Wire-format definitions for the Hyper-V SCSI VMBus protocol.
5//!
6//! Defines packet structures, interface GUIDs (`SCSI_INTERFACE_ID`,
7//! `IDE_ACCELERATOR_INTERFACE_ID`), and protocol version negotiation types.
8
9#![expect(missing_docs)]
10#![forbid(unsafe_code)]
11
12use guid::Guid;
13use open_enum::open_enum;
14use scsi_defs::ScsiStatus;
15use scsi_defs::srb::SrbStatusAndFlags;
16use std::fmt::Debug;
17use zerocopy::FromBytes;
18use zerocopy::Immutable;
19use zerocopy::IntoBytes;
20use zerocopy::KnownLayout;
21
22pub const SCSI_INTERFACE_ID: Guid = guid::guid!("ba6163d9-04a1-4d29-b605-72e2ffb1dc7f");
23
24pub const IDE_ACCELERATOR_INTERFACE_ID: Guid = guid::guid!("32412632-86cb-44a2-9b5c-50d1417354f5");
25
26/// Sent as part of the channel offer. Old versions of Windows drivers look at
27/// this to determine the IDE device the channel is for. Newer drivers and Linux
28/// just look at instance ID.
29#[repr(C)]
30#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
31pub struct OfferProperties {
32    pub reserved: u16,
33    pub path_id: u8,
34    pub target_id: u8,
35    pub reserved2: u32,
36    pub flags: u32,
37    pub reserved3: [u32; 3],
38}
39
40pub const OFFER_PROPERTIES_FLAG_IDE_DEVICE: u32 = 0x2;
41
42const fn version(major: u8, minor: u8) -> u16 {
43    (major as u16) << 8 | minor as u16
44}
45
46pub const VERSION_WIN6: u16 = version(2, 0);
47pub const VERSION_WIN7: u16 = version(4, 2);
48pub const VERSION_WIN8: u16 = version(5, 1);
49pub const VERSION_BLUE: u16 = version(6, 0);
50pub const VERSION_THRESHOLD: u16 = version(6, 2);
51
52open_enum! {
53    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
54    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
55    pub enum NtStatus: u32 {
56        SUCCESS = 0x0000_0000,
57        BUFFER_OVERFLOW = 0x8000_0005, // The data was too large to fit into the specified buffer.
58        DEVICE_BUSY = 0x8000_0011, // The device is currently busy.
59
60        UNSUCCESSFUL = 0xC000_0001, // The requested operation was unsuccessful.
61        INVALID_PARAMETER = 0xC000_000D, // An invalid parameter was passed to a service or function.
62        INVALID_DEVICE_REQUEST = 0xC000_0010, // The specified request is not a valid operation for the target device.
63        REVISION_MISMATCH = 0xC000_0059, // Used to indicate the requested version is not supported.
64        DEVICE_NOT_CONNECTED = 0xC000_009D,
65        IO_TIMEOUT = 0xC000_00B5, // The specified I/O operation was not completed before the time-out period expired.
66        DEVICE_DOES_NOT_EXIST = 0xC000_00C0, // This device does not exist.
67        CANCELLED = 0xC000_0120, // The I/O request was canceled.
68
69        INVALID_DEVICE_STATE = 0xC000_0184, // The device is not in a valid state to perform this request.
70        IO_DEVICE_ERROR = 0xC000_0185, // The I/O device reported an I/O error.
71    }
72}
73
74#[repr(C)]
75#[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
76#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
77pub struct Packet {
78    // Requested operation type
79    pub operation: Operation,
80    //  Flags - see below for values
81    pub flags: u32,
82    // Status of the request returned from the server side.
83    pub status: NtStatus,
84}
85
86open_enum! {
87    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
88    #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
89    pub enum Operation: u32 {
90        COMPLETE_IO = 1,
91        REMOVE_DEVICE = 2,
92        EXECUTE_SRB = 3,
93        RESET_LUN = 4,
94        RESET_ADAPTER = 5,
95        RESET_BUS = 6,
96        BEGIN_INITIALIZATION = 7,
97        END_INITIALIZATION = 8,
98        QUERY_PROTOCOL_VERSION = 9,
99        QUERY_PROPERTIES = 10,
100        ENUMERATE_BUS = 11,
101        FC_HBA_DATA = 12,
102        CREATE_SUB_CHANNELS = 13,
103        EVENT_NOTIFICATION = 14,
104    }
105}
106
107pub const CDB16GENERIC_LENGTH: usize = 0x10;
108pub const MAX_DATA_BUFFER_LENGTH_WITH_PADDING: usize = 0x14;
109pub const VMSCSI_SENSE_BUFFER_SIZE: usize = 0x14;
110
111#[repr(C)]
112#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
113#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
114pub struct ScsiRequest {
115    pub length: u16,
116    pub srb_status: SrbStatusAndFlags,
117    pub scsi_status: ScsiStatus,
118
119    pub reserved1: u8,
120    pub path_id: u8,
121    pub target_id: u8,
122    pub lun: u8,
123
124    pub cdb_length: u8,
125    pub sense_info_ex_length: u8,
126    pub data_in: u8,
127    pub properties: u8,
128
129    pub data_transfer_length: u32,
130
131    pub payload: [u8; MAX_DATA_BUFFER_LENGTH_WITH_PADDING],
132
133    // The following were added in Windows 8
134    pub reserve: u16,
135    pub queue_tag: u8,
136    pub queue_action: u8,
137    pub srb_flags: u32,
138    pub time_out_value: u32,
139    pub queue_sort_key: u32,
140}
141
142pub const SCSI_REQUEST_LEN_V1: usize = 0x24;
143pub const SCSI_REQUEST_LEN_V2: usize = 0x34;
144pub const SCSI_REQUEST_LEN_MAX: usize = SCSI_REQUEST_LEN_V2;
145
146const _: () = assert!(SCSI_REQUEST_LEN_MAX == size_of::<ScsiRequest>());
147
148#[repr(C)]
149#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
150pub struct ChannelProperties {
151    pub reserved: u32,
152    pub maximum_sub_channel_count: u16,
153    pub reserved2: u16,
154    pub flags: u32,
155    pub max_transfer_bytes: u32,
156    pub reserved3: [u32; 2],
157}
158
159// ChannelProperties flags
160pub const STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL: u32 = 0x1;
161
162#[repr(C)]
163#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
164pub struct ProtocolVersion {
165    // Major (MSB) and minor (LSB) version numbers.
166    pub major_minor: u16,
167    pub reserved: u16,
168}
169
170#[repr(C)]
171#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
172pub struct ClientProperties {
173    flags: u32, // AsyncNotifyCapable
174}
175
176#[repr(C)]
177#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
178pub struct NotificationPacket {
179    pub lun: u8,
180    pub target: u8,
181    pub path: u8,
182    pub flags: u8,
183}
184
185pub const SCSI_IOCTL_DATA_OUT: u8 = 0;
186pub const SCSI_IOCTL_DATA_IN: u8 = 1;