iscsi_client_rs/models/text/
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, TargetTaskTag,
18 },
19 data_fromat::ZeroCopyType,
20 opcode::{BhsOpcode, Opcode, RawBhsOpcode},
21 text::common::RawStageFlags,
22 },
23};
24
25#[repr(C)]
27#[derive(Default, Debug, PartialEq, ZFromBytes, IntoBytes, KnownLayout, Immutable)]
28pub struct TextRequest {
29 pub opcode: RawBhsOpcode, pub flags: RawStageFlags, reserved1: [u8; 2], pub total_ahs_length: u8, pub data_segment_length: [u8; 3], pub lun: LogicalUnitNumber, pub initiator_task_tag: InitiatorTaskTag, pub target_task_tag: TargetTaskTag, pub cmd_sn: U32<BigEndian>, pub exp_stat_sn: U32<BigEndian>, reserved2: [u8; 16],
42}
43
44impl TextRequest {
45 pub const DEFAULT_TAG: u32 = 0xFFFF_FFFF;
47
48 pub fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
50 buf.fill(0);
51 if buf.len() != HEADER_LEN {
52 bail!("buffer length must be {HEADER_LEN}, got {}", buf.len());
53 }
54 buf.copy_from_slice(self.as_bytes());
55 Ok(())
56 }
57
58 pub fn from_bhs_bytes(buf: &mut [u8]) -> Result<&mut Self> {
60 let hdr = <Self as zerocopy::FromBytes>::mut_from_bytes(buf)
61 .map_err(|e| anyhow::anyhow!("failed convert buffer TextRequest: {e}"))?;
62 if hdr.opcode.opcode_known() != Some(Opcode::TextReq) {
63 anyhow::bail!(
64 "TextRequest: invalid opcode 0x{:02x}",
65 hdr.opcode.opcode_raw()
66 );
67 }
68 Ok(hdr)
69 }
70}
71
72#[derive(Debug, Default)]
97pub struct TextRequestBuilder {
98 pub header: TextRequest,
99 enable_header_digest: bool,
100 enable_data_digest: bool,
101}
102
103impl TextRequestBuilder {
104 pub fn new() -> Self {
106 TextRequestBuilder {
107 header: TextRequest {
108 opcode: {
109 let mut tmp = RawBhsOpcode::default();
110 tmp.set_opcode_known(Opcode::TextReq);
111 tmp
112 },
113 ..Default::default()
114 },
115 enable_data_digest: false,
116 enable_header_digest: false,
117 }
118 }
119
120 pub fn immediate(mut self) -> Self {
122 self.header.opcode.set_i();
123 self
124 }
125
126 pub fn with_header_digest(mut self) -> Self {
128 self.enable_header_digest = true;
129 self
130 }
131
132 pub fn with_data_digest(mut self) -> Self {
134 self.enable_data_digest = true;
135 self
136 }
137
138 pub fn initiator_task_tag(mut self, tag: u32) -> Self {
140 self.header.initiator_task_tag.set(tag);
141 self
142 }
143
144 pub fn target_task_tag(mut self, tag: u32) -> Self {
147 self.header.target_task_tag.set(tag);
148 self
149 }
150
151 pub fn cmd_sn(mut self, sn: u32) -> Self {
153 self.header.cmd_sn.set(sn);
154 self
155 }
156
157 pub fn exp_stat_sn(mut self, sn: u32) -> Self {
159 self.header.exp_stat_sn.set(sn);
160 self
161 }
162
163 pub fn lun(mut self, lun: u64) -> Self {
165 self.header.lun.set(lun);
166 self
167 }
168}
169
170impl SendingData for TextRequest {
171 fn get_final_bit(&self) -> bool {
172 self.flags.get_final_bit()
173 }
174
175 fn set_final_bit(&mut self) {
176 self.flags.set_final_bit();
178 if self.get_continue_bit() {
179 self.flags.set_continue_bit();
180 }
181 }
182
183 fn get_continue_bit(&self) -> bool {
184 self.flags.get_continue_bit()
185 }
186
187 fn set_continue_bit(&mut self) {
188 self.flags.set_continue_bit();
190 if self.get_final_bit() {
191 self.flags.set_final_bit();
192 }
193 }
194}
195
196impl FromBytes for TextRequest {
197 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
198 TextRequest::from_bhs_bytes(bytes)
199 }
200}
201
202impl BasicHeaderSegment for TextRequest {
203 #[inline]
204 fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
205 self.to_bhs_bytes(buf)
206 }
207
208 #[inline]
209 fn get_opcode(&self) -> Result<BhsOpcode> {
210 BhsOpcode::try_from(self.opcode.raw())
211 }
212
213 #[inline]
214 fn get_initiator_task_tag(&self) -> u32 {
215 self.initiator_task_tag.get()
216 }
217
218 #[inline]
219 fn get_ahs_length_bytes(&self) -> usize {
220 (self.total_ahs_length as usize) * 4
221 }
222
223 #[inline]
224 fn set_ahs_length_bytes(&mut self, len: u8) {
225 self.total_ahs_length = len >> 2;
226 }
227
228 #[inline]
229 fn get_data_length_bytes(&self) -> usize {
230 u32::from_be_bytes([
231 0,
232 self.data_segment_length[0],
233 self.data_segment_length[1],
234 self.data_segment_length[2],
235 ]) as usize
236 }
237
238 #[inline]
239 fn set_data_length_bytes(&mut self, len: u32) {
240 let be = len.to_be_bytes();
241 self.data_segment_length = [be[1], be[2], be[3]];
242 }
243}
244
245impl ZeroCopyType for TextRequest {}