Skip to content

Commit 46cc9d4

Browse files
committed
nvme: mi: dev: Implement Admin / Namespace Mangement / Delete
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
1 parent 3b3b35f commit 46cc9d4

4 files changed

Lines changed: 339 additions & 15 deletions

File tree

src/lib.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use deku::{DekuContainerWrite, DekuError};
88
use flagset::FlagSet;
99
use hmac::Mac;
10+
use log::debug;
1011
use mctp::AsyncRespChannel;
1112
use nvme::{
1213
AdminGetLogPageLidRequestType, LidSupportedAndEffectsFlags, LogPageAttributes,
@@ -365,6 +366,7 @@ pub enum NamespaceIdentifierType {
365366

366367
#[derive(Debug)]
367368
pub struct Namespace {
369+
id: NamespaceId,
368370
size: u64,
369371
capacity: u64,
370372
used: u64,
@@ -385,20 +387,26 @@ impl Namespace {
385387
uuid::Builder::from_random_bytes(digest).into_uuid()
386388
}
387389

388-
pub fn new(id: Uuid, capacity: u64) -> Self {
390+
pub fn new(nsid: NamespaceId, uuid: Uuid, capacity: u64) -> Self {
389391
Self {
392+
id: nsid,
390393
size: capacity,
391394
capacity,
392395
used: 0,
393396
block_order: 9,
394397
nids: [
395-
NamespaceIdentifierType::Nuuid(id),
398+
NamespaceIdentifierType::Nuuid(uuid),
396399
NamespaceIdentifierType::Csi(nvme::CommandSetIdentifier::Nvm),
397400
],
398401
}
399402
}
400403
}
401404

405+
#[derive(Debug, Eq, PartialEq)]
406+
pub enum SubsystemError {
407+
NamespaceIdentifierUnavailable,
408+
}
409+
402410
#[derive(Clone, Copy, Debug)]
403411
pub struct SubsystemInfo {
404412
pub pci_vid: u16,
@@ -480,6 +488,7 @@ pub struct Subsystem {
480488
caps: nvme::mi::SubsystemCapabilities,
481489
ports: heapless::Vec<Port, MAX_PORTS>,
482490
ctlrs: heapless::Vec<Controller, MAX_CONTROLLERS>,
491+
nsids: u32,
483492
nss: heapless::Vec<Namespace, MAX_NAMESPACES>,
484493
health: SubsystemHealth,
485494
mi: MiCapability,
@@ -495,6 +504,7 @@ impl Subsystem {
495504
caps: nvme::mi::SubsystemCapabilities::new(),
496505
ports: heapless::Vec::new(),
497506
ctlrs: heapless::Vec::new(),
507+
nsids: 0,
498508
nss: heapless::Vec::new(),
499509
health: SubsystemHealth::new(),
500510
mi: MiCapability::new(),
@@ -523,16 +533,33 @@ impl Subsystem {
523533
.expect("Invalid ControllerId provided")
524534
}
525535

526-
pub fn add_namespace(&mut self, capacity: u64) -> Result<NamespaceId, u8> {
527-
debug_assert!(self.nss.len() <= u32::MAX.try_into().unwrap());
528-
let nsid = NamespaceId((self.nss.len() + 1).try_into().unwrap());
536+
pub fn add_namespace(&mut self, capacity: u64) -> Result<NamespaceId, SubsystemError> {
537+
let Some(allocated) = self.nsids.checked_add(1) else {
538+
debug!("Implement allocation tracking with reuse");
539+
return Err(SubsystemError::NamespaceIdentifierUnavailable);
540+
};
541+
self.nsids = allocated;
542+
let nsid = NamespaceId(self.nsids);
529543
let ns = Namespace::new(
544+
nsid,
530545
Namespace::generate_uuid(&self.info.instance, nsid),
531546
capacity,
532547
);
533548
match self.nss.push(ns) {
534549
Ok(_) => Ok(nsid),
535-
Err(_) => Err(0x16), // Namespace Identifier Unavailable
550+
Err(_) => Err(SubsystemError::NamespaceIdentifierUnavailable),
536551
}
537552
}
553+
554+
pub fn remove_namespace(&mut self, nsid: NamespaceId) -> Result<(), SubsystemError> {
555+
if nsid.0 == u32::MAX {
556+
self.nss.clear();
557+
return Ok(());
558+
}
559+
let Some(e) = self.nss.iter().enumerate().find(|args| args.1.id == nsid) else {
560+
return Err(SubsystemError::NamespaceIdentifierUnavailable);
561+
};
562+
let _ = self.nss.swap_remove(e.0);
563+
Ok(())
564+
}
538565
}

src/nvme.rs

Lines changed: 10 additions & 3 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 => todo!(),
64+
AdminIoCqeStatusType::CommandSpecificStatus(s) => s.id(),
6565
AdminIoCqeStatusType::MediaAndDataIntegrityErrors => todo!(),
6666
AdminIoCqeStatusType::PathRelatedStatus => todo!(),
6767
AdminIoCqeStatusType::VendorSpecific => todo!(),
@@ -90,8 +90,7 @@ unsafe impl Discriminant<u8> for CommandRetryDelay {}
9090
#[repr(u8)]
9191
enum AdminIoCqeStatusType {
9292
GenericCommandStatus(AdminIoCqeGenericCommandStatus) = 0x00,
93-
#[expect(dead_code)]
94-
CommandSpecificStatus = 0x01,
93+
CommandSpecificStatus(AdminIoCqeCommandSpecificStatus) = 0x01,
9594
#[expect(dead_code)]
9695
MediaAndDataIntegrityErrors = 0x02,
9796
#[expect(dead_code)]
@@ -110,6 +109,14 @@ enum AdminIoCqeGenericCommandStatus {
110109
}
111110
unsafe impl Discriminant<u8> for AdminIoCqeGenericCommandStatus {}
112111

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,
117+
}
118+
unsafe impl Discriminant<u8> for AdminIoCqeCommandSpecificStatus {}
119+
113120
// Base v2.1, 5.1.12, Figure 202
114121
// MI v2.0, 6.3, Figure 141
115122
#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]

src/nvme/mi/dev.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ use log::debug;
99
use mctp::{AsyncRespChannel, MsgIC};
1010

1111
use crate::{
12-
CommandEffect, CommandEffectError, Discriminant, MAX_CONTROLLERS, MAX_NAMESPACES,
12+
CommandEffect, CommandEffectError, Discriminant, MAX_CONTROLLERS, MAX_NAMESPACES, NamespaceId,
13+
SubsystemError,
1314
nvme::{
1415
AdminGetLogPageLidRequestType, AdminGetLogPageSupportedLogPagesResponse,
1516
AdminIdentifyActiveNamespaceIdListResponse, AdminIdentifyAllocatedNamespaceIdListResponse,
1617
AdminIdentifyCnsRequestType, AdminIdentifyControllerResponse,
1718
AdminIdentifyNamespaceIdentificationDescriptorListResponse,
18-
AdminIdentifyNvmIdentifyNamespaceResponse, AdminIoCqeGenericCommandStatus,
19-
AdminIoCqeStatus, AdminIoCqeStatusType, ControllerListResponse,
20-
LidSupportedAndEffectsDataStructure, LidSupportedAndEffectsFlags, LogPageAttributes,
21-
NamespaceIdentifierType, SmartHealthInformationLogPageResponse,
19+
AdminIdentifyNvmIdentifyNamespaceResponse, AdminIoCqeCommandSpecificStatus,
20+
AdminIoCqeGenericCommandStatus, AdminIoCqeStatus, AdminIoCqeStatusType,
21+
ControllerListResponse, LidSupportedAndEffectsDataStructure, LidSupportedAndEffectsFlags,
22+
LogPageAttributes, NamespaceIdentifierType, SmartHealthInformationLogPageResponse,
2223
mi::{
2324
AdminCommandRequestHeader, AdminCommandResponseHeader, AdminNamespaceManagementRequest,
2425
CompositeControllerStatusDataStructureResponse, CompositeControllerStatusFlagSet,
@@ -1519,7 +1520,41 @@ impl RequestHandler for AdminNamespaceManagementRequest {
15191520

15201521
Ok(())
15211522
}
1522-
crate::nvme::mi::AdminNamespaceManagementSelect::Delete => todo!(),
1523+
crate::nvme::mi::AdminNamespaceManagementSelect::Delete => {
1524+
let res = subsys.remove_namespace(NamespaceId(self.nsid));
1525+
let status = match &res {
1526+
Ok(_) => AdminIoCqeStatusType::GenericCommandStatus(
1527+
AdminIoCqeGenericCommandStatus::SuccessfulCompletion,
1528+
),
1529+
Err(err) => {
1530+
assert_eq!(err, &SubsystemError::NamespaceIdentifierUnavailable);
1531+
AdminIoCqeStatusType::CommandSpecificStatus(
1532+
AdminIoCqeCommandSpecificStatus::NamespaceIdentifierUnavailable,
1533+
)
1534+
}
1535+
};
1536+
let mh = MessageHeader::respond(MessageType::NvmeAdminCommand).encode()?;
1537+
1538+
let acrh = AdminCommandResponseHeader {
1539+
status: ResponseStatus::Success,
1540+
cqedw0: self.nsid, // TODO: Base v2.1, 5.1.21 unclear, test against hardware
1541+
cqedw1: 0,
1542+
cqedw3: AdminIoCqeStatus {
1543+
cid: 0,
1544+
p: true,
1545+
status,
1546+
crd: crate::nvme::CommandRetryDelay::None,
1547+
m: false,
1548+
dnr: res.is_err(),
1549+
}
1550+
.into(),
1551+
}
1552+
.encode()?;
1553+
1554+
send_response(resp, &[&mh.0, &acrh.0]).await;
1555+
1556+
Ok(())
1557+
}
15231558
}
15241559
}
15251560
}

0 commit comments

Comments
 (0)