iscsi_client_rs/models/data/
request.rs1use anyhow::{Result, bail};
8use zerocopy::{
9 BigEndian, FromBytes as ZFromBytes, Immutable, IntoBytes, KnownLayout, U32,
10};
11
12use crate::{
13 client::pdu_connection::FromBytes,
14 models::{
15 common::{
16 BasicHeaderSegment, HEADER_LEN, InitiatorTaskTag, LogicalUnitNumber,
17 SendingData,
18 },
19 data::common::RawDataOutFlags,
20 data_fromat::ZeroCopyType,
21 opcode::{BhsOpcode, Opcode, RawBhsOpcode},
22 },
23};
24
25#[repr(C)]
27#[derive(Debug, Default, PartialEq, ZFromBytes, IntoBytes, KnownLayout, Immutable)]
28pub struct ScsiDataOut {
29 pub opcode: RawBhsOpcode, pub flags: RawDataOutFlags, pub reserved2: [u8; 2], pub total_ahs_length: u8, pub data_segment_length: [u8; 3], pub lun: LogicalUnitNumber, pub initiator_task_tag: InitiatorTaskTag, pub target_transfer_tag: U32<BigEndian>, pub exp_stat_sn: U32<BigEndian>, pub reserved3: [u8; 8], pub data_sn: U32<BigEndian>, pub buffer_offset: U32<BigEndian>, pub reserved4: u32, }
43
44impl ScsiDataOut {
45 pub fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
47 buf.fill(0);
48 if buf.len() != HEADER_LEN {
49 bail!("buffer length must be {HEADER_LEN}, got {}", buf.len());
50 }
51 buf.copy_from_slice(self.as_bytes());
52 Ok(())
53 }
54
55 pub fn from_bhs_bytes(buf: &mut [u8]) -> Result<&mut Self> {
57 let hdr = Self::mut_from_bytes(buf)
58 .map_err(|e| anyhow::anyhow!("failed convert buffer ScsiDataOut: {e}"))?;
59 if hdr.opcode.opcode_known() != Some(Opcode::ScsiDataOut) {
60 anyhow::bail!(
61 "ScsiDataOut: invalid opcode 0x{:02x}",
62 hdr.opcode.opcode_raw()
63 );
64 }
65 Ok(hdr)
66 }
67}
68
69impl SendingData for ScsiDataOut {
70 fn get_final_bit(&self) -> bool {
71 self.flags.fin()
72 }
73
74 fn set_final_bit(&mut self) {
75 self.flags.set_fin(true);
76 }
77
78 fn get_continue_bit(&self) -> bool {
79 !self.flags.fin()
80 }
81
82 fn set_continue_bit(&mut self) {
83 self.flags.set_fin(false);
84 }
85}
86
87impl FromBytes for ScsiDataOut {
88 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
89 ScsiDataOut::from_bhs_bytes(bytes)
90 }
91}
92
93impl BasicHeaderSegment for ScsiDataOut {
94 #[inline]
95 fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
96 self.to_bhs_bytes(buf)
97 }
98
99 #[inline]
100 fn get_opcode(&self) -> Result<BhsOpcode> {
101 BhsOpcode::try_from(self.opcode.raw())
102 }
103
104 fn get_initiator_task_tag(&self) -> u32 {
105 self.initiator_task_tag.get()
106 }
107
108 #[inline]
109 fn get_ahs_length_bytes(&self) -> usize {
110 (self.total_ahs_length as usize) * 4
111 }
112
113 #[inline]
114 fn set_ahs_length_bytes(&mut self, len_bytes: u8) {
115 self.total_ahs_length = len_bytes >> 2;
116 }
117
118 #[inline]
119 fn get_data_length_bytes(&self) -> usize {
120 u32::from_be_bytes([
121 0,
122 self.data_segment_length[0],
123 self.data_segment_length[1],
124 self.data_segment_length[2],
125 ]) as usize
126 }
127
128 #[inline]
129 fn set_data_length_bytes(&mut self, len: u32) {
130 let be = len.to_be_bytes();
131 self.data_segment_length = [be[1], be[2], be[3]];
132 }
133}
134
135#[derive(Debug, Default)]
158pub struct ScsiDataOutBuilder {
159 pub header: ScsiDataOut,
160
161 enable_header_digest: bool,
162 enable_data_digest: bool,
163}
164
165impl ScsiDataOutBuilder {
166 pub const DEFAULT_TTT: u32 = 0xFFFF_FFFF;
168
169 pub fn new() -> Self {
171 Self {
172 header: ScsiDataOut {
173 opcode: {
174 let mut tmp = RawBhsOpcode::default();
175 tmp.set_opcode_known(Opcode::ScsiDataOut);
176 tmp
177 },
178 ..Default::default()
179 },
180 enable_header_digest: false,
181 enable_data_digest: false,
182 }
183 }
184
185 pub fn lun(mut self, lun: u64) -> Self {
187 self.header.lun.set(lun);
188 self
189 }
190
191 pub fn initiator_task_tag(mut self, itt: u32) -> Self {
193 self.header.initiator_task_tag.set(itt);
194 self
195 }
196
197 pub fn target_transfer_tag(mut self, ttt: u32) -> Self {
199 self.header.target_transfer_tag.set(ttt);
200 self
201 }
202
203 pub fn exp_stat_sn(mut self, sn: u32) -> Self {
205 self.header.exp_stat_sn.set(sn);
206 self
207 }
208
209 pub fn data_sn(mut self, data_sn: u32) -> Self {
211 self.header.data_sn.set(data_sn);
212 self
213 }
214
215 pub fn buffer_offset(mut self, buffer_offset: u32) -> Self {
217 self.header.buffer_offset.set(buffer_offset);
218 self
219 }
220
221 pub fn with_header_digest(mut self) -> Self {
223 self.enable_header_digest = true;
224 self
225 }
226
227 pub fn with_data_digest(mut self) -> Self {
229 self.enable_data_digest = true;
230 self
231 }
232}
233
234impl ZeroCopyType for ScsiDataOut {}