Skip to content

Commit 19973ba

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

5 files changed

Lines changed: 839 additions & 18 deletions

File tree

src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ pub struct Controller {
293293
cc: nvme::ControllerConfiguration,
294294
csts: FlagSet<nvme::ControllerStatusFlags>,
295295
lpa: FlagSet<LogPageAttributes>,
296-
lsaes: [FlagSet<LidSupportedAndEffectsFlags>; 19],
296+
lsaes: [FlagSet<LidSupportedAndEffectsFlags>; 130],
297297
}
298298

299299
#[derive(Debug)]
@@ -323,13 +323,15 @@ impl Controller {
323323
csts: FlagSet::empty(),
324324
lpa: FlagSet::empty(),
325325
lsaes: {
326-
let mut arr = [FlagSet::default(); 19];
326+
let mut arr = [FlagSet::default(); 130];
327327
arr[AdminGetLogPageLidRequestType::SupportedLogPages.id() as usize] =
328328
LidSupportedAndEffectsFlags::Lsupp.into();
329329
arr[AdminGetLogPageLidRequestType::SmartHealthInformation.id() as usize] =
330330
LidSupportedAndEffectsFlags::Lsupp.into();
331331
arr[AdminGetLogPageLidRequestType::FeatureIdentifiersSupportedAndEffects.id()
332332
as usize] = LidSupportedAndEffectsFlags::Lsupp.into();
333+
arr[AdminGetLogPageLidRequestType::SanitizeStatus.id() as usize] =
334+
LidSupportedAndEffectsFlags::Lsupp.into();
333335
arr
334336
},
335337
}
@@ -535,6 +537,10 @@ pub struct Subsystem {
535537
nsids: u32,
536538
nss: heapless::Vec<Namespace, MAX_NAMESPACES>,
537539
health: SubsystemHealth,
540+
sanicap: nvme::SanitizeCapabilities,
541+
ssi: nvme::SanitizeStateInformation,
542+
sstat: nvme::SanitizeStatus,
543+
sconf: Option<nvme::AdminSanitizeConfiguration>,
538544
mi: MiCapability,
539545
sn: &'static str,
540546
mn: &'static str,
@@ -555,6 +561,10 @@ impl Subsystem {
555561
sn: "1000",
556562
mn: "MIDEV",
557563
fr: "00.00.01",
564+
sstat: Default::default(),
565+
sconf: None,
566+
ssi: Default::default(),
567+
sanicap: Default::default(),
558568
}
559569
}
560570

src/nvme.rs

Lines changed: 196 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ pub enum AdminGetLogPageLidRequestType {
129129
ErrorInformation = 0x01,
130130
SmartHealthInformation = 0x02,
131131
FeatureIdentifiersSupportedAndEffects = 0x12,
132+
SanitizeStatus = 0x81,
132133
}
133-
unsafe impl Discriminant<u8> for AdminGetLogPageLidRequestType {}
134+
unsafe impl crate::Discriminant<u8> for AdminGetLogPageLidRequestType {}
134135

135136
// Base v2.1, 5.1.12.1.1, Figure 203
136137
#[derive(Debug, DekuRead, DekuWrite)]
@@ -234,6 +235,84 @@ flags! {
234235
}
235236
}
236237

238+
// Base v2.1, 5.1.12.1.33, Figure 291, SSTAT, SOS
239+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
240+
#[repr(u8)]
241+
pub enum SanitizeOperationStatus {
242+
#[default]
243+
SanitizeNeverStarted = 0b000,
244+
Sanitized = 0b001,
245+
Sanitizing = 0b010,
246+
SanitizeFailed = 0b011,
247+
SanitizedUnexpectedDeallocate = 0b100,
248+
}
249+
unsafe impl crate::Discriminant<u8> for SanitizeOperationStatus {}
250+
251+
// Base v2.1, 5.1.12.1.33, Figure 291, SSTAT
252+
#[derive(Clone, Copy, Debug, Default)]
253+
pub struct SanitizeStatus {
254+
sos: SanitizeOperationStatus,
255+
opc: u8,
256+
gde: bool,
257+
mvcncled: bool,
258+
}
259+
260+
impl From<SanitizeStatus> for u16 {
261+
fn from(value: SanitizeStatus) -> Self {
262+
((value.mvcncled as u16) << 9)
263+
| ((value.gde as u16) << 8)
264+
| ((value.opc & ((1 << 6) - 1)) << 3) as u16
265+
| value.sos.id() as u16
266+
}
267+
}
268+
269+
// Base v2.1, 5.12.1.33, Fgure 291, SSI, SANS
270+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
271+
#[repr(u8)]
272+
#[expect(dead_code)]
273+
enum SanitizeState {
274+
#[default]
275+
Idle = 0x00,
276+
RestrictedProcessing = 0x01,
277+
RestrictedFailure = 0x02,
278+
UnrestrictedProcessing = 0x03,
279+
UnrestrictedFailure = 0x04,
280+
MediaVerification = 0x05,
281+
PostVerificationDeallocation = 0x06,
282+
}
283+
unsafe impl crate::Discriminant<u8> for SanitizeState {}
284+
285+
// Base v2.1, 5.1.12.1.33, Figure 291, SSI
286+
#[derive(Clone, Copy, Debug, Default)]
287+
pub struct SanitizeStateInformation {
288+
sans: SanitizeState,
289+
fails: u8,
290+
}
291+
292+
impl From<SanitizeStateInformation> for u8 {
293+
fn from(value: SanitizeStateInformation) -> Self {
294+
(value.fails << 4) | (value.sans.id())
295+
}
296+
}
297+
298+
// Base v2.1, 5.1.12.1.33, Figure 291
299+
#[derive(Debug, DekuRead, DekuWrite)]
300+
#[deku(endian = "little")]
301+
struct SanitizeStatusLogPageResponse {
302+
sprog: u16,
303+
sstat: u16,
304+
scdw10: u32,
305+
eto: u32,
306+
etbe: u32,
307+
etce: u32,
308+
etodmm: u32,
309+
etbenmm: u32,
310+
etcenmm: u32,
311+
etpvds: u32,
312+
ssi: u8,
313+
}
314+
impl Encode<512> for SanitizeStatusLogPageResponse {}
315+
237316
// Base v2.1, 5.1.13.1, Figure 310
238317
#[derive(Clone, Copy, Debug, DekuRead, DekuWrite, Eq, PartialEq)]
239318
#[deku(ctx = "endian: Endian, cns: u8", id = "cns", endian = "endian")]
@@ -324,6 +403,53 @@ flags! {
324403
}
325404
}
326405

406+
// Base v2.1, 5.1.13.2.1, Figure 312, SANICAP, NODMMAS
407+
#[derive(Clone, Copy, Debug, Default)]
408+
#[repr(u8)]
409+
pub enum NoDeallocateModifiesMediaAfterSanitize {
410+
Undefined = 0b00,
411+
#[default]
412+
Unmodified = 0b01,
413+
Modified = 0b10,
414+
Reserved = 0b11,
415+
}
416+
unsafe impl Discriminant<u8> for NoDeallocateModifiesMediaAfterSanitize {}
417+
418+
// Base v2.1, 5.1.13.2.1, Figure 312, SANICAP
419+
#[derive(Clone, Copy, Debug)]
420+
pub struct SanitizeCapabilities {
421+
ces: bool,
422+
bes: bool,
423+
ows: bool,
424+
vers: bool,
425+
ndi: bool,
426+
nodmmas: NoDeallocateModifiesMediaAfterSanitize,
427+
}
428+
429+
impl From<SanitizeCapabilities> for u32 {
430+
fn from(value: SanitizeCapabilities) -> Self {
431+
(((value.nodmmas.id() & 0b11) as u32) << 30)
432+
| ((value.ndi as u32) << 29)
433+
| ((value.vers as u32) << 3)
434+
| ((value.ows as u32) << 2)
435+
| ((value.bes as u32) << 1)
436+
| (value.ces as u32)
437+
}
438+
}
439+
440+
impl Default for SanitizeCapabilities {
441+
fn default() -> Self {
442+
Self {
443+
ces: true,
444+
bes: true,
445+
ows: true,
446+
vers: false,
447+
ndi: true,
448+
nodmmas: NoDeallocateModifiesMediaAfterSanitize::Unmodified,
449+
}
450+
}
451+
}
452+
327453
// Base v2.1, 5.1.13.2.1, Figure 312
328454
#[derive(Debug, DekuRead, DekuWrite)]
329455
#[deku(endian = "little")]
@@ -363,7 +489,9 @@ struct AdminIdentifyControllerResponse {
363489
#[deku(seek_from_current = "49")]
364490
fwug: u8,
365491
kas: u16,
366-
#[deku(seek_from_current = "64")]
492+
#[deku(seek_from_current = "6")]
493+
sanicap: u32,
494+
#[deku(seek_from_current = "54")]
367495
cqt: u16,
368496
#[deku(seek_from_current = "124")]
369497
sqes: u8,
@@ -510,6 +638,72 @@ struct NvmNamespaceManagementCreate {
510638
lbstm: u64,
511639
}
512640

641+
// Base v2.1, 5.1.22, Figure 372, SANACT
642+
#[derive(Clone, Copy, Debug)]
643+
#[repr(u8)]
644+
enum SanitizeAction {
645+
Reserved = 0x00,
646+
ExitFailureMode = 0x01,
647+
StartBlockErase = 0x02,
648+
StartOverwrite = 0x03,
649+
StartCryptoErase = 0x04,
650+
ExitMediaVerificationState = 0x05,
651+
}
652+
unsafe impl Discriminant<u8> for SanitizeAction {}
653+
654+
impl TryFrom<u32> for SanitizeAction {
655+
type Error = ();
656+
657+
fn try_from(value: u32) -> Result<Self, Self::Error> {
658+
match value {
659+
0x00 => Ok(Self::Reserved),
660+
0x01 => Ok(Self::ExitFailureMode),
661+
0x02 => Ok(Self::StartBlockErase),
662+
0x03 => Ok(Self::StartOverwrite),
663+
0x04 => Ok(Self::StartCryptoErase),
664+
0x05 => Ok(Self::ExitMediaVerificationState),
665+
_ => Err(()),
666+
}
667+
}
668+
}
669+
670+
// Base v2.1, 5.1.22, Figure 372
671+
#[derive(Clone, Copy, Debug)]
672+
pub struct AdminSanitizeConfiguration {
673+
sanact: SanitizeAction,
674+
ause: bool,
675+
owpass: u8,
676+
oipbp: bool,
677+
ndas: bool,
678+
emvs: bool,
679+
}
680+
681+
impl TryFrom<u32> for AdminSanitizeConfiguration {
682+
type Error = ();
683+
684+
fn try_from(value: u32) -> Result<Self, Self::Error> {
685+
Ok(Self {
686+
sanact: TryInto::try_into(value & 0x7)?,
687+
ause: ((value >> 3) & 1) == 1,
688+
owpass: ((value >> 4) & 0xf) as u8,
689+
oipbp: ((value >> 8) & 1) == 1,
690+
ndas: ((value >> 9) & 1) == 1,
691+
emvs: ((value >> 10) & 1) == 1,
692+
})
693+
}
694+
}
695+
696+
impl From<AdminSanitizeConfiguration> for u32 {
697+
fn from(value: AdminSanitizeConfiguration) -> Self {
698+
((value.emvs as u32) << 10)
699+
| ((value.ndas as u32) << 9)
700+
| ((value.oipbp as u32) << 8)
701+
| (((value.owpass & 0xf) as u32) << 4)
702+
| ((value.ause as u32) << 3)
703+
| value.sanact.id() as u32
704+
}
705+
}
706+
513707
// Base v2.1, 5.1.25, Figure 385
514708
// Base v2.1, 3.1.3.6, Figure 32
515709
#[derive(Debug, DekuRead, DekuWrite)]

src/nvme/mi.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -765,9 +765,11 @@ enum AdminCommandRequestType {
765765
ControllerDataQueue = 0x45, // P
766766
DoorbellBufferConfig = 0x7c, // P
767767
FabricsCommands = 0x7f, // P
768-
LoadProgram = 0x85, // P
769-
ProgramActivationManagement = 0x88, // P
770-
MemoryRangeSetManagement = 0x89, // P
768+
#[deku(id = 0x84)]
769+
Sanitize(AdminSanitizeRequest),
770+
LoadProgram = 0x85, // P
771+
ProgramActivationManagement = 0x88, // P
772+
MemoryRangeSetManagement = 0x89, // P
771773
}
772774
unsafe impl Discriminant<u8> for AdminCommandRequestType {}
773775

@@ -864,6 +866,21 @@ struct AdminNamespaceAttachmentRequest {
864866
body: ControllerListRequest,
865867
}
866868

869+
// MI v2.0, 6, Figure 136
870+
// Base v2.1, 5.1.22, Figure 372
871+
#[derive(Debug, DekuRead, Eq, PartialEq)]
872+
#[deku(ctx = "endian: Endian", endian = "endian")]
873+
struct AdminSanitizeRequest {
874+
nsid: u32,
875+
#[deku(seek_from_current = "16")]
876+
dofst: u32,
877+
dlen: u32,
878+
#[deku(seek_from_current = "8")]
879+
config: u32,
880+
#[deku(pad_bytes_after = "16")]
881+
ovrpat: u32,
882+
}
883+
867884
// MI v2.0, 6, Figure 138
868885
#[derive(Debug, DekuRead, DekuWrite)]
869886
#[deku(endian = "little")]

0 commit comments

Comments
 (0)