1use super::IoQueueEntrySizes;
7use super::admin::AddNamespaceError;
8use super::admin::AdminConfig;
9use super::admin::AdminHandler;
10use super::admin::AdminState;
11use crate::queue::DoorbellMemory;
12use crate::queue::InvalidDoorbell;
13use disk_backend::Disk;
14use futures::FutureExt;
15use futures::StreamExt;
16use futures_concurrency::future::Race;
17use guestmem::GuestMemory;
18use guid::Guid;
19use inspect::Inspect;
20use inspect::InspectMut;
21use mesh::rpc::PendingRpc;
22use mesh::rpc::Rpc;
23use mesh::rpc::RpcSend;
24use pal_async::task::Spawn;
25use pal_async::task::Task;
26use parking_lot::Mutex;
27use parking_lot::RwLock;
28use std::future::pending;
29use std::sync::Arc;
30use task_control::TaskControl;
31use vmcore::interrupt::Interrupt;
32use vmcore::vm_task::VmTaskDriver;
33use vmcore::vm_task::VmTaskDriverSource;
34
35#[derive(InspectMut)]
36pub struct NvmeWorkers {
37 #[inspect(skip)]
38 _task: Task<()>,
39 #[inspect(flatten, send = "CoordinatorRequest::Inspect")]
40 send: mesh::Sender<CoordinatorRequest>,
41 #[inspect(skip)]
42 doorbells: Arc<RwLock<DoorbellMemory>>,
43 #[inspect(skip)]
44 state: EnableState,
45}
46
47#[derive(Debug)]
48enum EnableState {
49 Disabled,
50 Enabling(PendingRpc<()>),
51 Enabled,
52 Resetting(PendingRpc<()>),
53}
54
55impl NvmeWorkers {
56 pub fn new(
57 driver_source: &VmTaskDriverSource,
58 mem: GuestMemory,
59 interrupts: Vec<Interrupt>,
60 max_sqs: u16,
61 max_cqs: u16,
62 qe_sizes: Arc<Mutex<IoQueueEntrySizes>>,
63 subsystem_id: Guid,
64 ) -> Self {
65 let num_qids = 2 + max_sqs.max(max_cqs) * 2;
66 let doorbells = Arc::new(RwLock::new(DoorbellMemory::new(num_qids)));
67 let driver = driver_source.simple();
68 let handler: AdminHandler = AdminHandler::new(
69 driver.clone(),
70 AdminConfig {
71 driver_source: driver_source.clone(),
72 mem,
73 interrupts,
74 doorbells: doorbells.clone(),
75 subsystem_id,
76 max_sqs,
77 max_cqs,
78 qe_sizes,
79 },
80 );
81 let coordinator = Coordinator {
82 driver: driver.clone(),
83 admin: TaskControl::new(handler),
84 reset: None,
85 };
86 let (send, recv) = mesh::mpsc_channel();
87 let task = driver.spawn("nvme-coord", coordinator.run(recv));
88 Self {
89 _task: task,
90 send,
91 doorbells,
92 state: EnableState::Disabled,
93 }
94 }
95
96 pub fn client(&self) -> NvmeControllerClient {
97 NvmeControllerClient {
98 send: self.send.clone(),
99 }
100 }
101
102 pub fn doorbell(&self, db_id: u16, value: u32) {
103 if let Err(InvalidDoorbell) = self.doorbells.read().try_write(db_id, value) {
104 tracelimit::error_ratelimited!(db_id, "write to invalid doorbell index");
105 }
106 }
107
108 pub fn enable(&mut self, asq: u64, asqs: u16, acq: u64, acqs: u16) {
109 if let EnableState::Disabled = self.state {
110 self.state = EnableState::Enabling(self.send.call(
111 CoordinatorRequest::EnableAdmin,
112 EnableAdminParams {
113 asq,
114 asqs,
115 acq,
116 acqs,
117 },
118 ));
119 } else {
120 panic!("not disabled: {:?}", self.state);
121 }
122 }
123
124 pub fn poll_enabled(&mut self) -> bool {
125 if let EnableState::Enabling(recv) = &mut self.state {
126 if recv.now_or_never().is_some() {
127 self.state = EnableState::Enabled;
128 true
129 } else {
130 false
131 }
132 } else {
133 panic!("not enabling: {:?}", self.state)
134 }
135 }
136
137 pub fn controller_reset(&mut self) {
138 if let EnableState::Enabled = self.state {
139 self.state =
140 EnableState::Resetting(self.send.call(CoordinatorRequest::ControllerReset, ()));
141 } else {
142 panic!("not enabled: {:?}", self.state);
143 }
144 }
145
146 pub fn poll_controller_reset(&mut self) -> bool {
147 let Self {
148 _task: _,
149 send: _,
150 doorbells,
151 state,
152 } = self;
153 if let EnableState::Resetting(recv) = state {
154 if recv.now_or_never().is_some() {
155 *state = EnableState::Disabled;
156 doorbells.write().reset();
157 true
158 } else {
159 false
160 }
161 } else {
162 panic!("not resetting: {:?}", state)
163 }
164 }
165
166 pub async fn reset(&mut self) {
168 loop {
169 match &mut self.state {
170 EnableState::Disabled => break,
171 EnableState::Enabling(recv) => {
172 recv.await.unwrap();
173 self.state = EnableState::Enabled;
174 }
175 EnableState::Enabled => {
176 self.controller_reset();
177 }
178 EnableState::Resetting(recv) => {
179 recv.await.unwrap();
180 self.state = EnableState::Disabled;
181 }
182 }
183 }
184 self.doorbells.write().reset();
185 }
186}
187
188#[derive(Debug)]
190pub struct NvmeControllerClient {
191 send: mesh::Sender<CoordinatorRequest>,
192}
193
194impl NvmeControllerClient {
195 pub async fn add_namespace(&self, nsid: u32, disk: Disk) -> Result<(), AddNamespaceError> {
197 self.send
198 .call(CoordinatorRequest::AddNamespace, (nsid, disk))
199 .await
200 .unwrap()
201 }
202
203 pub async fn remove_namespace(&self, nsid: u32) -> bool {
205 self.send
206 .call(CoordinatorRequest::RemoveNamespace, nsid)
207 .await
208 .unwrap()
209 }
210}
211
212#[derive(Inspect)]
213struct Coordinator {
214 driver: VmTaskDriver,
215 #[inspect(flatten)]
216 admin: TaskControl<AdminHandler, AdminState>,
217 #[inspect(with = "Option::is_some")]
218 reset: Option<Rpc<(), ()>>,
219}
220
221enum CoordinatorRequest {
222 EnableAdmin(Rpc<EnableAdminParams, ()>),
223 AddNamespace(Rpc<(u32, Disk), Result<(), AddNamespaceError>>),
224 RemoveNamespace(Rpc<u32, bool>),
225 Inspect(inspect::Deferred),
226 ControllerReset(Rpc<(), ()>),
227}
228
229struct EnableAdminParams {
230 asq: u64,
231 asqs: u16,
232 acq: u64,
233 acqs: u16,
234}
235
236impl Coordinator {
237 async fn run(mut self, mut recv: mesh::Receiver<CoordinatorRequest>) {
238 loop {
239 enum Event {
240 Request(Option<CoordinatorRequest>),
241 ResetComplete,
242 }
243
244 let controller_reset = async {
245 if self.reset.is_some() {
246 self.admin.stop().await;
247 if let Some(state) = self.admin.state_mut() {
248 state.drain().await;
249 self.admin.remove();
250 }
251 } else {
252 pending().await
253 }
254 };
255
256 let event = (
257 recv.next().map(Event::Request),
258 controller_reset.map(|_| Event::ResetComplete),
259 )
260 .race()
261 .await;
262
263 match event {
264 Event::Request(Some(req)) => match req {
265 CoordinatorRequest::EnableAdmin(rpc) => rpc.handle_sync(
266 |EnableAdminParams {
267 asq,
268 asqs,
269 acq,
270 acqs,
271 }| {
272 if !self.admin.has_state() {
273 let state =
274 AdminState::new(self.admin.task(), asq, asqs, acq, acqs);
275 self.admin.insert(&self.driver, "nvme-admin", state);
276 self.admin.start();
277 } else {
278 tracelimit::warn_ratelimited!("duplicate attempt to enable admin");
279 }
280 },
281 ),
282 CoordinatorRequest::AddNamespace(rpc) => {
283 rpc.handle(async |(nsid, disk)| {
284 let running = self.admin.stop().await;
285 let (admin, state) = self.admin.get_mut();
286 let r = admin.add_namespace(state, nsid, disk).await;
287 if running {
288 self.admin.start();
289 }
290 r
291 })
292 .await
293 }
294 CoordinatorRequest::RemoveNamespace(rpc) => {
295 rpc.handle(async |nsid| {
296 let running = self.admin.stop().await;
297 let (admin, state) = self.admin.get_mut();
298 let r = admin.remove_namespace(state, nsid).await;
299 if running {
300 self.admin.start();
301 }
302 r
303 })
304 .await
305 }
306 CoordinatorRequest::ControllerReset(rpc) => {
307 assert!(self.reset.is_none());
308 self.reset = Some(rpc);
309 }
310 CoordinatorRequest::Inspect(req) => req.inspect(&self),
311 },
312 Event::Request(None) => break,
313 Event::ResetComplete => {
314 self.reset.take().unwrap().complete(());
315 }
316 }
317 }
318 }
319}