iscsi_client_rs/models/nop/
request.rs1use anyhow::{Result, bail};
8use tracing::{debug, warn};
9use zerocopy::{
10 BigEndian, FromBytes as ZFromBytes, Immutable, IntoBytes, KnownLayout, U32,
11};
12
13use crate::{
14 client::pdu_connection::FromBytes,
15 models::{
16 common::{
17 BasicHeaderSegment, HEADER_LEN, InitiatorTaskTag, LogicalUnitNumber,
18 SendingData, TargetTaskTag,
19 },
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 NopOutRequest {
29 pub opcode: RawBhsOpcode, reserved1: [u8; 3], 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], }
40
41impl NopOutRequest {
42 pub const DEFAULT_TAG: u32 = 0xffffffff_u32;
44
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 as zerocopy::FromBytes>::mut_from_bytes(buf)
58 .map_err(|e| anyhow::anyhow!("failed convert buffer NopOutRequest: {e}"))?;
59 if hdr.opcode.opcode_known() != Some(Opcode::NopOut) {
60 anyhow::bail!(
61 "NopOutRequest: invalid opcode 0x{:02x}",
62 hdr.opcode.opcode_raw()
63 );
64 }
65 Ok(hdr)
66 }
67}
68
69#[derive(Debug, Default)]
101pub struct NopOutRequestBuilder {
102 pub header: NopOutRequest,
103 want_header_digest: bool,
104 want_data_digest: bool,
105}
106
107impl NopOutRequestBuilder {
108 pub fn new() -> Self {
110 NopOutRequestBuilder {
111 header: NopOutRequest {
112 opcode: {
113 let mut tmp = RawBhsOpcode::default();
114 tmp.set_opcode_known(Opcode::NopOut);
115 tmp
116 },
117 reserved1: {
118 let mut tmp = [0; 3];
119 tmp[0] = 0b1000_0000;
120 tmp
121 },
122 ..Default::default()
123 },
124 want_data_digest: false,
125 want_header_digest: false,
126 }
127 }
128
129 pub fn immediate(mut self) -> Self {
131 self.header.opcode.set_i();
132 self
133 }
134
135 pub fn with_header_digest(mut self) -> Self {
137 self.want_header_digest = true;
138 self
139 }
140
141 pub fn with_data_digest(mut self) -> Self {
143 self.want_data_digest = true;
144 self
145 }
146
147 pub fn initiator_task_tag(mut self, tag: u32) -> Self {
149 self.header.initiator_task_tag.set(tag);
150 self
151 }
152
153 pub fn target_task_tag(mut self, tag: u32) -> Self {
155 self.header.target_task_tag.set(tag);
156 self
157 }
158
159 pub fn cmd_sn(mut self, sn: u32) -> Self {
161 self.header.cmd_sn.set(sn);
162 self
163 }
164
165 pub fn exp_stat_sn(mut self, sn: u32) -> Self {
167 self.header.exp_stat_sn.set(sn);
168 self
169 }
170
171 pub fn lun(mut self, lun: u64) -> Self {
173 self.header.lun.set(lun);
174 self
175 }
176}
177
178impl SendingData for NopOutRequest {
179 fn get_final_bit(&self) -> bool {
180 true
181 }
182
183 fn set_final_bit(&mut self) {
184 debug!("NopOut Request cannot be marked as Final")
185 }
186
187 fn get_continue_bit(&self) -> bool {
188 false
189 }
190
191 fn set_continue_bit(&mut self) {
192 warn!("NopOut Request cannot be marked as Contine");
193 }
194}
195
196impl FromBytes for NopOutRequest {
197 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
198 NopOutRequest::from_bhs_bytes(bytes)
199 }
200}
201
202impl BasicHeaderSegment for NopOutRequest {
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 NopOutRequest {}