Skip to content

Commit 123155f

Browse files
committed
lib: Introduce NamespaceId::disposition() and NamespaceIdDisposition
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
1 parent ea3a4e3 commit 123155f

2 files changed

Lines changed: 137 additions & 94 deletions

File tree

src/lib.rs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,61 @@ pub enum NamespaceIdentifierType {
413413
Csi(nvme::CommandSetIdentifier),
414414
}
415415

416+
// Base v2.1, 3.2.1
417+
// Base v2.1, 3.2.1.5, Figure 71
418+
#[derive(Clone, Copy, Debug)]
419+
enum NamespaceIdDisposition<'a> {
420+
Invalid,
421+
Broadcast,
422+
Unallocated,
423+
Inactive(&'a Namespace),
424+
Active(&'a Namespace),
425+
}
426+
427+
// NSID
428+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
429+
pub struct NamespaceId(u32);
430+
431+
impl NamespaceId {
432+
fn disposition<'a>(&self, subsys: &'a Subsystem) -> NamespaceIdDisposition<'a> {
433+
if self.0 == 0 {
434+
return NamespaceIdDisposition::Invalid;
435+
}
436+
437+
if self.0 == u32::MAX {
438+
return NamespaceIdDisposition::Broadcast;
439+
}
440+
441+
assert!(subsys.nss.capacity() <= u32::MAX.try_into().unwrap());
442+
if self.0 > subsys.nss.capacity() as u32 {
443+
return NamespaceIdDisposition::Invalid;
444+
}
445+
446+
let Some(ns) = subsys.nss.iter().find(|nsid| self.0 == nsid.id.0) else {
447+
return NamespaceIdDisposition::Unallocated;
448+
};
449+
450+
if !subsys
451+
.ctlrs
452+
.iter()
453+
.flat_map(|c| c.active_ns.iter())
454+
.any(|&nsid| nsid.0 == self.0)
455+
{
456+
return NamespaceIdDisposition::Inactive(ns);
457+
}
458+
459+
NamespaceIdDisposition::Active(ns)
460+
}
461+
462+
fn max(subsys: &Subsystem) -> u32 {
463+
subsys
464+
.nss
465+
.capacity()
466+
.try_into()
467+
.expect("Too many namespaces")
468+
}
469+
}
470+
416471
#[derive(Debug)]
417472
pub struct Namespace {
418473
id: NamespaceId,
@@ -423,10 +478,6 @@ pub struct Namespace {
423478
nids: [NamespaceIdentifierType; 2],
424479
}
425480

426-
// NSID
427-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
428-
pub struct NamespaceId(u32);
429-
430481
impl Namespace {
431482
fn generate_uuid(seed: &[u8], nsid: NamespaceId) -> Uuid {
432483
let mut hasher = hmac::Hmac::<sha2::Sha256>::new_from_slice(seed).unwrap();

src/nvme/mi/dev.rs

Lines changed: 82 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use mctp::{AsyncRespChannel, MsgIC};
1010

1111
use crate::{
1212
CommandEffect, CommandEffectError, Controller, ControllerError, ControllerType, Discriminant,
13-
MAX_CONTROLLERS, MAX_NAMESPACES, NamespaceId, SubsystemError,
13+
MAX_CONTROLLERS, MAX_NAMESPACES, NamespaceId, NamespaceIdDisposition, SubsystemError,
1414
nvme::{
1515
AdminFormatNvmConfiguration, AdminGetLogPageLidRequestType,
1616
AdminGetLogPageSupportedLogPagesResponse, AdminIdentifyActiveNamespaceIdListResponse,
@@ -1242,59 +1242,43 @@ impl RequestHandler for AdminIdentifyRequest {
12421242

12431243
match &self.req {
12441244
AdminIdentifyCnsRequestType::NvmIdentifyNamespace => {
1245-
assert!(subsys.nss.len() <= u32::MAX.try_into().unwrap());
1246-
1247-
if self.nsid == u32::MAX {
1248-
let ainvminr = AdminIdentifyNvmIdentifyNamespaceResponse {
1249-
lbaf0_lbads: 9, // TODO: Tie to controller model
1250-
..Default::default()
1245+
let ainvminr = match NamespaceId(self.nsid).disposition(subsys) {
1246+
NamespaceIdDisposition::Invalid => {
1247+
debug!("Invalid NSID: {}", self.nsid);
1248+
Err(ResponseStatus::InvalidParameter)
12511249
}
1252-
.encode()?;
1253-
1254-
return admin_send_response_body(
1255-
resp,
1256-
admin_constrain_body(self.dofst, self.dlen, &ainvminr.0)?,
1257-
)
1258-
.await;
1259-
}
1260-
1261-
if self.nsid == 0 || self.nsid > subsys.nss.capacity() as u32 {
1262-
debug!("Invalid NSID: {}", self.nsid);
1263-
return Err(ResponseStatus::InvalidParameter);
1264-
}
1265-
1266-
let Some(ns) = subsys.nss.get(self.nsid as usize - 1) else {
1267-
debug!("Unallocated NSID: {}", self.nsid);
1268-
return Err(ResponseStatus::InvalidParameter);
1269-
};
1270-
1271-
// 4.1.5.1 NVM Command Set Spec, v1.0c
1272-
// TODO: Ensure the associated controller is an IO controller
1273-
// FIXME: Improve determination algo
1274-
let active = subsys
1275-
.ctlrs
1276-
.iter()
1277-
.flat_map(|c| c.active_ns.iter())
1278-
.any(|&nsid| nsid.0 == self.nsid);
1279-
let ainvminr = if active {
1280-
AdminIdentifyNvmIdentifyNamespaceResponse {
1281-
nsze: ns.size,
1282-
ncap: ns.capacity,
1283-
nuse: ns.used,
1284-
nsfeat: ((ns.size == ns.capacity) as u8),
1285-
nlbaf: 0,
1286-
flbas: 0,
1287-
mc: 0,
1288-
dpc: 0,
1289-
dps: 0,
1290-
nvmcap: 2_u128.pow(ns.block_order as u32) * ns.size as u128,
1291-
lbaf0: 0,
1292-
lbaf0_lbads: ns.block_order,
1293-
lbaf0_rp: 0,
1250+
NamespaceIdDisposition::Broadcast => {
1251+
Ok(AdminIdentifyNvmIdentifyNamespaceResponse {
1252+
lbaf0_lbads: 9, // TODO: Tie to controller model
1253+
..Default::default()
1254+
})
12941255
}
1295-
} else {
1296-
AdminIdentifyNvmIdentifyNamespaceResponse::default()
1297-
}
1256+
NamespaceIdDisposition::Unallocated => {
1257+
debug!("Unallocated NSID: {}", self.nsid);
1258+
Err(ResponseStatus::InvalidParameter)
1259+
}
1260+
NamespaceIdDisposition::Inactive(_) => {
1261+
Ok(AdminIdentifyNvmIdentifyNamespaceResponse::default())
1262+
}
1263+
// 4.1.5.1 NVM Command Set Spec, v1.0c
1264+
NamespaceIdDisposition::Active(ns) => {
1265+
Ok(AdminIdentifyNvmIdentifyNamespaceResponse {
1266+
nsze: ns.size,
1267+
ncap: ns.capacity,
1268+
nuse: ns.used,
1269+
nsfeat: ((ns.size == ns.capacity) as u8),
1270+
nlbaf: 0,
1271+
flbas: 0,
1272+
mc: 0,
1273+
dpc: 0,
1274+
dps: 0,
1275+
nvmcap: 2_u128.pow(ns.block_order as u32) * ns.size as u128,
1276+
lbaf0: 0,
1277+
lbaf0_lbads: ns.block_order,
1278+
lbaf0_rp: 0,
1279+
})
1280+
}
1281+
}?
12981282
.encode()?;
12991283

13001284
admin_send_response_body(
@@ -1358,11 +1342,7 @@ impl RequestHandler for AdminIdentifyRequest {
13581342
sqes: 0,
13591343
cqes: 0,
13601344
maxcmd: 0,
1361-
nn: subsys
1362-
.nss
1363-
.capacity()
1364-
.try_into()
1365-
.expect("Too many namespaces"),
1345+
nn: NamespaceId::max(subsys),
13661346
oncs: 0,
13671347
fuses: 0,
13681348
fna: ctlr.fna.into(),
@@ -1420,36 +1400,43 @@ impl RequestHandler for AdminIdentifyRequest {
14201400
}
14211401
AdminIdentifyCnsRequestType::NamespaceIdentificationDescriptorList => {
14221402
// 5.1.13.2.3, Base v2.1
1423-
if self.nsid >= u32::MAX - 1 {
1424-
debug!("Unacceptable NSID for Namespace Identification Descriptor List");
1425-
return Err(ResponseStatus::InvalidParameter);
1426-
}
1427-
1428-
if self.nsid == 0 || self.nsid > subsys.nss.capacity() as u32 {
1429-
debug!("Invalid NSID: {}", self.nsid);
1430-
return Err(ResponseStatus::InvalidParameter);
1431-
}
1432-
1433-
let Some(ns) = subsys.nss.get(self.nsid as usize - 1) else {
1434-
debug!("Unallocated NSID: {}", self.nsid);
1435-
return Err(ResponseStatus::InvalidParameter);
1436-
};
1437-
1438-
let ainsidlr = AdminIdentifyNamespaceIdentificationDescriptorListResponse {
1439-
nids: {
1440-
let mut vec = WireVec::new();
1441-
for nid in &ns.nids {
1442-
if vec
1443-
.push(Into::<NamespaceIdentifierType>::into(*nid))
1444-
.is_err()
1445-
{
1446-
debug!("Failed to push NID {nid:?}");
1447-
return Err(ResponseStatus::InternalError);
1448-
}
1403+
let ainsidlr = match NamespaceId(self.nsid).disposition(subsys) {
1404+
NamespaceIdDisposition::Invalid => {
1405+
if self.nsid == u32::MAX - 1 {
1406+
debug!(
1407+
"Unacceptable NSID for Namespace Identification Descriptor List"
1408+
);
1409+
} else {
1410+
debug!("Invalid NSID: {}", self.nsid);
14491411
}
1450-
vec
1451-
},
1452-
}
1412+
Err(ResponseStatus::InvalidParameter)
1413+
}
1414+
NamespaceIdDisposition::Broadcast => {
1415+
debug!("Invalid NSID: {}", self.nsid);
1416+
Err(ResponseStatus::InvalidParameter)
1417+
}
1418+
NamespaceIdDisposition::Unallocated => {
1419+
debug!("Unallocated NSID: {}", self.nsid);
1420+
Err(ResponseStatus::InvalidParameter)
1421+
}
1422+
NamespaceIdDisposition::Inactive(ns) | NamespaceIdDisposition::Active(ns) => {
1423+
Ok(AdminIdentifyNamespaceIdentificationDescriptorListResponse {
1424+
nids: {
1425+
let mut vec = WireVec::new();
1426+
for nid in &ns.nids {
1427+
if vec
1428+
.push(Into::<NamespaceIdentifierType>::into(*nid))
1429+
.is_err()
1430+
{
1431+
debug!("Failed to push NID {nid:?}");
1432+
return Err(ResponseStatus::InternalError);
1433+
}
1434+
}
1435+
vec
1436+
},
1437+
})
1438+
}
1439+
}?
14531440
.encode()?;
14541441

14551442
admin_send_response_body(
@@ -1465,13 +1452,18 @@ impl RequestHandler for AdminIdentifyRequest {
14651452
return Err(ResponseStatus::InvalidParameter);
14661453
}
14671454

1468-
assert!(subsys.nss.len() < 4096 / core::mem::size_of::<u32>());
1455+
assert!(NamespaceId::max(subsys) < (4096 / core::mem::size_of::<u32>()) as u32);
14691456
let aiansidl = AdminIdentifyAllocatedNamespaceIdListResponse {
14701457
nsid: {
1471-
let start = self.nsid + 1;
1472-
let end = subsys.nss.len() as u32;
1458+
let mut allocated: heapless::Vec<u32, MAX_NAMESPACES> = subsys
1459+
.nss
1460+
.iter()
1461+
.map(|ns| ns.id.0)
1462+
.filter(|nsid| *nsid > self.nsid)
1463+
.collect();
1464+
allocated.sort_unstable();
14731465
let mut vec = WireVec::new();
1474-
for nsid in start..=end {
1466+
for nsid in allocated {
14751467
if vec.push(nsid).is_err() {
14761468
debug!("Failed to insert NSID {nsid}");
14771469
return Err(ResponseStatus::InternalError);

0 commit comments

Comments
 (0)