iscsi_client_rs/models/data/
response.rs1use anyhow::{Result, anyhow, bail};
9use tracing::debug;
10use zerocopy::{
11 BigEndian, FromBytes as ZFromBytes, Immutable, IntoBytes, KnownLayout, U32,
12};
13
14use crate::{
15 client::pdu_connection::FromBytes,
16 models::{
17 command::{common::ScsiStatus, zero_copy::RawScsiStatus},
18 common::{
19 BasicHeaderSegment, HEADER_LEN, InitiatorTaskTag, LogicalUnitNumber,
20 SendingData,
21 },
22 data::common::RawDataInFlags,
23 data_fromat::ZeroCopyType,
24 opcode::{BhsOpcode, Opcode, RawBhsOpcode},
25 },
26};
27
28#[repr(C)]
31#[derive(Debug, Default, PartialEq, ZFromBytes, IntoBytes, KnownLayout, Immutable)]
32pub struct ScsiDataIn {
33 pub opcode: RawBhsOpcode, pub flags: RawDataInFlags, pub reserved2: u8, pub status_or_rsvd: RawScsiStatus, 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 stat_sn_or_rsvd: U32<BigEndian>, pub exp_cmd_sn: U32<BigEndian>, pub max_cmd_sn: U32<BigEndian>, pub data_sn: U32<BigEndian>, pub buffer_offset: U32<BigEndian>, pub residual_count: U32<BigEndian>, }
50
51impl ScsiDataIn {
52 #[inline]
54 pub fn scsi_status(&self) -> Option<ScsiStatus> {
55 if self.flags.s() {
56 self.status_or_rsvd.decode().ok()
57 } else {
58 None
59 }
60 }
61
62 #[inline]
64 pub fn residual_valid(&self) -> bool {
65 self.flags.u() || self.flags.o()
66 }
67
68 #[inline]
70 pub fn residual_effective(&self) -> u32 {
71 if self.residual_valid() {
72 self.residual_count.get()
73 } else {
74 0
75 }
76 }
77
78 #[inline]
80 pub fn set_scsi_status(&mut self, st: Option<ScsiStatus>) {
81 match st {
82 Some(s) => {
83 self.flags.set_s(true); self.flags.set_fin(true); self.status_or_rsvd.encode(s);
86 },
87 None => {
88 self.flags.set_s(false); self.status_or_rsvd.encode(ScsiStatus::Good);
90 self.stat_sn_or_rsvd.set(0);
91 self.residual_count.set(0);
92 },
93 }
94 }
95
96 #[inline]
98 pub fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
99 if buf.len() != HEADER_LEN {
100 bail!("buffer length must be {HEADER_LEN}, got {}", buf.len());
101 }
102 buf.copy_from_slice(self.as_bytes());
103 if !self.flags.s() {
104 buf[3] = 0; buf[24..28].fill(0); buf[44..48].fill(0); }
108 Ok(())
109 }
110
111 #[inline]
113 pub fn from_bhs_bytes(buf: &mut [u8]) -> Result<&mut Self> {
114 if buf.len() < HEADER_LEN {
115 return Err(anyhow!(
116 "buffer too small for SCSI Data-In BHS: {}",
117 buf.len()
118 ));
119 }
120 let hdr = Self::mut_from_bytes(buf)
121 .map_err(|_| anyhow!("SCSI Data-In: zerocopy prefix error"))?;
122 if hdr.opcode.opcode_known() != Some(Opcode::ScsiDataIn) {
124 bail!(
125 "ScsiDataIn invalid opcode 0x{:02x}",
126 hdr.opcode.opcode_raw()
127 );
128 }
129 hdr.flags.validate()?;
131 Ok(hdr)
132 }
133
134 #[inline]
136 pub fn get_real_final_bit(&self) -> bool {
137 self.flags.fin()
138 }
139
140 #[inline]
142 pub fn get_status_bit(&self) -> bool {
143 self.flags.s()
144 }
145}
146
147impl SendingData for ScsiDataIn {
148 fn get_final_bit(&self) -> bool {
149 let f = self.flags.fin();
153 let s = self.flags.s();
154 let is_final = f && s;
155 debug!(
156 "DataIn get_final_bit (channel): F={} S={} status={:?} => {}",
157 f,
158 s,
159 self.scsi_status(),
160 is_final
161 );
162 is_final
163 }
164
165 fn set_final_bit(&mut self) {
166 self.flags.set_fin(true);
167 }
168
169 fn get_continue_bit(&self) -> bool {
170 !self.flags.fin()
171 }
172
173 fn set_continue_bit(&mut self) {
174 self.flags.set_fin(false);
176 self.flags.set_s(false);
177 }
178}
179
180impl FromBytes for ScsiDataIn {
181 #[inline]
182 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
183 ScsiDataIn::from_bhs_bytes(bytes)
184 }
185}
186
187impl BasicHeaderSegment for ScsiDataIn {
188 #[inline]
189 fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
190 self.to_bhs_bytes(buf)
191 }
192
193 #[inline]
194 fn get_opcode(&self) -> Result<BhsOpcode> {
195 BhsOpcode::try_from(self.opcode.raw())
196 }
197
198 #[inline]
199 fn get_initiator_task_tag(&self) -> u32 {
200 self.initiator_task_tag.get()
201 }
202
203 #[inline]
204 fn get_ahs_length_bytes(&self) -> usize {
205 (self.total_ahs_length as usize) * 4
206 }
207
208 #[inline]
209 fn set_ahs_length_bytes(&mut self, len_bytes: u8) {
210 self.total_ahs_length = len_bytes >> 2;
211 }
212
213 #[inline]
214 fn get_data_length_bytes(&self) -> usize {
215 u32::from_be_bytes([
216 0,
217 self.data_segment_length[0],
218 self.data_segment_length[1],
219 self.data_segment_length[2],
220 ]) as usize
221 }
222
223 #[inline]
224 fn set_data_length_bytes(&mut self, len: u32) {
225 let be = len.to_be_bytes();
226 self.data_segment_length = [be[1], be[2], be[3]];
227 }
228}
229
230impl ZeroCopyType for ScsiDataIn {}