1 /*++
2 Copyright (c) Microsoft. All rights reserved.
3 
4 Module Name:
5 
6     SelfManagedIoStateMachine.cpp
7 
8 Abstract:
9 
10     This module implements the self managed io state machine start / stop logic
11     in the framework.
12 
13 Author:
14 
15 
16 
17 Environment:
18     Both kernel and user mode
19 
20 Revision History:
21 
22 
23 
24 --*/
25 
26 #include "pnppriv.hpp"
27 
28 extern "C" {
29 #if defined(EVENT_TRACING)
30 #include "SelfManagedIoStateMachine.tmh"
31 #endif
32 }
33 
34 // * - We can get a restart from the created state if a PDO is newly enumerated
35 //     but was disabled on a previous enumeration.  Treat restart as an init
36 //     in this case.
37 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_CreatedStates[] =
38 {
39     { SelfManagedIoEventStart, FxSelfManagedIoInit DEBUGGED_EVENT },
40     { SelfManagedIoEventFlush, FxSelfManagedIoCreated DEBUGGED_EVENT },
41     { SelfManagedIoEventCleanup, FxSelfManagedIoFinal DEBUGGED_EVENT },
42 };
43 
44 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_InitFailedStates[] =
45 {
46     { SelfManagedIoEventSuspend, FxSelfManagedIoInitFailed DEBUGGED_EVENT },
47     { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
48 };
49 
50 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StartedStates[] =
51 {
52     { SelfManagedIoEventSuspend, FxSelfManagedIoSuspending DEBUGGED_EVENT },
53 };
54 
55 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StoppedStates[] =
56 {
57     { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT },
58     { SelfManagedIoEventSuspend, FxSelfManagedIoStopped DEBUGGED_EVENT },
59     { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
60 };
61 
62 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FailedStates[] =
63 {
64     { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT },
65     { SelfManagedIoEventSuspend, FxSelfManagedIoFailed DEBUGGED_EVENT },
66 };
67 
68 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FlushedStates[] =
69 {
70     { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT },
71     { SelfManagedIoEventCleanup, FxSelfManagedIoCleanup DEBUGGED_EVENT },
72     { SelfManagedIoEventFlush, FxSelfManagedIoFlushed TRAP_ON_EVENT },
73 };
74 
75 const FxSelfManagedIoStateTable FxSelfManagedIoMachine::m_StateTable[] =
76 {
77     // FxSelfManagedIoCreated
78     {   NULL,
79         FxSelfManagedIoMachine::m_CreatedStates,
80         ARRAY_SIZE(FxSelfManagedIoMachine::m_CreatedStates),
81     },
82 
83     // FxSelfManagedIoInit
84     {   FxSelfManagedIoMachine::Init,
85         NULL,
86         0,
87     },
88 
89     // FxSelfManagedIoInitFailed
90     {   NULL,
91         FxSelfManagedIoMachine::m_InitFailedStates,
92         ARRAY_SIZE(FxSelfManagedIoMachine::m_InitFailedStates),
93     },
94 
95     // FxSelfManagedIoStarted
96     {   NULL,
97         FxSelfManagedIoMachine::m_StartedStates,
98         ARRAY_SIZE(FxSelfManagedIoMachine::m_StartedStates),
99     },
100 
101     // FxSelfManagedIoSuspending
102     {   FxSelfManagedIoMachine::Suspending,
103         NULL,
104         0,
105     },
106 
107     // FxSelfManagedIoStopped
108     {   NULL,
109         FxSelfManagedIoMachine::m_StoppedStates,
110         ARRAY_SIZE(FxSelfManagedIoMachine::m_StoppedStates),
111     },
112 
113     // FxSelfManagedIoRestarting
114     {   FxSelfManagedIoMachine::Restarting,
115         NULL,
116         0,
117     },
118 
119     // FxSelfManagedIoFailed
120     {   NULL,
121         FxSelfManagedIoMachine::m_FailedStates,
122         ARRAY_SIZE(FxSelfManagedIoMachine::m_FailedStates),
123     },
124 
125     // FxSelfManagedIoFlushing
126     {   FxSelfManagedIoMachine::Flushing,
127         NULL,
128         0,
129     },
130 
131     // FxSelfManagedIoFlushed
132     {   NULL,
133         FxSelfManagedIoMachine::m_FlushedStates,
134         ARRAY_SIZE(FxSelfManagedIoMachine::m_FlushedStates),
135     },
136 
137     // FxSelfManagedIoCleanup
138     {   FxSelfManagedIoMachine::Cleanup,
139         NULL,
140         0,
141     },
142 
143     // FxSelfManagedIoFinal
144     {   NULL,
145         NULL,
146         0,
147     },
148 };
149 
150 FxSelfManagedIoMachine::FxSelfManagedIoMachine(
151     __in FxPkgPnp* PkgPnp
152     )
153 {
154     m_PkgPnp = PkgPnp;
155 
156     m_EventHistoryIndex = 0;
157     m_StateHistoryIndex = 0;
158 
159     m_CurrentState = FxSelfManagedIoCreated;
160 
161     RtlZeroMemory(&m_Events, sizeof(m_Events));
162     RtlZeroMemory(&m_States, sizeof(m_States));
163 
164     //
165     // Make sure we can fit the state into a byte
166     //
167     ASSERT(FxSelfManagedIoMax <= 0xFF);
168 }
169 
170 NTSTATUS
171 FxSelfManagedIoMachine::_CreateAndInit(
172     __deref_out FxSelfManagedIoMachine** SelfManagedIoMachine,
173     __in FxPkgPnp* PkgPnp
174     )
175 {
176     NTSTATUS status;
177     FxSelfManagedIoMachine * selfManagedIoMachine;
178 
179     *SelfManagedIoMachine = NULL;
180 
181     selfManagedIoMachine = new (PkgPnp->GetDriverGlobals()) FxSelfManagedIoMachine(
182         PkgPnp
183         );
184 
185     if (selfManagedIoMachine == NULL) {
186         DoTraceLevelMessage(
187             PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
188             "Self managed I/O state machine allocation failed for "
189             "WDFDEVICE 0x%p",
190             PkgPnp->GetDevice()->GetHandle());
191 
192         return STATUS_INSUFFICIENT_RESOURCES;
193     }
194 
195     status = selfManagedIoMachine->m_StateMachineLock.Initialize();
196     if (!NT_SUCCESS(status)) {
197         DoTraceLevelMessage(
198             PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
199             "Self managed I/O state machine lock initialization failed for "
200             "WDFDEVICE 0x%p, %!STATUS!",
201             PkgPnp->GetDevice()->GetHandle(),
202             status);
203 
204         delete selfManagedIoMachine;
205 
206         return status;
207     }
208 
209     *SelfManagedIoMachine = selfManagedIoMachine;
210 
211     return status;
212 }
213 
214 
215 VOID
216 FxSelfManagedIoMachine::InitializeMachine(
217     __in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks
218     )
219 /*++
220 
221 Routine Description:
222     Sets all the function event callbacks.
223 
224 Arguments:
225     Callbacks - list of callbacks to set
226 
227 Return Value:
228     None
229 
230   --*/
231 {
232     m_DeviceSelfManagedIoCleanup.m_Method = Callbacks->EvtDeviceSelfManagedIoCleanup;
233     m_DeviceSelfManagedIoFlush.m_Method = Callbacks->EvtDeviceSelfManagedIoFlush;
234     m_DeviceSelfManagedIoInit.m_Method    = Callbacks->EvtDeviceSelfManagedIoInit;
235     m_DeviceSelfManagedIoSuspend.m_Method = Callbacks->EvtDeviceSelfManagedIoSuspend;
236     m_DeviceSelfManagedIoRestart.m_Method = Callbacks->EvtDeviceSelfManagedIoRestart;
237 }
238 
239 WDFDEVICE
240 FxSelfManagedIoMachine::GetDeviceHandle(
241     VOID
242     )
243 {
244     return m_PkgPnp->GetDevice()->GetHandle();
245 }
246 
247 _Must_inspect_result_
248 NTSTATUS
249 FxSelfManagedIoMachine::ProcessEvent(
250     __in FxSelfManagedIoEvents Event
251     )
252 /*++
253 
254 Routine Description:
255     Processes an event and runs it through the state machine.  Unlike other
256     state machines in the framework, this one acquires lock in the event
257     processing function rather then relying on the caller to do so.
258 
259 Arguments:
260     Event - The event to feed into the state machine.
261 
262 Return Value:
263     result of the event
264 
265   --*/
266 {
267     const FxSelfManagedIoStateTable* entry;
268     FxSelfManagedIoStates newState;
269     NTSTATUS status;
270 
271     m_StateMachineLock.AcquireLock(m_PkgPnp->GetDriverGlobals());
272 
273     m_Events.History[m_EventHistoryIndex] = (UCHAR) Event;
274     m_EventHistoryIndex = (m_EventHistoryIndex + 1) %
275                           (sizeof(m_Events.History)/sizeof(m_Events.History[0]));
276 
277     entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated];
278     newState = FxSelfManagedIoMax;
279 
280     for (ULONG i = 0; i < entry->TargetStatesCount; i++) {
281         if (entry->TargetStates[i].SelfManagedIoEvent == Event) {
282             DO_EVENT_TRAP(&entry->TargetStates[i]);
283             newState = entry->TargetStates[i].SelfManagedIoState;
284             break;
285         }
286     }
287 
288     if (newState == FxSelfManagedIoMax) {
289         //
290         // We always can handle io increment/decrement from any state, but we
291         // should not be dropping any other events from this state.
292         //
293 
294         COVERAGE_TRAP();
295     }
296 
297     status = STATUS_SUCCESS;
298 
299     while (newState != FxSelfManagedIoMax) {
300         DoTraceLevelMessage(
301             m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
302             "WDFDEVICE 0x%p !devobj 0x%p entering self managed io state "
303             "%!FxSelfManagedIoStates! from %!FxSelfManagedIoStates!",
304             m_PkgPnp->GetDevice()->GetHandle(),
305             m_PkgPnp->GetDevice()->GetDeviceObject(),
306             newState, m_CurrentState);
307 
308         m_States.History[m_StateHistoryIndex] = (UCHAR) newState;
309         m_StateHistoryIndex = (m_StateHistoryIndex + 1) %
310                               (sizeof(m_States.History)/sizeof(m_States.History[0]));
311 
312         m_CurrentState = (BYTE) newState;
313         entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated];
314 
315         if (entry->StateFunc != NULL) {
316             newState = entry->StateFunc(this, &status);
317         }
318         else {
319             newState = FxSelfManagedIoMax;
320         }
321     }
322 
323     m_StateMachineLock.ReleaseLock(m_PkgPnp->GetDriverGlobals());
324 
325     return status;
326 }
327 
328 FxSelfManagedIoStates
329 FxSelfManagedIoMachine::Init(
330     __in  FxSelfManagedIoMachine* This,
331     __out PNTSTATUS Status
332     )
333 /*++
334 
335 Routine Description:
336     Calls the event callback for initializing self managed io.
337 
338 Arguments:
339     This - instance of the state machine
340 
341     Status - result of the event callback into the driver
342 
343 Return Value:
344     new machine state
345 
346   --*/
347 {
348     *Status = This->m_DeviceSelfManagedIoInit.Invoke(This->GetDeviceHandle());
349 
350     if (NT_SUCCESS(*Status))  {
351         return FxSelfManagedIoStarted;
352     }
353     else {
354         return FxSelfManagedIoInitFailed;
355     }
356 }
357 
358 FxSelfManagedIoStates
359 FxSelfManagedIoMachine::Suspending(
360     __in  FxSelfManagedIoMachine* This,
361     __out PNTSTATUS Status
362     )
363 /*++
364 
365 Routine Description:
366     Invokes the self managed io suspend event callback.  Upon failure goes to
367     the failed state and awaits teardown of the stack.
368 
369 Arguments:
370     This - instance of the state machine
371 
372     Status - result of the event callback into the driver
373 
374 Return Value:
375     new machine state
376 
377   --*/
378 {
379     *Status = This->m_DeviceSelfManagedIoSuspend.Invoke(This->GetDeviceHandle());
380 
381     if (NT_SUCCESS(*Status)) {
382         return FxSelfManagedIoStopped;
383     }
384     else {
385         return FxSelfManagedIoFailed;
386     }
387 }
388 
389 FxSelfManagedIoStates
390 FxSelfManagedIoMachine::Restarting(
391     __in  FxSelfManagedIoMachine* This,
392     __out PNTSTATUS Status
393     )
394 /*++
395 
396 Routine Description:
397     Invokes the self managed io event callback for restarting self managed io
398     from the stopped state.
399 
400 Arguments:
401     This - instance of the state machine
402 
403     Status - result of the event callback into the driver
404 
405 Return Value:
406     new machine state
407 
408   --*/
409 {
410     *Status = This->m_DeviceSelfManagedIoRestart.Invoke(This->GetDeviceHandle());
411 
412     if (NT_SUCCESS(*Status)) {
413         return FxSelfManagedIoStarted;
414     }
415     else {
416         return FxSelfManagedIoFailed;
417     }
418 }
419 
420 FxSelfManagedIoStates
421 FxSelfManagedIoMachine::Flushing(
422     __in  FxSelfManagedIoMachine* This,
423     __out PNTSTATUS Status
424     )
425 /*++
426 
427 Routine Description:
428     Calls the self managed io flush routine.
429 
430 Arguments:
431     This - instance of the state machine
432 
433     Status - result of the event callback into the driver
434 
435 Return Value:
436     FxSelfManagedIoFlushed
437 
438   --*/
439 {
440     UNREFERENCED_PARAMETER(Status);
441     This->m_DeviceSelfManagedIoFlush.Invoke(This->GetDeviceHandle());
442     return FxSelfManagedIoFlushed;
443 }
444 
445 FxSelfManagedIoStates
446 FxSelfManagedIoMachine::Cleanup(
447     __in  FxSelfManagedIoMachine* This,
448     __out PNTSTATUS Status
449     )
450 /*++
451 
452 Routine Description:
453     Calls the self managed io cleanup routine.
454 
455 Arguments:
456     This - instance of the state machine
457 
458     Status - result of the event callback into the driver
459 
460 Return Value:
461     FxSelfManagedIoFinal
462 
463   --*/
464 {
465     UNREFERENCED_PARAMETER(Status);
466 
467     This->m_DeviceSelfManagedIoCleanup.Invoke(This->GetDeviceHandle());
468     return FxSelfManagedIoFinal;
469 }
470