iscsi_client_rs/models/command/
zero_copy.rs1use core::fmt;
9
10use anyhow::{Result, bail};
11use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
12
13use crate::models::command::common::{
14 ResponseCode, ScsiCommandRequestFlags, ScsiCommandResponseFlags, ScsiStatus,
15 TaskAttribute, UnknownResponseCode, UnknownScsiStatus,
16};
17
18#[repr(transparent)]
21#[derive(Default, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
22pub struct RawTaskAttribute(u8);
23
24impl RawTaskAttribute {
25 const MASK: u8 = 0b0000_0111;
26
27 #[inline]
29 pub const fn raw(&self) -> u8 {
30 self.0 & Self::MASK
31 }
32
33 #[inline]
35 pub const fn new(bits3: u8) -> Self {
36 Self(bits3 & Self::MASK)
37 }
38
39 #[inline]
41 pub fn decode(&self) -> TaskAttribute {
42 match self.raw() {
43 0 => TaskAttribute::Untagged,
44 1 => TaskAttribute::Simple,
45 2 => TaskAttribute::Ordered,
46 3 => TaskAttribute::HeadOfQueue,
47 4 => TaskAttribute::ACA,
48 r @ 5..=7 => TaskAttribute::Reserved(r),
49 _ => TaskAttribute::Reserved(self.raw()),
51 }
52 }
53
54 #[inline]
56 pub fn encode(&mut self, attr: TaskAttribute) {
57 let v = match attr {
58 TaskAttribute::Untagged => 0,
59 TaskAttribute::Simple => 1,
60 TaskAttribute::Ordered => 2,
61 TaskAttribute::HeadOfQueue => 3,
62 TaskAttribute::ACA => 4,
63 TaskAttribute::Reserved(v) => v & Self::MASK,
64 };
65 self.0 = (self.0 & !Self::MASK) | v;
66 }
67}
68
69impl From<TaskAttribute> for RawTaskAttribute {
70 #[inline]
71 fn from(a: TaskAttribute) -> Self {
72 let mut r = RawTaskAttribute::default();
73 r.encode(a);
74 r
75 }
76}
77
78impl From<RawTaskAttribute> for TaskAttribute {
79 #[inline]
80 fn from(r: RawTaskAttribute) -> Self {
81 r.decode()
82 }
83}
84
85#[repr(transparent)]
87#[derive(Default, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
88pub struct RawScsiCmdReqFlags(u8);
89
90impl RawScsiCmdReqFlags {
91 pub const ATTR: u8 = 0x07;
93 pub const FINAL: u8 = 0x80;
95 pub const READ: u8 = 0x40;
97 pub const WRITE: u8 = 0x20;
99
100 #[inline]
102 pub const fn raw(&self) -> u8 {
103 self.0
104 }
105
106 #[inline]
108 pub const fn new_raw(v: u8) -> Self {
109 Self(v)
110 }
111
112 #[inline]
114 pub fn fin(&self) -> bool {
115 self.0 & Self::FINAL != 0
116 }
117
118 #[inline]
120 pub fn read(&self) -> bool {
121 self.0 & Self::READ != 0
122 }
123
124 #[inline]
126 pub fn write(&self) -> bool {
127 self.0 & Self::WRITE != 0
128 }
129
130 #[inline]
132 pub fn set_fin(&mut self, on: bool) {
133 self.set(Self::FINAL, on)
134 }
135
136 #[inline]
138 pub fn set_read(&mut self, on: bool) {
139 self.set(Self::READ, on)
140 }
141
142 #[inline]
144 pub fn set_write(&mut self, on: bool) {
145 self.set(Self::WRITE, on)
146 }
147
148 #[inline]
149 fn set(&mut self, bit: u8, on: bool) {
150 if on {
151 self.0 |= bit;
152 } else {
153 self.0 &= !bit;
154 }
155 }
156
157 #[inline]
159 pub fn task_attr(&self) -> TaskAttribute {
160 RawTaskAttribute::new(self.0 & Self::ATTR).decode()
161 }
162
163 #[inline]
165 pub fn set_task_attr(&mut self, attr: TaskAttribute) {
166 let ra = RawTaskAttribute::from(attr);
167 self.0 = (self.0 & !Self::ATTR) | ra.raw();
168 }
169}
170
171impl From<ScsiCommandRequestFlags> for RawScsiCmdReqFlags {
172 #[inline]
173 fn from(f: ScsiCommandRequestFlags) -> Self {
174 Self(f.bits())
175 }
176}
177impl TryFrom<RawScsiCmdReqFlags> for ScsiCommandRequestFlags {
178 type Error = anyhow::Error;
179
180 #[inline]
181 fn try_from(r: RawScsiCmdReqFlags) -> Result<Self> {
182 ScsiCommandRequestFlags::from_bits(r.raw()).ok_or_else(|| {
183 anyhow::anyhow!("invalid ScsiCommandRequestFlags: {:#010b}", r.raw())
184 })
185 }
186}
187
188#[repr(transparent)]
190#[derive(Default, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
191pub struct RawScsiCmdRespFlags(u8);
192
193impl RawScsiCmdRespFlags {
194 pub const FINAL: u8 = 0b1000_0000;
196 pub const O_BIG: u8 = 0b0000_0100;
198 pub const O_SMALL: u8 = 0b0001_0000;
200 pub const U_BIG: u8 = 0b0000_0010;
202 pub const U_SMALL: u8 = 0b0000_1000;
204
205 #[inline]
207 pub const fn raw(&self) -> u8 {
208 self.0
209 }
210
211 #[inline]
213 pub const fn new_raw(v: u8) -> Self {
214 Self(v)
215 }
216
217 #[inline]
219 pub fn fin(&self) -> bool {
220 self.0 & Self::FINAL != 0
221 }
222
223 #[inline]
225 pub fn o_small(&self) -> bool {
226 self.0 & Self::O_SMALL != 0
227 }
228
229 #[inline]
231 pub fn u_small(&self) -> bool {
232 self.0 & Self::U_SMALL != 0
233 }
234
235 #[inline]
237 pub fn o_big(&self) -> bool {
238 self.0 & Self::O_BIG != 0
239 }
240
241 #[inline]
243 pub fn u_big(&self) -> bool {
244 self.0 & Self::U_BIG != 0
245 }
246
247 #[inline]
249 pub fn set_fin(&mut self, on: bool) {
250 self.set(Self::FINAL, on)
251 }
252
253 #[inline]
255 pub fn set_o_small(&mut self, on: bool) {
256 self.set_pair(Self::O_SMALL, Self::U_SMALL, on)
257 }
258
259 #[inline]
261 pub fn set_u_small(&mut self, on: bool) {
262 self.set_pair(Self::U_SMALL, Self::O_SMALL, on)
263 }
264
265 #[inline]
267 pub fn set_o_big(&mut self, on: bool) {
268 self.set_pair(Self::O_BIG, Self::U_BIG, on)
269 }
270
271 #[inline]
273 pub fn set_u_big(&mut self, on: bool) {
274 self.set_pair(Self::U_BIG, Self::O_BIG, on)
275 }
276
277 #[inline]
278 fn set(&mut self, bit: u8, on: bool) {
279 if on {
280 self.0 |= bit;
281 } else {
282 self.0 &= !bit;
283 }
284 }
285
286 #[inline]
288 fn set_pair(&mut self, set_bit: u8, clear_bit: u8, on: bool) {
289 if on {
290 self.0 |= set_bit;
291 self.0 &= !clear_bit;
292 } else {
293 self.0 &= !set_bit;
294 }
295 }
296
297 #[inline]
299 pub fn validate(&self) -> Result<()> {
300 if (self.o_big() && self.u_big()) || (self.o_small() && self.u_small()) {
301 bail!("protocol error: both Underflow and Overflow bits set");
302 }
303 Ok(())
304 }
305}
306
307impl From<ScsiCommandResponseFlags> for RawScsiCmdRespFlags {
309 #[inline]
310 fn from(f: ScsiCommandResponseFlags) -> Self {
311 Self(f.bits())
312 }
313}
314impl TryFrom<RawScsiCmdRespFlags> for ScsiCommandResponseFlags {
315 type Error = anyhow::Error;
316
317 #[inline]
318 fn try_from(r: RawScsiCmdRespFlags) -> Result<Self> {
319 let f = ScsiCommandResponseFlags::from_bits(r.raw()).ok_or_else(|| {
320 anyhow::anyhow!("invalid ScsiCommandResponseFlags: {:#010b}", r.raw())
321 })?;
322 if (f.contains(ScsiCommandResponseFlags::U_BIG)
324 && f.contains(ScsiCommandResponseFlags::O_BIG))
325 || (f.contains(ScsiCommandResponseFlags::U_SMALL)
326 && f.contains(ScsiCommandResponseFlags::O_SMALL))
327 {
328 bail!("protocol error: both Underflow and Overflow bits set");
329 }
330 Ok(f)
331 }
332}
333
334#[repr(transparent)]
337#[derive(Default, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
338pub struct RawResponseCode(u8);
339
340impl RawResponseCode {
341 #[inline]
343 pub const fn raw(&self) -> u8 {
344 self.0
345 }
346
347 #[inline]
349 pub const fn new_raw(v: u8) -> Self {
350 Self(v)
351 }
352
353 #[inline]
355 pub fn decode(&self) -> Result<ResponseCode, UnknownResponseCode> {
356 match self.0 {
357 0x00 => Ok(ResponseCode::CommandCompleted),
358 0x01 => Ok(ResponseCode::TargetFailure),
359 0x80..=0xFF => Ok(ResponseCode::VendorSpecific(self.0)),
360 r @ 0x02..=0x7F => Ok(ResponseCode::Reserved(r)),
361 }
362 }
363
364 #[inline]
366 pub fn encode(&mut self, rc: ResponseCode) {
367 self.0 = match rc {
368 ResponseCode::CommandCompleted => 0x00,
369 ResponseCode::TargetFailure => 0x01,
370 ResponseCode::VendorSpecific(v) => v,
371 ResponseCode::Reserved(v) => v,
372 };
373 }
374}
375
376impl TryFrom<RawResponseCode> for ResponseCode {
377 type Error = UnknownResponseCode;
378
379 #[inline]
380 fn try_from(r: RawResponseCode) -> Result<Self, Self::Error> {
381 r.decode()
382 }
383}
384impl From<ResponseCode> for RawResponseCode {
385 #[inline]
386 fn from(rc: ResponseCode) -> Self {
387 let mut w = RawResponseCode::default();
388 w.encode(rc);
389 w
390 }
391}
392
393#[repr(transparent)]
396#[derive(Default, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
397pub struct RawScsiStatus(u8);
398
399impl RawScsiStatus {
400 #[inline]
402 pub const fn raw(&self) -> u8 {
403 self.0
404 }
405
406 #[inline]
408 pub const fn new_raw(v: u8) -> Self {
409 Self(v)
410 }
411
412 #[inline]
414 pub fn decode(&self) -> Result<ScsiStatus, UnknownScsiStatus> {
415 Ok(match self.0 {
416 0x00 => ScsiStatus::Good,
417 0x02 => ScsiStatus::CheckCondition,
418 0x08 => ScsiStatus::Busy,
419 0x18 => ScsiStatus::ReservationConflict,
420 0x28 => ScsiStatus::TaskSetFull,
421 0x30 => ScsiStatus::AcaActive,
422 0x40 => ScsiStatus::TaskAborted,
423 other => ScsiStatus::Other(other),
424 })
425 }
426
427 #[inline]
429 pub fn encode(&mut self, st: ScsiStatus) {
430 self.0 = match st {
431 ScsiStatus::Good => 0x00,
432 ScsiStatus::CheckCondition => 0x02,
433 ScsiStatus::Busy => 0x08,
434 ScsiStatus::ReservationConflict => 0x18,
435 ScsiStatus::TaskSetFull => 0x28,
436 ScsiStatus::AcaActive => 0x30,
437 ScsiStatus::TaskAborted => 0x40,
438 ScsiStatus::Other(v) => v,
439 };
440 }
441}
442
443impl TryFrom<RawScsiStatus> for ScsiStatus {
444 type Error = UnknownScsiStatus;
445
446 #[inline]
447 fn try_from(r: RawScsiStatus) -> Result<Self, Self::Error> {
448 r.decode()
449 }
450}
451impl From<ScsiStatus> for RawScsiStatus {
452 #[inline]
453 fn from(s: ScsiStatus) -> Self {
454 let mut w = RawScsiStatus::default();
455 w.encode(s);
456 w
457 }
458}
459
460impl fmt::Debug for RawTaskAttribute {
462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 write!(f, "RawTaskAttribute {{ {:?} }}", self.decode())
464 }
465}
466
467impl fmt::Debug for RawScsiCmdReqFlags {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 write!(f, "RawScsiCmdReqFlags {{ ")?;
471 if self.fin() {
472 write!(f, "FIN|")?;
473 }
474 if self.read() {
475 write!(f, "READ|")?;
476 }
477 if self.write() {
478 write!(f, "WRITE|")?;
479 }
480 write!(f, "ATTR={:?} }}", self.task_attr())
481 }
482}
483
484impl fmt::Debug for RawScsiCmdRespFlags {
486 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487 let valid = self.validate().is_ok();
488 write!(f, "RawScsiCmdRespFlags {{ ")?;
489 if self.fin() {
490 write!(f, "FIN|")?;
491 }
492 if self.o_small() {
493 write!(f, "O_SMALL|")?;
494 }
495 if self.u_small() {
496 write!(f, "U_SMALL|")?;
497 }
498 if self.o_big() {
499 write!(f, "O_BIG|")?;
500 }
501 if self.u_big() {
502 write!(f, "U_BIG|")?;
503 }
504 write!(f, "valid:{} }}", &valid)
505 }
506}
507
508impl fmt::Debug for RawResponseCode {
509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510 let decoded = match self.clone().decode() {
511 Ok(rc) => format!("{rc:?}"),
512 Err(_e) => format!("invalid(0x{:02X})", self.raw()),
513 };
514
515 f.debug_struct("RawResponseCode")
516 .field("decoded", &decoded)
517 .finish()
518 }
519}
520
521impl fmt::Debug for RawScsiStatus {
523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524 let decoded = match self.decode() {
525 Ok(st) => format!("{st:?}"),
526 Err(_e) => format!("invalid(0x{:02X})", self.raw()),
527 };
528
529 write!(f, "RawScsiStatus {{ {:?} }}", decoded)
530 }
531}