nvme_resources/
fault.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Fault definitions for NVMe fault controller.
5
6use mesh::Cell;
7use mesh::MeshPayload;
8use nvme_spec::Command;
9use nvme_spec::Completion;
10use std::time::Duration;
11
12/// Supported fault behaviour for NVMe queues
13#[derive(Debug, Clone, MeshPayload)]
14pub enum QueueFaultBehavior<T> {
15    /// Update the queue entry with the returned data
16    Update(T),
17    /// Drop the queue entry
18    Drop,
19    /// Delay
20    Delay(Duration),
21    /// Panic
22    Panic(String),
23    /// Update a completion payload
24    CustomPayload(Vec<u8>),
25}
26
27#[derive(Clone, MeshPayload)]
28/// Supported fault behaviour for PCI faults
29pub enum PciFaultBehavior {
30    /// Introduce a delay to the PCI operation
31    Delay(Duration),
32    /// Do nothing
33    Default,
34}
35
36#[derive(MeshPayload, Clone)]
37/// A buildable fault configuration for the controller management interface (cc.en(), csts.rdy(), ... )
38pub struct PciFaultConfig {
39    /// Fault to apply to cc.en() bit during enablement
40    pub controller_management_fault_enable: PciFaultBehavior,
41}
42
43#[derive(MeshPayload, Clone)]
44/// A buildable fault configuration
45pub struct AdminQueueFaultConfig {
46    /// A map of NVME opcodes to the submission fault behavior for each. (This would ideally be a `HashMap`, but `mesh` doesn't support that type. Given that this is not performance sensitive, the lookup is okay)
47    pub admin_submission_queue_faults: Vec<(CommandMatch, QueueFaultBehavior<Command>)>,
48    /// A map of NVME opcodes to the completion fault behavior for each.
49    pub admin_completion_queue_faults: Vec<(CommandMatch, QueueFaultBehavior<Completion>)>,
50}
51
52#[derive(Clone, MeshPayload, PartialEq)]
53/// A definition of a command matching pattern.
54pub struct CommandMatch {
55    /// Command to match against
56    pub command: Command,
57    /// Bitmask that defines the bits to match against
58    pub mask: [u8; 64],
59}
60
61#[derive(MeshPayload, Clone)]
62/// A simple fault configuration with admin submission queue support
63pub struct FaultConfiguration {
64    /// Fault active state
65    pub fault_active: Cell<bool>,
66    /// Fault to apply to the admin queues
67    pub admin_fault: AdminQueueFaultConfig,
68    /// Fault to apply to management layer of the controller
69    pub pci_fault: PciFaultConfig,
70}
71
72impl FaultConfiguration {
73    /// Create a new empty fault configuration
74    pub fn new(fault_active: Cell<bool>) -> Self {
75        Self {
76            fault_active,
77            admin_fault: AdminQueueFaultConfig::new(),
78            pci_fault: PciFaultConfig::new(),
79        }
80    }
81
82    /// Add a PCI fault configuration to the fault configuration
83    pub fn with_pci_fault(mut self, pci_fault: PciFaultConfig) -> Self {
84        self.pci_fault = pci_fault;
85        self
86    }
87
88    /// Add an admin queue fault configuration to the fault configuration
89    pub fn with_admin_queue_fault(mut self, admin_fault: AdminQueueFaultConfig) -> Self {
90        self.admin_fault = admin_fault;
91        self
92    }
93}
94
95impl PciFaultConfig {
96    /// Create a new no-op fault configuration
97    pub fn new() -> Self {
98        Self {
99            controller_management_fault_enable: PciFaultBehavior::Default,
100        }
101    }
102
103    /// Add a cc.en() fault
104    pub fn with_cc_enable_fault(mut self, behaviour: PciFaultBehavior) -> Self {
105        self.controller_management_fault_enable = behaviour;
106        self
107    }
108}
109
110impl AdminQueueFaultConfig {
111    /// Create an empty fault configuration
112    pub fn new() -> Self {
113        Self {
114            admin_submission_queue_faults: vec![],
115            admin_completion_queue_faults: vec![],
116        }
117    }
118
119    /// Add a [`CommandMatch`] -> [`QueueFaultBehavior`] mapping for the submission queue.
120    ///
121    /// # Panics
122    /// Panics if an identical [`CommandMatch`] has already been configured.
123    pub fn with_submission_queue_fault(
124        mut self,
125        pattern: CommandMatch,
126        behaviour: QueueFaultBehavior<Command>,
127    ) -> Self {
128        if self
129            .admin_submission_queue_faults
130            .iter()
131            .any(|(c, _)| (pattern == *c))
132        {
133            panic!(
134                "Duplicate submission queue fault for Compare {:?} and Mask {:?}",
135                pattern.command, pattern.mask
136            );
137        }
138
139        self.admin_submission_queue_faults
140            .push((pattern, behaviour));
141        self
142    }
143
144    /// Add a [`CommandMatch`] -> [`QueueFaultBehavior`] mapping for the completion queue.
145    ///
146    /// # Panics
147    /// Panics if an identical [`CommandMatch`] has already been configured.
148    pub fn with_completion_queue_fault(
149        mut self,
150        pattern: CommandMatch,
151        behaviour: QueueFaultBehavior<Completion>,
152    ) -> Self {
153        if self
154            .admin_completion_queue_faults
155            .iter()
156            .any(|(c, _)| (pattern == *c))
157        {
158            panic!(
159                "Duplicate completion queue fault for Compare {:?} and Mask {:?}",
160                pattern.command, pattern.mask
161            );
162        }
163
164        self.admin_completion_queue_faults
165            .push((pattern, behaviour));
166        self
167    }
168}