Skip to content

Commit 463d15e

Browse files
committed
nvme: mi: dev: Implement Admin / Namespace Attachment / Controller Attach
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
1 parent 72c9255 commit 463d15e

6 files changed

Lines changed: 665 additions & 72 deletions

File tree

src/lib.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,19 @@ pub struct SecondaryController {
266266
id: ControllerId,
267267
}
268268

269+
#[derive(Debug, Clone, Copy, PartialEq)]
270+
enum ControllerType {
271+
Io,
272+
#[expect(dead_code)]
273+
Discovery,
274+
#[expect(dead_code)]
275+
Administrative,
276+
}
277+
269278
#[derive(Debug)]
270279
pub struct Controller {
271280
id: ControllerId,
281+
cntrltype: ControllerType,
272282
port: PortId,
273283
secondaries: heapless::Vec<SecondaryController, 0>,
274284
active_ns: heapless::Vec<NamespaceId, MAX_NAMESPACES>,
@@ -286,10 +296,17 @@ pub struct Controller {
286296
lsaes: [FlagSet<LidSupportedAndEffectsFlags>; 19],
287297
}
288298

299+
#[derive(Debug)]
300+
pub enum ControllerError {
301+
NamespaceAlreadyAttached,
302+
NamespaceAttachmentLimitExceeded,
303+
}
304+
289305
impl Controller {
290306
fn new(id: ControllerId, port: PortId) -> Self {
291307
Self {
292308
id,
309+
cntrltype: ControllerType::Io,
293310
port,
294311
secondaries: heapless::Vec::new(),
295312
active_ns: heapless::Vec::new(),
@@ -338,8 +355,17 @@ impl Controller {
338355
self.temp = k;
339356
}
340357

341-
pub fn attach_namespace(&mut self, nsid: NamespaceId) -> Result<(), NamespaceId> {
342-
self.active_ns.push(nsid)
358+
pub fn attach_namespace(&mut self, nsid: NamespaceId) -> Result<(), ControllerError> {
359+
debug!("Attaching NSID {} to CTLRID {}", nsid.0, self.id.0);
360+
if self.active_ns.iter().any(|ns| ns.0 == nsid.0) {
361+
return Err(ControllerError::NamespaceAlreadyAttached);
362+
}
363+
364+
if self.active_ns.push(nsid).is_err() {
365+
return Err(ControllerError::NamespaceAttachmentLimitExceeded);
366+
}
367+
368+
Ok(())
343369
}
344370
}
345371

@@ -404,6 +430,7 @@ impl Namespace {
404430

405431
#[derive(Debug, Eq, PartialEq)]
406432
pub enum SubsystemError {
433+
ControllerLimitExceeded,
407434
NamespaceIdentifierUnavailable,
408435
}
409436

@@ -520,11 +547,14 @@ impl Subsystem {
520547
self.ports.push(p).map(|_p| self.ports.last().unwrap().id)
521548
}
522549

523-
#[expect(clippy::result_large_err)]
524-
pub fn add_controller(&mut self, port: PortId) -> Result<ControllerId, Controller> {
550+
pub fn add_controller(&mut self, port: PortId) -> Result<ControllerId, SubsystemError> {
525551
debug_assert!(self.ctlrs.len() <= u16::MAX.into());
526-
let c = Controller::new(ControllerId(self.ctlrs.len() as u16), port);
527-
self.ctlrs.push(c).map(|_c| self.ctlrs.last().unwrap().id)
552+
let cid = ControllerId(self.ctlrs.len() as u16);
553+
let c = Controller::new(cid, port);
554+
self.ctlrs
555+
.push(c)
556+
.map_err(|_| SubsystemError::ControllerLimitExceeded)?;
557+
Ok(cid)
528558
}
529559

530560
pub fn controller_mut(&mut self, id: ControllerId) -> &mut Controller {

src/nvme.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl From<AdminIoCqeStatus> for u32 {
6161
debug_assert_eq!((sct & !7), 0);
6262
let sc: u32 = match value.status {
6363
AdminIoCqeStatusType::GenericCommandStatus(s) => s.id(),
64-
AdminIoCqeStatusType::CommandSpecificStatus(s) => s.id(),
64+
AdminIoCqeStatusType::CommandSpecificStatus(v) => v,
6565
AdminIoCqeStatusType::MediaAndDataIntegrityErrors => todo!(),
6666
AdminIoCqeStatusType::PathRelatedStatus => todo!(),
6767
AdminIoCqeStatusType::VendorSpecific => todo!(),
@@ -90,7 +90,7 @@ unsafe impl Discriminant<u8> for CommandRetryDelay {}
9090
#[repr(u8)]
9191
enum AdminIoCqeStatusType {
9292
GenericCommandStatus(AdminIoCqeGenericCommandStatus) = 0x00,
93-
CommandSpecificStatus(AdminIoCqeCommandSpecificStatus) = 0x01,
93+
CommandSpecificStatus(u8) = 0x01,
9494
#[expect(dead_code)]
9595
MediaAndDataIntegrityErrors = 0x02,
9696
#[expect(dead_code)]
@@ -109,13 +109,15 @@ enum AdminIoCqeGenericCommandStatus {
109109
}
110110
unsafe impl Discriminant<u8> for AdminIoCqeGenericCommandStatus {}
111111

112-
// Base v2.1, 4.2.3.2, Figure 103
113-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
114-
#[repr(u8)]
115-
enum AdminIoCqeCommandSpecificStatus {
116-
NamespaceIdentifierUnavailable = 0x16,
112+
// Base v2.1, 4.6.1, Figure 137
113+
// TODO: Unify with ControllerListResponse
114+
#[derive(Debug, DekuRead, Eq, PartialEq)]
115+
#[deku(ctx = "endian: Endian", endian = "little")]
116+
struct ControllerListRequest {
117+
numids: u16,
118+
#[deku(count = "*numids")]
119+
ids: WireVec<u16, 2047>,
117120
}
118-
unsafe impl Discriminant<u8> for AdminIoCqeCommandSpecificStatus {}
119121

120122
// Base v2.1, 5.1.12, Figure 202
121123
// MI v2.0, 6.3, Figure 141
@@ -298,6 +300,16 @@ enum ControllerType {
298300
AdministrativeController = 0x03,
299301
}
300302

303+
impl From<crate::ControllerType> for ControllerType {
304+
fn from(value: crate::ControllerType) -> Self {
305+
match value {
306+
crate::ControllerType::Io => Self::IoController,
307+
crate::ControllerType::Discovery => Self::DiscoveryController,
308+
crate::ControllerType::Administrative => Self::AdministrativeController,
309+
}
310+
}
311+
}
312+
301313
// Base v2.1, 5.1.13.2.1, Figure 312, LPA
302314
flags! {
303315
#[repr(u8)]
@@ -438,7 +450,7 @@ struct AdminIdentifyAllocatedNamespaceIdListResponse {
438450
impl Encode<4096> for AdminIdentifyAllocatedNamespaceIdListResponse {}
439451

440452
// Base v2.1, Section 5.1.13.2.12
441-
#[derive(Debug, DekuRead, DekuWrite)]
453+
#[derive(Debug, DekuWrite)]
442454
#[deku(endian = "little")]
443455
struct ControllerListResponse {
444456
#[deku(update = "self.ids.len()")]
@@ -457,6 +469,15 @@ impl ControllerListResponse {
457469
}
458470
}
459471

472+
// Base v2.1, 5.1.20.1, Figure 364, SEL
473+
#[derive(Debug, DekuRead, Eq, PartialEq)]
474+
#[deku(ctx = "endian: Endian, sel: u8", endian = "endian", id = "sel")]
475+
#[repr(u8)]
476+
enum AdminNamespaceAttachmentSelect {
477+
#[deku(id = 0x00)]
478+
ControllerAttach(ControllerListRequest),
479+
}
480+
460481
// Base v2.1, 5.1.21, Figure 376, SEL
461482
#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
462483
#[deku(ctx = "endian: Endian, sel: u8", endian = "endian", id = "sel")]

src/nvme/mi.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use deku::{DekuError, DekuRead, DekuWrite};
33
use flagset::{FlagSet, flags};
44
use log::debug;
55

6-
use crate::nvme::AdminNamespaceManagementSelect;
6+
use crate::nvme::{AdminNamespaceAttachmentSelect, AdminNamespaceManagementSelect};
77
use crate::wire::{WireFlagSet, WireVec};
88
use crate::{CommandEffectError, Discriminant, Encode, MAX_CONTROLLERS};
99

@@ -726,7 +726,8 @@ struct ControllerInformationResponse {
726726
impl Encode<32> for ControllerInformationResponse {}
727727

728728
// MI v2.0, 6, Figure 134
729-
#[derive(Debug, DekuRead, DekuWrite, PartialEq, Eq)]
729+
#[expect(clippy::large_enum_variant)] // FIXME
730+
#[derive(Debug, DekuRead, PartialEq, Eq)]
730731
#[deku(ctx = "endian: Endian, opcode: u8", id = "opcode", endian = "endian")]
731732
#[repr(u8)]
732733
enum AdminCommandRequestType {
@@ -743,6 +744,8 @@ enum AdminCommandRequestType {
743744
AsynchronousEventRequest = 0x0c, // P
744745
#[deku(id = 0x0d)]
745746
NamespaceManagement(AdminNamespaceManagementRequest),
747+
#[deku(id = 0x15)]
748+
NamespaceAttachement(AdminNamespaceAttachmentRequest),
746749
KeepAlive = 0x18, // P
747750
DirectiveSend = 0x19, // P
748751
DirectiveReceive = 0x1a, // P
@@ -767,14 +770,13 @@ enum AdminCommandRequestType {
767770
unsafe impl Discriminant<u8> for AdminCommandRequestType {}
768771

769772
// MI v2.0, 6, Figure 136
770-
#[derive(Debug, DekuRead, DekuWrite)]
773+
#[derive(Debug, DekuRead)]
771774
#[deku(endian = "little")]
772775
struct AdminCommandRequestHeader {
773-
#[deku(update = "self.op.id()")]
774-
opcode: u8,
776+
_opcode: u8,
775777
cflgs: u8,
776778
ctlid: u16,
777-
#[deku(ctx = "*opcode")]
779+
#[deku(ctx = "*_opcode")]
778780
op: AdminCommandRequestType,
779781
}
780782

@@ -845,6 +847,22 @@ struct AdminNamespaceManagementRequest {
845847
req: AdminNamespaceManagementSelect,
846848
}
847849

850+
// MI v2.0, 6, Figure 136
851+
// Base v2.1, 5.1.20, Figure 364
852+
#[derive(Debug, DekuRead, Eq, PartialEq)]
853+
#[deku(ctx = "endian: Endian", endian = "endian")]
854+
struct AdminNamespaceAttachmentRequest {
855+
nsid: u32,
856+
#[deku(seek_from_current = "16")]
857+
dofst: u32,
858+
dlen: u32,
859+
#[deku(seek_from_current = "8")]
860+
sel: u8, // NOTE: SEL is the bottom nibble
861+
#[deku(seek_from_current = "23")]
862+
#[deku(ctx = "*sel")]
863+
req: AdminNamespaceAttachmentSelect,
864+
}
865+
848866
// MI v2.0, 6, Figure 138
849867
#[derive(Debug, DekuRead, DekuWrite)]
850868
#[deku(endian = "little")]

0 commit comments

Comments
 (0)