storvsp_protocol/
lib.rs

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