Skip to content

Commit f9fe53a

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

5 files changed

Lines changed: 490 additions & 82 deletions

File tree

src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ pub struct Controller {
299299
#[derive(Debug)]
300300
pub enum ControllerError {
301301
NamespaceAlreadyAttached,
302+
NamespaceNotAttached,
302303
NamespaceAttachmentLimitExceeded,
303304
}
304305

@@ -367,6 +368,22 @@ impl Controller {
367368

368369
Ok(())
369370
}
371+
372+
pub fn detach_namespace(&mut self, nsid: NamespaceId) -> Result<(), ControllerError> {
373+
debug!("Detaching NSID {} from CTRLID {}", nsid.0, self.id.0);
374+
let Some((idx, _)) = self
375+
.active_ns
376+
.iter()
377+
.enumerate()
378+
.find(|args| args.1.0 == nsid.0)
379+
else {
380+
return Err(ControllerError::NamespaceNotAttached);
381+
};
382+
383+
let _ = self.active_ns.swap_remove(idx);
384+
385+
Ok(())
386+
}
370387
}
371388

372389
#[derive(Debug)]

src/nvme.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,11 @@ impl ControllerListResponse {
471471

472472
// Base v2.1, 5.1.20.1, Figure 364, SEL
473473
#[derive(Debug, DekuRead, Eq, PartialEq)]
474-
#[deku(ctx = "endian: Endian, sel: u8", endian = "endian", id = "sel")]
474+
#[deku(ctx = "endian: Endian", endian = "endian", id_type = "u8")]
475475
#[repr(u8)]
476476
enum AdminNamespaceAttachmentSelect {
477-
#[deku(id = 0x00)]
478-
ControllerAttach(ControllerListRequest),
477+
ControllerAttach = 0x00,
478+
ControllerDetach = 0x01,
479479
}
480480

481481
// Base v2.1, 5.1.21, Figure 376, SEL

src/nvme/mi.rs

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

6-
use crate::nvme::{AdminNamespaceAttachmentSelect, AdminNamespaceManagementSelect};
6+
use crate::nvme::{
7+
AdminNamespaceAttachmentSelect, AdminNamespaceManagementSelect, ControllerListRequest,
8+
};
79
use crate::wire::{WireFlagSet, WireVec};
810
use crate::{CommandEffectError, Discriminant, Encode, MAX_CONTROLLERS};
911

@@ -857,10 +859,9 @@ struct AdminNamespaceAttachmentRequest {
857859
dofst: u32,
858860
dlen: u32,
859861
#[deku(seek_from_current = "8")]
860-
sel: u8, // NOTE: SEL is the bottom nibble
862+
sel: AdminNamespaceAttachmentSelect, // NOTE: SEL is the bottom nibble
861863
#[deku(seek_from_current = "23")]
862-
#[deku(ctx = "*sel")]
863-
req: AdminNamespaceAttachmentSelect,
864+
body: ControllerListRequest,
864865
}
865866

866867
// MI v2.0, 6, Figure 138

src/nvme/mi/dev.rs

Lines changed: 82 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use log::debug;
99
use mctp::{AsyncRespChannel, MsgIC};
1010

1111
use crate::{
12-
CommandEffect, CommandEffectError, ControllerError, ControllerType, Discriminant,
12+
CommandEffect, CommandEffectError, Controller, ControllerError, ControllerType, Discriminant,
1313
MAX_CONTROLLERS, MAX_NAMESPACES, NamespaceId, SubsystemError,
1414
nvme::{
1515
AdminGetLogPageLidRequestType, AdminGetLogPageSupportedLogPagesResponse,
@@ -1586,6 +1586,7 @@ impl RequestHandler for AdminNamespaceAttachmentRequest {
15861586
#[repr(u8)]
15871587
enum CommandSpecificStatus {
15881588
NamespaceAlreadyAttached = 0x18,
1589+
NamespaceNotAttached = 0x1a,
15891590
ControllerListInvalid = 0x1c,
15901591
NamespaceAttachmentLimitExceeded = 0x27,
15911592
}
@@ -1598,96 +1599,102 @@ impl RequestHandler for AdminNamespaceAttachmentRequest {
15981599
ControllerError::NamespaceAttachmentLimitExceeded => {
15991600
Self::NamespaceAttachmentLimitExceeded
16001601
}
1602+
ControllerError::NamespaceNotAttached => Self::NamespaceNotAttached,
16011603
}
16021604
}
16031605
}
16041606

1605-
match &self.req {
1606-
crate::nvme::AdminNamespaceAttachmentSelect::ControllerAttach(req) => {
1607-
// SAFETY: Protected in parsing by DekuError::InvalidParam
1608-
debug_assert!(req.numids <= 2047);
1607+
// SAFETY: Protected in parsing by DekuError::InvalidParam
1608+
debug_assert!(self.body.numids <= 2047);
16091609

1610-
let expected = (2047 - (req.numids as usize)) * core::mem::size_of::<u16>();
1611-
if rest.len() != expected {
1612-
debug!(
1613-
"Invalid request size for Admin Namespace Attachment: Found {}, expected {expected}",
1614-
rest.len()
1615-
);
1616-
return Err(ResponseStatus::InvalidCommandSize);
1617-
}
1618-
1619-
if self.nsid == u32::MAX {
1620-
debug!("Refusing to attach broadcast NSID");
1621-
return Err(ResponseStatus::InvalidParameter);
1622-
}
1623-
1624-
// TODO: Handle MAXCNA
1610+
let expected = (2047 - (self.body.numids as usize)) * core::mem::size_of::<u16>();
1611+
if rest.len() != expected {
1612+
debug!(
1613+
"Invalid request size for Admin Namespace Attachment: Found {}, expected {expected}",
1614+
rest.len()
1615+
);
1616+
return Err(ResponseStatus::InvalidCommandSize);
1617+
}
16251618

1626-
let mut status = AdminIoCqeStatusType::GenericCommandStatus(
1627-
AdminIoCqeGenericCommandStatus::SuccessfulCompletion,
1628-
);
1619+
if self.nsid == u32::MAX {
1620+
debug!("Refusing to perform {:?} for broadcast NSID", self.sel);
1621+
return Err(ResponseStatus::InvalidParameter);
1622+
}
16291623

1630-
for cid in &req.ids.0 {
1631-
let Some(ctlr) = subsys.ctlrs.get_mut(*cid as usize) else {
1632-
debug!("Unrecognised controller ID: {cid}");
1633-
status = AdminIoCqeStatusType::CommandSpecificStatus(
1634-
CommandSpecificStatus::ControllerListInvalid.id(),
1635-
);
1636-
break;
1637-
};
1624+
// TODO: Handle MAXCNA
16381625

1639-
// TODO: Allow addition of non-IO controllers
1640-
if ctlr.cntrltype != ControllerType::Io {
1641-
debug!(
1642-
"Require {:?} controller type, have {:?}",
1643-
ControllerType::Io,
1644-
ctlr.cntrltype
1645-
);
1646-
status = AdminIoCqeStatusType::CommandSpecificStatus(
1647-
CommandSpecificStatus::ControllerListInvalid.id(),
1648-
);
1649-
break;
1650-
}
1626+
let mut status = AdminIoCqeStatusType::GenericCommandStatus(
1627+
AdminIoCqeGenericCommandStatus::SuccessfulCompletion,
1628+
);
16511629

1652-
// TODO: Handle Namespace Is Private
1653-
// TODO: Handle I/O Command Set Not Supported
1654-
// TODO: Handle I/O Command Set Not Enabled
1630+
let action = match &self.sel {
1631+
crate::nvme::AdminNamespaceAttachmentSelect::ControllerAttach => {
1632+
|ctlr: &mut Controller, ns: NamespaceId| ctlr.attach_namespace(ns)
1633+
}
1634+
crate::nvme::AdminNamespaceAttachmentSelect::ControllerDetach => {
1635+
|ctlr: &mut Controller, ns: NamespaceId| ctlr.detach_namespace(ns)
1636+
}
1637+
};
16551638

1656-
// XXX: Should this be transactional? Two loops?
1657-
if let Err(err) = ctlr.attach_namespace(NamespaceId(self.nsid)) {
1658-
let err: CommandSpecificStatus = err.into();
1659-
status = AdminIoCqeStatusType::CommandSpecificStatus(err.id());
1660-
break;
1661-
}
1662-
}
1639+
for cid in &self.body.ids.0 {
1640+
let Some(ctlr) = subsys.ctlrs.get_mut(*cid as usize) else {
1641+
debug!("Unrecognised controller ID: {cid}");
1642+
status = AdminIoCqeStatusType::CommandSpecificStatus(
1643+
CommandSpecificStatus::ControllerListInvalid.id(),
1644+
);
1645+
break;
1646+
};
16631647

1664-
let mh = MessageHeader::respond(MessageType::NvmeAdminCommand).encode()?;
1648+
// TODO: Allow addition of non-IO controllers
1649+
if ctlr.cntrltype != ControllerType::Io {
1650+
debug!(
1651+
"Require {:?} controller type, have {:?}",
1652+
ControllerType::Io,
1653+
ctlr.cntrltype
1654+
);
1655+
status = AdminIoCqeStatusType::CommandSpecificStatus(
1656+
CommandSpecificStatus::ControllerListInvalid.id(),
1657+
);
1658+
break;
1659+
}
16651660

1666-
let acrh = AdminCommandResponseHeader {
1667-
status: ResponseStatus::Success,
1668-
cqedw0: self.nsid,
1669-
cqedw1: 0,
1670-
cqedw3: AdminIoCqeStatus {
1671-
cid: 0,
1672-
p: true,
1673-
status,
1674-
crd: crate::nvme::CommandRetryDelay::None,
1675-
m: false,
1676-
dnr: {
1677-
AdminIoCqeStatusType::GenericCommandStatus(
1678-
AdminIoCqeGenericCommandStatus::SuccessfulCompletion,
1679-
) != status
1680-
},
1681-
}
1682-
.into(),
1683-
}
1684-
.encode()?;
1661+
// TODO: Handle Namespace Is Private
1662+
// TODO: Handle I/O Command Set Not Supported
1663+
// TODO: Handle I/O Command Set Not Enabled
16851664

1686-
send_response(resp, &[&mh.0, &acrh.0]).await;
1665+
// XXX: Should this be transactional? Two loops?
1666+
if let Err(err) = action(ctlr, NamespaceId(self.nsid)) {
1667+
let err: CommandSpecificStatus = err.into();
1668+
status = AdminIoCqeStatusType::CommandSpecificStatus(err.id());
1669+
break;
1670+
}
1671+
}
16871672

1688-
Ok(())
1673+
let mh = MessageHeader::respond(MessageType::NvmeAdminCommand).encode()?;
1674+
1675+
let acrh = AdminCommandResponseHeader {
1676+
status: ResponseStatus::Success,
1677+
cqedw0: self.nsid,
1678+
cqedw1: 0,
1679+
cqedw3: AdminIoCqeStatus {
1680+
cid: 0,
1681+
p: true,
1682+
status,
1683+
crd: crate::nvme::CommandRetryDelay::None,
1684+
m: false,
1685+
dnr: {
1686+
AdminIoCqeStatusType::GenericCommandStatus(
1687+
AdminIoCqeGenericCommandStatus::SuccessfulCompletion,
1688+
) != status
1689+
},
16891690
}
1691+
.into(),
16901692
}
1693+
.encode()?;
1694+
1695+
send_response(resp, &[&mh.0, &acrh.0]).await;
1696+
1697+
Ok(())
16911698
}
16921699
}
16931700

0 commit comments

Comments
 (0)