Skip to content

Commit cc02d18

Browse files
committed
nvme: mi: dev: Implement Admin / Format NVM
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
1 parent 19973ba commit cc02d18

File tree

5 files changed

+460
-7
lines changed

5 files changed

+460
-7
lines changed

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ pub struct Controller {
294294
csts: FlagSet<nvme::ControllerStatusFlags>,
295295
lpa: FlagSet<LogPageAttributes>,
296296
lsaes: [FlagSet<LidSupportedAndEffectsFlags>; 130],
297+
fna: FlagSet<nvme::FormatNvmAttributes>,
297298
}
298299

299300
#[derive(Debug)]
@@ -334,6 +335,9 @@ impl Controller {
334335
LidSupportedAndEffectsFlags::Lsupp.into();
335336
arr
336337
},
338+
fna: (nvme::FormatNvmAttributes::Fns
339+
| nvme::FormatNvmAttributes::Sens
340+
| nvme::FormatNvmAttributes::Fnvmbs),
337341
}
338342
}
339343

src/nvme.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,54 @@ struct ControllerListRequest {
119119
ids: WireVec<u16, 2047>,
120120
}
121121

122+
// Base v2.1, 5.1.10, Figure 189, SES
123+
#[derive(Debug)]
124+
#[repr(u8)]
125+
enum SecureEraseSettings {
126+
NoOperation = 0b000,
127+
UserDataErase = 0b001,
128+
CryptographicErase = 0b010,
129+
}
130+
unsafe impl Discriminant<u8> for SecureEraseSettings {}
131+
132+
impl TryFrom<u32> for SecureEraseSettings {
133+
type Error = ();
134+
135+
fn try_from(value: u32) -> Result<Self, Self::Error> {
136+
match value {
137+
0b000 => Ok(Self::NoOperation),
138+
0b001 => Ok(Self::UserDataErase),
139+
0b010 => Ok(Self::CryptographicErase),
140+
_ => Err(()),
141+
}
142+
}
143+
}
144+
145+
// Base v2.1, 5.1.10, Figure 189
146+
#[derive(Debug)]
147+
#[expect(dead_code)]
148+
struct AdminFormatNvmConfiguration {
149+
lbafi: u8,
150+
mset: bool,
151+
pi: u8,
152+
pil: bool,
153+
ses: SecureEraseSettings,
154+
}
155+
156+
impl TryFrom<u32> for AdminFormatNvmConfiguration {
157+
type Error = ();
158+
159+
fn try_from(value: u32) -> Result<Self, Self::Error> {
160+
Ok(Self {
161+
lbafi: ((((value >> 12) & 0x3) << 4) | (value & 0xf)) as u8,
162+
mset: ((value >> 4) & 1) == 1,
163+
pi: ((value >> 5) & 0x3) as u8,
164+
pil: ((value >> 6) & 1) == 1,
165+
ses: TryFrom::try_from((value >> 9) & 0x7)?,
166+
})
167+
}
168+
}
169+
122170
// Base v2.1, 5.1.12, Figure 202
123171
// MI v2.0, 6.3, Figure 141
124172
#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
@@ -450,6 +498,16 @@ impl Default for SanitizeCapabilities {
450498
}
451499
}
452500

501+
// Base v2.1, 5.1.13.2.1, Figure 312, FNA
502+
flags! {
503+
pub enum FormatNvmAttributes: u8 {
504+
Fns,
505+
Sens,
506+
Cryes,
507+
Fnvmbs,
508+
}
509+
}
510+
453511
// Base v2.1, 5.1.13.2.1, Figure 312
454512
#[derive(Debug, DekuRead, DekuWrite)]
455513
#[deku(endian = "little")]
@@ -500,7 +558,7 @@ struct AdminIdentifyControllerResponse {
500558
nn: u32,
501559
oncs: u16,
502560
fuses: u16,
503-
fna: u8,
561+
fna: WireFlagSet<FormatNvmAttributes>,
504562
vwc: u8,
505563
awun: u16,
506564
awupf: u16,

src/nvme/mi.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,8 @@ enum AdminCommandRequestType {
765765
ControllerDataQueue = 0x45, // P
766766
DoorbellBufferConfig = 0x7c, // P
767767
FabricsCommands = 0x7f, // P
768+
#[deku(id = 0x80)]
769+
FormatNvm(AdminFormatNvmRequest),
768770
#[deku(id = 0x84)]
769771
Sanitize(AdminSanitizeRequest),
770772
LoadProgram = 0x85, // P
@@ -784,6 +786,20 @@ struct AdminCommandRequestHeader {
784786
op: AdminCommandRequestType,
785787
}
786788

789+
// MI v2.0, 6, Figure 136
790+
// Base v2.1, 5.1.10, Figure 189
791+
#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
792+
#[deku(ctx = "endian: Endian", endian = "endian")]
793+
struct AdminFormatNvmRequest {
794+
nsid: u32,
795+
#[deku(seek_from_current = "16")]
796+
dofst: u32,
797+
dlen: u32,
798+
#[deku(seek_from_current = "8")]
799+
#[deku(pad_bytes_after = "20")]
800+
config: u32,
801+
}
802+
787803
// MI v2.0, 6, Figure 136
788804
// Base v2.1, 5.1.12, Figures 197-201
789805
#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]

src/nvme/mi/dev.rs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ use crate::{
1212
CommandEffect, CommandEffectError, Controller, ControllerError, ControllerType, Discriminant,
1313
MAX_CONTROLLERS, MAX_NAMESPACES, NamespaceId, SubsystemError,
1414
nvme::{
15-
AdminGetLogPageLidRequestType, AdminGetLogPageSupportedLogPagesResponse,
16-
AdminIdentifyActiveNamespaceIdListResponse, AdminIdentifyAllocatedNamespaceIdListResponse,
17-
AdminIdentifyCnsRequestType, AdminIdentifyControllerResponse,
15+
AdminFormatNvmConfiguration, AdminGetLogPageLidRequestType,
16+
AdminGetLogPageSupportedLogPagesResponse, AdminIdentifyActiveNamespaceIdListResponse,
17+
AdminIdentifyAllocatedNamespaceIdListResponse, AdminIdentifyCnsRequestType,
18+
AdminIdentifyControllerResponse,
1819
AdminIdentifyNamespaceIdentificationDescriptorListResponse,
1920
AdminIdentifyNvmIdentifyNamespaceResponse, AdminIoCqeGenericCommandStatus,
2021
AdminIoCqeStatus, AdminIoCqeStatusType, AdminSanitizeConfiguration, ControllerListResponse,
@@ -23,8 +24,8 @@ use crate::{
2324
SanitizeStateInformation, SanitizeStatus, SanitizeStatusLogPageResponse,
2425
SmartHealthInformationLogPageResponse,
2526
mi::{
26-
AdminCommandRequestHeader, AdminCommandResponseHeader, AdminNamespaceAttachmentRequest,
27-
AdminNamespaceManagementRequest, AdminSanitizeRequest,
27+
AdminCommandRequestHeader, AdminCommandResponseHeader, AdminFormatNvmRequest,
28+
AdminNamespaceAttachmentRequest, AdminNamespaceManagementRequest, AdminSanitizeRequest,
2829
CompositeControllerStatusDataStructureResponse, CompositeControllerStatusFlagSet,
2930
ControllerFunctionAndReportingFlags, ControllerHealthDataStructure,
3031
ControllerHealthStatusPollResponse, ControllerInformationResponse,
@@ -810,6 +811,9 @@ impl RequestHandler for AdminCommandRequestHeader {
810811
AdminCommandRequestType::NamespaceManagement(req) => {
811812
req.handle(ctx, mep, subsys, rest, resp, app).await
812813
}
814+
AdminCommandRequestType::FormatNvm(req) => {
815+
req.handle(ctx, mep, subsys, rest, resp, app).await
816+
}
813817
AdminCommandRequestType::Sanitize(req) => {
814818
req.handle(ctx, mep, subsys, rest, resp, app).await
815819
}
@@ -1339,7 +1343,7 @@ impl RequestHandler for AdminIdentifyRequest {
13391343
.expect("Too many namespaces"),
13401344
oncs: 0,
13411345
fuses: 0,
1342-
fna: 0,
1346+
fna: ctlr.fna.into(),
13431347
vwc: 0,
13441348
awun: 0,
13451349
awupf: 0,
@@ -1813,6 +1817,53 @@ impl RequestHandler for AdminSanitizeRequest {
18131817
}
18141818
}
18151819

1820+
impl RequestHandler for AdminFormatNvmRequest {
1821+
type Ctx = AdminCommandRequestHeader;
1822+
1823+
async fn handle<A, C>(
1824+
&self,
1825+
ctx: &Self::Ctx,
1826+
_mep: &mut crate::ManagementEndpoint,
1827+
subsys: &mut crate::Subsystem,
1828+
rest: &[u8],
1829+
resp: &mut C,
1830+
_app: A,
1831+
) -> Result<(), ResponseStatus>
1832+
where
1833+
A: AsyncFnMut(CommandEffect) -> Result<(), CommandEffectError>,
1834+
C: AsyncRespChannel,
1835+
{
1836+
if !rest.is_empty() {
1837+
debug!("Invalid request size for Admin Format NVM");
1838+
return Err(ResponseStatus::InvalidCommandSize);
1839+
}
1840+
1841+
let Some(ctlr) = subsys.ctlrs.iter().find(|c| c.id.0 == ctx.ctlid) else {
1842+
debug!("Unrecognised CTLID: {}", ctx.ctlid);
1843+
return Err(ResponseStatus::InvalidParameter);
1844+
};
1845+
1846+
let Ok(config) = TryInto::<AdminFormatNvmConfiguration>::try_into(self.config) else {
1847+
debug!("Invalid configuration for Admin Format NVM");
1848+
return Err(ResponseStatus::InvalidParameter);
1849+
};
1850+
1851+
if config.lbafi != 0 {
1852+
debug!("Unsupported LBA format index: {}", config.lbafi);
1853+
return Err(ResponseStatus::InvalidParameter);
1854+
}
1855+
1856+
if !ctlr.active_ns.iter().any(|ns| ns.0 == self.nsid) && self.nsid != u32::MAX {
1857+
debug!("Unrecognised NSID: {}", self.nsid);
1858+
return Err(ResponseStatus::InvalidParameter);
1859+
}
1860+
1861+
// TODO: handle config.ses
1862+
1863+
admin_send_response_body(resp, &[]).await
1864+
}
1865+
}
1866+
18161867
impl crate::ManagementEndpoint {
18171868
fn update(&mut self, subsys: &crate::Subsystem) {
18181869
assert!(subsys.ctlrs.len() <= self.mecss.len());

0 commit comments

Comments
 (0)