iscsi_client_rs/models/ready_2_transfer/
response.rs1use anyhow::{Result, bail};
9use tracing::warn;
10use zerocopy::{
11 BigEndian, FromBytes as ZFromBytes, Immutable, IntoBytes, KnownLayout, U32,
12};
13
14use crate::{
15 client::pdu_connection::FromBytes,
16 models::{
17 common::{
18 BasicHeaderSegment, HEADER_LEN, InitiatorTaskTag, LogicalUnitNumber,
19 SendingData,
20 },
21 data_fromat::ZeroCopyType,
22 opcode::{BhsOpcode, Opcode, RawBhsOpcode},
23 },
24};
25
26#[repr(C)]
28#[derive(Debug, Default, PartialEq, ZFromBytes, IntoBytes, KnownLayout, Immutable)]
29pub struct ReadyToTransfer {
30 pub opcode: RawBhsOpcode, pub reserved1: [u8; 3], 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: U32<BigEndian>, pub exp_cmd_sn: U32<BigEndian>, pub max_cmd_sn: U32<BigEndian>, pub r2t_sn: U32<BigEndian>, pub buffer_offset: U32<BigEndian>, pub desired_data_transfer_length: U32<BigEndian>, }
44
45impl ReadyToTransfer {
46 pub fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
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 ReadyToTransfer: {e}"))?;
59 if hdr.opcode.opcode_known() != Some(Opcode::ReadyToTransfer) {
60 anyhow::bail!(
61 "ReadyToTransfer: invalid opcode 0x{:02x}",
62 hdr.opcode.opcode_raw()
63 );
64 }
65 Ok(hdr)
66 }
67}
68
69impl SendingData for ReadyToTransfer {
70 fn get_final_bit(&self) -> bool {
71 true
72 }
73
74 fn set_final_bit(&mut self) {
75 warn!("R2T is header-only; Final flag in opcode byte is not used");
76 }
77
78 fn get_continue_bit(&self) -> bool {
79 false
80 }
81
82 fn set_continue_bit(&mut self) {
83 warn!("R2T cannot be marked as Continue");
84 }
85}
86
87impl FromBytes for ReadyToTransfer {
88 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
89 ReadyToTransfer::from_bhs_bytes(bytes)
90 }
91}
92
93impl BasicHeaderSegment for ReadyToTransfer {
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 #[inline]
105 fn get_initiator_task_tag(&self) -> u32 {
106 self.initiator_task_tag.get()
107 }
108
109 #[inline]
110 fn get_ahs_length_bytes(&self) -> usize {
111 (self.total_ahs_length as usize) * 4
112 }
113
114 #[inline]
115 fn set_ahs_length_bytes(&mut self, len: u8) {
116 self.total_ahs_length = len >> 2;
117 }
118
119 #[inline]
120 fn get_data_length_bytes(&self) -> usize {
121 u32::from_be_bytes([
122 0,
123 self.data_segment_length[0],
124 self.data_segment_length[1],
125 self.data_segment_length[2],
126 ]) as usize
127 }
128
129 #[inline]
130 fn set_data_length_bytes(&mut self, len: u32) {
131 let be = len.to_be_bytes();
132 self.data_segment_length = [be[1], be[2], be[3]];
133 }
134}
135
136impl ZeroCopyType for ReadyToTransfer {}