ReactOS 0.4.16-dev-2633-g8dc9e50
portstate.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ATA Port Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Port state machine core logic
5 * COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "atapi.h"
11
12/* FUNCTIONS ******************************************************************/
13
14static
15VOID
17 _In_ PATAPORT_PORT_DATA PortData,
19 _In_opt_ PATA_DEVICE_REQUEST FailedRequest,
21{
23
25 {
27 {
28 if (FailedRequest)
29 {
30 ASSERT_REQUEST(FailedRequest);
31
32 DevExt = CONTAINING_RECORD(FailedRequest->Device, ATAPORT_DEVICE_EXTENSION, Device);
33
34 if (FailedRequest->Flags & REQUEST_FLAG_INTERNAL)
35 {
36 Action &= ~ACTION_DEVICE_ERROR;
37 }
38 else
39 {
40 ASSERT(PortData->Worker.FailedRequest == NULL);
41 PortData->Worker.FailedRequest = FailedRequest;
42 }
43 }
44 else
45 {
46 Action &= ~ACTION_DEVICE_ERROR;
48 }
49 }
50
51 /* Special case for the internal request */
52 if ((PortData->ActiveSlotsBitmap & 1) &&
53 (PortData->Slots[0]->Flags & REQUEST_FLAG_INTERNAL))
54 {
55 PATA_DEVICE_REQUEST InternalRequest = &PortData->Worker.InternalRequest;
56
58 InternalRequest->SrbStatus = SRB_STATUS_BUS_RESET;
59
60 PortData->ActiveSlotsBitmap &= ~1;
61
62 /* Internal request failed, kick off the port thread */
63 AtaReqStartCompletionDpc(InternalRequest);
64 }
65
66 /* Error recovery, save any commands pending on this port */
67 PortData->Worker.PausedSlotsBitmap |= PortData->ActiveSlotsBitmap;
68 PortData->ActiveSlotsBitmap = 0;
69
70 PortData->AbortChannel(PortData->ChannelContext, !!(Action & ACTION_PORT_RESET));
71 }
72
73 if (DevExt)
74 _InterlockedOr(&DevExt->Worker.EventsPending, Action);
75 _InterlockedOr(&PortData->Worker.EventsPending, Action);
76
77 /* Kick off the port thread */
78 if (PortData->InterruptFlags & PORT_INT_FLAG_IS_IO_ACTIVE)
79 {
80 _InterlockedAnd(&PortData->InterruptFlags, ~PORT_INT_FLAG_IS_IO_ACTIVE);
81 KeInsertQueueDpc(&PortData->Worker.Dpc, NULL, NULL);
82 }
83}
84
85static
90{
91 TRACE("Clear port action %lx, total %lx\n", Action, Context->EventsPending & ~Action);
92
93 return _InterlockedAnd(&Context->EventsPending, ~(ULONG)Action);
94}
95
96static
101{
102 TRACE("Clear dev action %lx, total %lx\n", Action, DevExt->Worker.EventsPending & ~Action);
103
104 return !!(_InterlockedAnd(&DevExt->Worker.EventsPending, ~(ULONG)Action) & Action);
105}
106
107static
110 _In_ PATAPORT_PORT_DATA PortData,
112{
116 KIRQL OldIrql, OldLevel;
117
118 ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
119
120 KeAcquireSpinLock(&ChanExt->PdoListLock, &OldLevel);
121 OldIrql = KeAcquireInterruptSpinLock(PortData->InterruptObject);
122
123 for (Entry = ChanExt->PdoList.Next; Entry != NULL; Entry = Entry->Next)
124 {
126
127 if (DevExt->Device.AtaScsiAddress.PathId != PortData->PortNumber)
128 continue;
129
130 if (DevExt->ReportedMissing)
131 continue;
132
134 continue;
135
136 if (DevExt->Worker.EventsPending & Action)
137 {
138 Result = DevExt;
139 break;
140 }
141 }
142
143 if (!Result)
144 AtaPortClearPortAction(&PortData->Worker, Action);
145
146 KeReleaseInterruptSpinLock(PortData->InterruptObject, OldIrql);
147 KeReleaseSpinLock(&ChanExt->PdoListLock, OldLevel);
148
149 return Result;
150}
151
152static
153VOID
155 _In_ PATAPORT_PORT_DATA PortData,
156 _In_ ULONG DeviceBitmap)
157{
159
160 KeInsertQueueDpc(&PortData->Worker.NotificationDpc, UlongToPtr(DeviceBitmap), NULL);
161}
162
163static
164VOID
166 _In_ PATAPORT_PORT_DATA PortData,
167 _In_ ULONG DeviceBitmap)
168{
170 ATA_SCSI_ADDRESS AtaScsiAddress;
172
173 /*
174 * We are about to reset the channel which will in turn
175 * cause the affected devices to lose their software settings.
176 * Enqueue a config event so the state machine can re-initialize all devices later on.
177 */
178 _InterlockedOr(&PortData->Worker.EventsPending,
182
183 ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
184
185 AtaScsiAddress.AsULONG = 0;
186 while (TRUE)
187 {
189
190 DevExt = AtaFdoFindNextDeviceByPath(ChanExt, &AtaScsiAddress, FALSE, NULL);
191 if (!DevExt)
192 break;
193
194 if (!(DeviceBitmap & (1 << (ULONG)AtaScsiAddress.TargetId)))
195 continue;
196
199 else
200 Event = ACTION_ENUM_DEVICE; // ACPI _GTF is not ready yet
201
203 }
204}
205
206static
207VOID
209 _In_ PATAPORT_PORT_DATA PortData,
210 _In_ ULONG CommandsCompleted)
211{
212 ULONG Slot;
213
215
216 PortData->ActiveSlotsBitmap &= ~CommandsCompleted;
217
218 while (_BitScanForward(&Slot, CommandsCompleted) != 0)
219 {
221
222 CommandsCompleted &= ~(1 << Slot);
223
224 Request = PortData->Slots[Slot];
226 ASSERT(Request->Slot == Slot);
227
229 }
230
232}
233
234static
235VOID
237 _In_ PATAPORT_PORT_DATA PortData,
239{
240 /* Ignore bad or incompatible devices, so we do not access them at all */
241 if (++DevExt->Worker.ResetRetryCount >= 4)
242 {
243 ERR("CH %lu: Too many reset attempts for the device %u, giving up\n",
244 PortData->PortNumber,
245 DevExt->Device.AtaScsiAddress.TargetId);
246
247 DevExt->Worker.Flags |= DEV_WORKER_FLAG_REMOVED;
248
249 PortData->Worker.BadDeviceBitmap |= 1 << (ULONG)DevExt->Device.AtaScsiAddress.TargetId;
250 }
251}
252
253static
256 _In_ PATAPORT_PORT_DATA PortData)
257{
259 ATA_SCSI_ADDRESS AtaScsiAddress;
260
261 _InterlockedOr(&PortData->InterruptFlags, PORT_INT_FLAG_IGNORE_LINK_IRQ);
262 PortData->Worker.DeviceCount = PortData->EnumerateChannel(PortData->ChannelContext);
263 _InterlockedAnd(&PortData->InterruptFlags, ~PORT_INT_FLAG_IGNORE_LINK_IRQ);
264
265 INFO("CH %lu: Detected %lu devices\n", PortData->PortNumber, PortData->Worker.DeviceCount);
266
267 if (AtaPortClearPortAction(&PortData->Worker, ACTION_ENUM_PORT))
268 {
269 /* Defer the completion */
270 PortData->Worker.Flags |= WORKER_FLAG_COMPLETE_PORT_ENUM_EVENT;
271 }
272
273 ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
274
275 /* Remove detached devices */
276 AtaScsiAddress.AsULONG = 0;
277 while (TRUE)
278 {
280
281 DevExt = AtaFdoFindNextDeviceByPath(ChanExt, &AtaScsiAddress, FALSE, NULL);
282 if (!DevExt)
283 break;
284
285 if (AtaScsiAddress.TargetId >= PortData->Worker.DeviceCount)
287 }
288
289 return STATUS_SUCCESS;
290}
291
292static
295 _In_ PATAPORT_PORT_DATA PortData)
296{
297 _InterlockedOr(&PortData->InterruptFlags, PORT_INT_FLAG_IGNORE_LINK_IRQ);
298 PortData->ResetChannel(PortData->ChannelContext);
299 _InterlockedAnd(&PortData->InterruptFlags, ~PORT_INT_FLAG_IGNORE_LINK_IRQ);
300
301 AtaPortEnumeratePort(PortData);
303
304 AtaPortClearPortAction(&PortData->Worker, ACTION_PORT_RESET);
305
306 /*
307 * Reset bus timings, as attached devices
308 * may reset their current transfer mode to default during the processing of a software reset
309 * and the subsequent IDENTIFY DEVICE command would end up using incorrect timings.
310 */
311 AtaPortSelectTimings(PortData, TRUE);
312
313 if (++PortData->Worker.ResetRetryCount >= 10)
314 {
315 ERR("CH %lu: Too many port reset attempts, giving up\n", PortData->PortNumber);
316 PortData->Worker.BadDeviceBitmap = MAXULONG;
317 }
318
319 return STATUS_SUCCESS;
320}
321
322static
325 _In_ PATAPORT_PORT_DATA PortData,
327{
329
331 {
332 DevExt = PortData->Worker.EnumDevExt;
333 ASSERT(DevExt);
335 }
336 else
337 {
338 DevExt = AtaPortFindDeviceForAction(PortData, Action);
339 if (!DevExt)
340 return STATUS_SUCCESS;
341 }
342
343 if (PortData->Worker.BadDeviceBitmap & (1 << (ULONG)DevExt->Device.AtaScsiAddress.TargetId))
344 {
346 }
347 else
348 {
349 DevExt->Worker.EnumStatus = AtaPortIdentifyDevice(PortData, DevExt);
350 if (DevExt->Worker.EnumStatus == DEV_STATUS_FAILED)
351 {
352 AtaPortMarkDeviceFailed(PortData, DevExt);
354 }
355 }
356
357 if ((DevExt->Worker.EnumStatus != DEV_STATUS_SAME_DEVICE) &&
359 {
361 }
362
363 if (AtaPortClearDeviceAction(DevExt, Action))
364 {
366 AtaPortClearPortAction(&PortData->Worker, Action);
367
369 }
370
371 return STATUS_SUCCESS;
372}
373
374static
377 _In_ PATAPORT_PORT_DATA PortData)
378{
381
383 if (!DevExt)
384 return STATUS_SUCCESS;
385
386 Status = AtaPortDeviceProcessError(PortData, DevExt);
388 {
389 AtaPortMarkDeviceFailed(PortData, DevExt);
390 return Status;
391 }
392
394 return STATUS_SUCCESS;
395}
396
397static
400 _In_ PATAPORT_PORT_DATA PortData)
401{
404
406 if (!DevExt)
407 return STATUS_SUCCESS;
408
409 Status = AtaPortDeviceProcessConfig(PortData, DevExt);
411 {
412 AtaPortMarkDeviceFailed(PortData, DevExt);
413 return Status;
414 }
415
418
419 return STATUS_SUCCESS;
420}
421
422static
425 _In_ PATAPORT_PORT_DATA PortData)
426{
429
431 if (!DevExt)
432 return STATUS_SUCCESS;
433
434 Status = AtaPortDeviceProcessPowerChange(PortData, DevExt);
436 {
437 AtaPortMarkDeviceFailed(PortData, DevExt);
438 return Status;
439 }
440
442 return STATUS_SUCCESS;
443}
444
445static
448 _In_ PATAPORT_PORT_DATA PortData)
449{
450 AtaPortSelectTimings(PortData, FALSE);
451 AtaPortClearPortAction(&PortData->Worker, ACTION_PORT_TIMING);
452
453 return STATUS_SUCCESS;
454}
455
456static
459 _In_ PATAPORT_PORT_DATA PortData,
461{
463 ULONG i, EventIndex;
465
466 OldIrql = KeAcquireInterruptSpinLock(PortData->InterruptObject);
467
468 /* Handle events by priority order */
469 Success = _BitScanForward(&EventIndex, PortData->Worker.EventsPending);
470 if (!Success)
471 {
473
474 /* Resume port I/O */
475 ASSERT(!(PortData->InterruptFlags & PORT_INT_FLAG_IS_IO_ACTIVE));
476 _InterlockedOr(&PortData->InterruptFlags, PORT_INT_FLAG_IS_IO_ACTIVE);
477
478 /* Complete failed request */
479 Request = PortData->Worker.FailedRequest;
480 if (Request && !(PortData->Worker.PausedSlotsBitmap & (1 << Request->Slot)))
481 {
483 }
484 PortData->Worker.FailedRequest = NULL;
485
486 /* Requeue saved commands */
487 for (i = 0; i < MAX_SLOTS; ++i)
488 {
489 if (!(PortData->Worker.PausedSlotsBitmap & (1 << i)))
490 continue;
491
492 Request = PortData->Slots[i];
494 ASSERT(Request != &PortData->Worker.InternalRequest);
495
496 Request->SrbStatus = SRB_STATUS_BUSY;
497 Request->InternalState = REQUEST_STATE_REQUEUE;
499 }
500
501 PortData->Worker.PausedSlotsBitmap = 0;
502 }
503
504 KeReleaseInterruptSpinLock(PortData->InterruptObject, OldIrql);
505
506 *Action = 1 << EventIndex;
507 return Success;
508}
509
510static
511VOID
513 _In_ PATAPORT_PORT_DATA PortData)
514{
517
518 while (TRUE)
519 {
520 if (!AtaPortGetNextEvent(PortData, &Action))
521 break;
522
523#if DBG
524 if (PortData->Worker.StateLoopCount++ > 1500)
525 {
526 ERR("CH %lu: Loop detected %lx\n", PortData->PortNumber,
527 PortData->Worker.EventsPending);
528 ASSERT(FALSE);
529 }
530#endif
531
532 switch (Action)
533 {
535 Status = AtaPortResetPort(PortData);
536 break;
537 case ACTION_ENUM_PORT:
538 Status = AtaPortEnumeratePort(PortData);
539 break;
543 break;
545 Status = AtaPortSetTransferMode(PortData);
546 break;
548 Status = AtaPortConfigureDevice(PortData);
549 break;
552 break;
555 break;
556
557 default:
558 ASSERT(FALSE);
560 }
561
563 _InterlockedOr(&PortData->Worker.EventsPending, ACTION_PORT_RESET);
564 }
565}
566
567static
568VOID
570 _In_ PATAPORT_PORT_DATA PortData)
571{
573 BOOLEAN DoWait = FALSE;
574
575 KeAcquireSpinLock(&PortData->QueueLock, &OldIrql);
576 KeClearEvent(&PortData->QueueStoppedEvent);
577 if (!AtaPortQueueEmpty(PortData))
578 {
579 PortData->QueueFlags |= PORT_QUEUE_FLAG_SIGNAL_STOP;
580 DoWait = TRUE;
581 }
582 KeReleaseSpinLock(&PortData->QueueLock, OldIrql);
583 if (DoWait)
584 {
585 KeWaitForSingleObject(&PortData->QueueStoppedEvent, Executive, KernelMode, FALSE, NULL);
586 }
587}
588
589static
590VOID
592 _In_ PATAPORT_PORT_DATA PortData)
593{
595 ATA_SCSI_ADDRESS AtaScsiAddress;
596
597 ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
598 ASSERT(IS_FDO(ChanExt));
599
600 AtaScsiAddress.AsULONG = 0;
601 while (TRUE)
602 {
604 PULONG PowerIdleCounter;
605
606 /*
607 * Acquire a reference to make sure the device object is valid
608 * for the duration of the port event handling.
609 */
610 DevExt = AtaFdoFindNextDeviceByPath(ChanExt,
611 &AtaScsiAddress,
612 FALSE,
614 if (!DevExt)
615 break;
616
618 DevExt->Worker.ResetRetryCount = 0;
619
621 {
623 continue;
624 }
625
626 /* Stop the Srb processing */
628
629 /*
630 * There is a chance that we can receive a power down request
631 * while the state maching is being running, so mark the device as busy
632 * to reduce the request probability.
633 */
634 PowerIdleCounter = DevExt->Device.PowerIdleCounter;
635 if (PowerIdleCounter)
636 PoSetDeviceBusy(PowerIdleCounter);
637 }
638
639 /* Wait for the port queue to become empty */
640 AtaPortWaitForIdle(PortData);
641
642 PortData->Worker.Flags = 0;
643 PortData->Worker.BadDeviceBitmap = 0;
644 PortData->Worker.ResetRetryCount = 0;
645#if DBG
646 PortData->Worker.StateLoopCount = 0;
647#endif
648
649 // FIXME: Handle PORT_FLAG_IS_SIMPLEX
650}
651
652static
653VOID
655 _In_ PATAPORT_PORT_DATA PortData)
656{
658 ATA_SCSI_ADDRESS AtaScsiAddress;
659
660 ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
661
662 AtaScsiAddress.AsULONG = 0;
663 while (TRUE)
664 {
667
668 DevExt = AtaFdoFindNextDeviceByPath(ChanExt, &AtaScsiAddress, TRUE, NULL);
669 if (!DevExt)
670 break;
671
673 {
675 if (!DevExt->RemovalPending)
676 PortData->Worker.Flags |= WORKER_FLAG_NEED_RESCAN;
677 DevExt->RemovalPending = TRUE;
679
682
685
688 }
689 else
690 {
691 /* Resume the Srb processing */
693 }
694
695 /* Release a reference */
697 {
698 DevExt->Worker.Flags &= ~DEV_WORKER_FLAG_HOLD_REFERENCE;
700 }
701 }
702
703 if (PortData->Worker.Flags & WORKER_FLAG_COMPLETE_PORT_ENUM_EVENT)
704 {
705 /* We defer this event completion to avoid a BusRelations request */
706 PortData->Worker.Flags &= ~WORKER_FLAG_NEED_RESCAN;
707
708 KeSetEvent(&PortData->Worker.EnumerationEvent, 0, FALSE);
709 }
710
711 if (PortData->Worker.Flags & WORKER_FLAG_NEED_RESCAN)
713}
714
715static
716VOID
718 _In_ PATAPORT_PORT_DATA PortData)
719{
721
722 KeAcquireSpinLock(&PortData->Worker.Lock, &OldIrql);
723 KeClearEvent(&PortData->Worker.ThreadEvent);
724 KeReleaseSpinLock(&PortData->Worker.Lock, OldIrql);
725}
726
727VOID
728NTAPI
730 _In_ PVOID StartContext)
731{
732 PATAPORT_PORT_DATA PortData = StartContext;
733
734 while (TRUE)
735 {
737 Executive,
739 FALSE,
740 NULL);
741 if (PortData->PortFlags & PORT_FLAG_EXIT_THREAD)
742 break;
743
744 AtaPortWorkerClearSignal(PortData);
745 AtaPortEnterStateMachine(PortData);
746 AtaPortRunStateMachine(PortData);
747 AtaPortExitStateMachine(PortData);
748 }
749
751}
752
753VOID
758 ...)
759{
761 va_list ap;
762
764
765 TRACE("CH %lu: Notification %lu\n", PortData->PortNumber, NotificationType);
766
767 switch (NotificationType)
768 {
770 {
772 break;
773 }
774
775 case AtaResetDetected:
776 {
777 ASSERT(PortData->Worker.Thread == KeGetCurrentThread());
780 break;
781 }
782
784 {
786
789 else
790 TRACE("CH %lu: Ignore link IRQ\n", PortData->PortNumber);
791 break;
792 }
793
794 case AtaRequestFailed:
795 {
796 AtaPortQueueEvent(PortData,
797 NULL,
800 break;
801 }
802
804 {
806 break;
807 }
808
809 default:
810 ERR("CH %lu: Unsupported notification %lu\n", PortData->PortNumber, NotificationType);
811 break;
812 }
813
814 va_end(ap);
815}
816
820{
822 PATAPORT_PORT_DATA PortData = Device->PortData;
823
825 KeSetEvent(&PortData->Worker.CompletionEvent, IO_NO_INCREMENT, FALSE);
826
827 return COMPLETE_IRP;
828}
829
832 _In_ PATAPORT_PORT_DATA PortData,
834{
835 PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
837
839 {
840 INFO("CH %lu: Send CDB %u %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
841 PortData->PortNumber,
842 DevExt->Device.AtaScsiAddress.TargetId,
843 Request->Cdb[0],
844 Request->Cdb[1],
845 Request->Cdb[2],
846 Request->Cdb[3],
847 Request->Cdb[4],
848 Request->Cdb[5],
849 Request->Cdb[6]);
850 }
851 else
852 {
853 INFO("CH %lu: Send TF %u %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
854 PortData->PortNumber,
855 DevExt->Device.AtaScsiAddress.TargetId,
856 Request->TaskFile.Command,
857 Request->TaskFile.Feature,
858 Request->TaskFile.SectorCount,
859 Request->TaskFile.LowLba,
860 Request->TaskFile.MidLba,
861 Request->TaskFile.HighLba,
862 Request->TaskFile.DriveSelect);
863 }
864
865 KeClearEvent(&PortData->Worker.CompletionEvent);
866
868 Request->Device = (PATA_IO_CONTEXT_COMMON)&DevExt->Device;
869
870 PortData->Worker.OldRequest = PortData->Slots[0];
871 PortData->Slots[0] = Request;
872
874
875 KeAcquireSpinLockAtDpcLevel(&PortData->QueueLock);
876 PortData->ActiveTimersBitmap |= 1 << 0;
877 KeReleaseSpinLockFromDpcLevel(&PortData->QueueLock);
878
880
882
883 KeWaitForSingleObject(&PortData->Worker.CompletionEvent, Executive, KernelMode, FALSE, NULL);
884
885 /* Stop the timer */
886 KeAcquireSpinLock(&PortData->QueueLock, &OldIrql);
887 PortData->ActiveTimersBitmap = 0;
888 KeReleaseSpinLock(&PortData->QueueLock, OldIrql);
889
890 PortData->Slots[0] = PortData->Worker.OldRequest;
891
892 if ((Request->SrbStatus == SRB_STATUS_TIMEOUT) ||
893 (Request->SrbStatus == SRB_STATUS_BUS_RESET))
894 {
896 }
897
898 if (Request->SrbStatus == SRB_STATUS_SUCCESS)
899 return STATUS_SUCCESS;
900
902}
903
904VOID
906 _In_ PATAPORT_PORT_DATA PortData,
907 _In_ ULONG Slot)
908{
911
913
914 Request = PortData->Slots[Slot];
916
918
919 ERR("CH %lu: Slot %lu (%08lx) timed out %lx (%lus) %u '%s'\n",
920 PortData->PortNumber,
921 Slot,
922 1 << Slot,
923 Request->Flags,
924 Request->TimeOut,
926 DevExt->FriendlyName);
928 {
929 ERR("CH %lu: CDB %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
930 PortData->PortNumber,
931 Request->Cdb[0],
932 Request->Cdb[1],
933 Request->Cdb[2],
934 Request->Cdb[3],
935 Request->Cdb[4],
936 Request->Cdb[5],
937 Request->Cdb[6]);
938 }
939 else
940 {
941 ERR("CH %lu: TF %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
942 PortData->PortNumber,
943 Request->TaskFile.Command,
944 Request->TaskFile.Feature,
945 Request->TaskFile.SectorCount,
946 Request->TaskFile.LowLba,
947 Request->TaskFile.MidLba,
948 Request->TaskFile.HighLba,
949 Request->TaskFile.DriveSelect);
950 }
951
952 Request->SrbStatus = SRB_STATUS_TIMEOUT;
953
954 /* The active command has timed out, set the ATA outputs to something meaningful */
955 Request->Output.Status = IDE_STATUS_ERROR;
956 Request->Output.Error = IDE_ERROR_COMMAND_ABORTED;
957
959}
960
962VOID
964 _In_ PATAPORT_PORT_DATA PortData)
965{
967
968 KeAcquireSpinLock(&PortData->Worker.Lock, &OldIrql);
969 KeSetEvent(&PortData->Worker.ThreadEvent, IO_NO_INCREMENT, FALSE);
970 KeReleaseSpinLock(&PortData->Worker.Lock, OldIrql);
971}
972
973VOID
974NTAPI
976 _In_ PKDPC Dpc,
980{
982
986
988}
989
991VOID
993 _In_ PATAPORT_PORT_DATA PortData,
996{
998
999 TRACE("New action %lu\n", Action);
1000
1001 OldIrql = KeAcquireInterruptSpinLock(PortData->InterruptObject);
1002 AtaPortQueueEvent(PortData, DevExt, NULL, Action);
1003 KeReleaseInterruptSpinLock(PortData->InterruptObject, OldIrql);
1004}
unsigned char BOOLEAN
Definition: actypes.h:127
ATA_COMPLETION_ACTION
Definition: ata_shared.h:148
@ COMPLETE_IRP
Definition: ata_shared.h:149
enum _PORT_NOTIFICATION_TYPE PORT_NOTIFICATION_TYPE
struct _ATA_IO_CONTEXT_COMMON * PATA_IO_CONTEXT_COMMON
#define REQUEST_STATE_REQUEUE
Definition: ata_shared.h:270
_In_ PVOID PortContext
Definition: ata_shared.h:375
#define REQUEST_FLAG_INTERNAL
Definition: ata_shared.h:345
@ AtaRequestFailed
Definition: ata_shared.h:77
@ AtaBusChangeDetected
Definition: ata_shared.h:76
@ AtaAsyncNotificationDetected
Definition: ata_shared.h:78
@ AtaResetDetected
Definition: ata_shared.h:75
@ AtaRequestComplete
Definition: ata_shared.h:74
VOID AtaReqSendRequest(_In_ PATA_DEVICE_REQUEST Request)
Definition: scsi.c:632
#define PORT_FLAG_EXIT_THREAD
Definition: atapi.h:346
#define ASSERT_REQUEST(Request)
Definition: atapi.h:326
VOID AtaDeviceFlushPowerIrpQueue(_In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:37
#define PORT_INT_FLAG_IS_IO_ACTIVE
Definition: atapi.h:360
KDEFERRED_ROUTINE AtaPortWorkerSignalDpc
Definition: atapi.h:879
SLIST_HEADER AtapCompletionQueueList
Definition: scsi.c:14
#define DEV_WORKER_FLAG_HOLD_REFERENCE
Definition: atapi.h:304
KSTART_ROUTINE AtaPortWorkerThread
Definition: atapi.h:878
#define MAX_SLOTS
Definition: atapi.h:207
@ ACTION_DEVICE_CONFIG
Definition: atapi.h:248
@ ACTION_ENUM_PORT
Definition: atapi.h:244
@ ACTION_DEVICE_POWER
Definition: atapi.h:250
@ ACTION_PORT_TIMING
Definition: atapi.h:247
@ ACTION_DEVICE_ERROR
Definition: atapi.h:249
@ ACTION_ENUM_DEVICE_NEW
Definition: atapi.h:245
@ ACTION_ENUM_DEVICE
Definition: atapi.h:246
@ ACTION_PORT_RESET
Definition: atapi.h:243
@ DEV_STATUS_FAILED
Definition: atapi.h:258
@ DEV_STATUS_SAME_DEVICE
Definition: atapi.h:257
@ DEV_STATUS_NO_DEVICE
Definition: atapi.h:255
NTSTATUS AtaPortDeviceProcessConfig(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_config.c:341
#define PORT_QUEUE_FLAG_SIGNAL_STOP
Definition: atapi.h:370
enum _ATA_PORT_ACTION ATA_PORT_ACTION
#define IS_FDO(p)
Definition: atapi.h:173
struct _ATAPORT_IO_CONTEXT * PATAPORT_IO_CONTEXT
Definition: atapi.h:36
#define WORKER_FLAG_NEED_RESCAN
Definition: atapi.h:279
NTSTATUS AtaPortDeviceProcessError(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_error.c:642
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaReqFlushDeviceQueue(_In_ PATAPORT_IO_CONTEXT Device)
Definition: scsi.c:1451
REQUEST_COMPLETION_ROUTINE AtaPortCompleteInternalRequest
Definition: atapi.h:880
#define QUEUE_FLAG_FROZEN_PORT_BUSY
Definition: atapi.h:105
DECLSPEC_NOINLINE_FROM_PAGED PATAPORT_DEVICE_EXTENSION AtaFdoFindNextDeviceByPath(_In_ PATAPORT_CHANNEL_EXTENSION ChanExt, _Inout_ PATA_SCSI_ADDRESS AtaScsiAddress, _In_ BOOLEAN SearchRemoveDev, _In_ PVOID ReferenceTag)
Definition: fdo.c:654
PORT_NOTIFICATION AtaPortNotification
Definition: atapi.h:881
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaReqThawQueue(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG ReasonFlags)
Definition: scsi.c:1365
VOID AtaReqStartCompletionDpc(_In_ PATA_DEVICE_REQUEST Request)
Definition: scsi.c:777
#define PORT_INT_FLAG_IGNORE_LINK_IRQ
Definition: atapi.h:361
#define DEV_WORKER_FLAG_REMOVED
Definition: atapi.h:305
FORCEINLINE BOOLEAN AtaPortQueueEmpty(_In_ PATAPORT_PORT_DATA PortData)
Definition: atapi.h:573
KDPC AtapCompletionDpc
Definition: scsi.c:15
#define DEVICE_UNINITIALIZED
Definition: atapi.h:91
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaReqFreezeQueue(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG ReasonFlags)
Definition: scsi.c:1351
#define DEVICE_PNP_STARTED
Definition: atapi.h:92
VOID AtaPortSelectTimings(_In_ PATAPORT_PORT_DATA PortData, _In_ BOOLEAN ForceCompatibleTimings)
Definition: dev_timings.c:258
ATA_DEVICE_STATUS AtaPortIdentifyDevice(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_identify.c:213
#define WORKER_FLAG_COMPLETE_PORT_ENUM_EVENT
Definition: atapi.h:280
#define QUEUE_FLAG_FROZEN_REMOVED
Definition: atapi.h:111
NTSTATUS AtaPortDeviceProcessPowerChange(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:151
#define IDE_STATUS_ERROR
Definition: atapi.h:125
#define IDE_ERROR_COMMAND_ABORTED
Definition: atapi.h:158
LONG NTSTATUS
Definition: precomp.h:26
#define ERR(fmt,...)
Definition: precomp.h:57
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define __cdecl
Definition: corecrt.h:121
#define va_end(v)
Definition: stdarg.h:28
#define va_arg(v, l)
Definition: stdarg.h:27
#define va_start(v, l)
Definition: stdarg.h:26
char * va_list
Definition: vadefs.h:50
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:725
#define INFO
Definition: debug.h:89
#define UlongToPtr(u)
Definition: config.h:106
#define SRB_STATUS_BUS_RESET
Definition: srb.h:353
#define SRB_STATUS_TIMEOUT
Definition: srb.h:349
#define SRB_STATUS_BUSY
Definition: srb.h:345
#define SRB_STATUS_SUCCESS
Definition: srb.h:341
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
@ Success
Definition: eventcreate.c:712
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define KeGetCurrentThread
Definition: hal.h:55
#define REQUEST_FLAG_PACKET_COMMAND
Definition: hwidep.h:169
volatile char *const const char modify _InterlockedAnd
Definition: intrin_ppc.h:267
#define ASSERT(a)
Definition: mode.c:44
#define KernelMode
Definition: asm.h:38
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define UNREACHABLE
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:154
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:171
NTSTATUS NTAPI PsTerminateSystemThread(IN NTSTATUS ExitStatus)
Definition: kill.c:1153
#define STATUS_ADAPTER_HARDWARE_ERROR
Definition: ntstatus.h:524
VOID NTAPI IoInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject, IN DEVICE_RELATION_TYPE Type)
Definition: pnpmgr.c:1772
static VOID AtaPortOnResetNotification(_In_ PATAPORT_PORT_DATA PortData, _In_ ULONG DeviceBitmap)
Definition: portstate.c:165
static VOID AtaPortWaitForIdle(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:569
static NTSTATUS AtaPortDeviceChangePower(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:424
static ATA_PORT_ACTION AtaPortClearPortAction(_In_ PATA_WORKER_CONTEXT Context, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:87
static PATAPORT_DEVICE_EXTENSION AtaPortFindDeviceForAction(_In_ PATAPORT_PORT_DATA PortData, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:109
static NTSTATUS AtaPortEnumerateDevice(_In_ PATAPORT_PORT_DATA PortData, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:324
static BOOLEAN AtaPortClearDeviceAction(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:98
static VOID AtaPortExitStateMachine(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:654
static NTSTATUS AtaPortConfigureDevice(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:399
static BOOLEAN AtaPortGetNextEvent(_In_ PATAPORT_PORT_DATA PortData, _Out_ ATA_PORT_ACTION *Action)
Definition: portstate.c:458
VOID AtaPortTimeout(_In_ PATAPORT_PORT_DATA PortData, _In_ ULONG Slot)
Definition: portstate.c:905
static VOID AtaPortOnAsyncNotification(_In_ PATAPORT_PORT_DATA PortData, _In_ ULONG DeviceBitmap)
Definition: portstate.c:154
static NTSTATUS AtaPortResetPort(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:294
static VOID AtaPortQueueEvent(_In_ PATAPORT_PORT_DATA PortData, _In_opt_ PATAPORT_DEVICE_EXTENSION DevExt, _In_opt_ PATA_DEVICE_REQUEST FailedRequest, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:16
static NTSTATUS AtaPortRecoveryFromError(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:376
static NTSTATUS AtaPortSetTransferMode(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:447
static VOID AtaPortMarkDeviceFailed(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: portstate.c:236
static VOID AtaPortWorkerClearSignal(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:717
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaPortSignalWorkerThread(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:963
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaDeviceQueueEvent(_In_ PATAPORT_PORT_DATA PortData, _In_opt_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:992
static VOID AtaPortOnRequestComplete(_In_ PATAPORT_PORT_DATA PortData, _In_ ULONG CommandsCompleted)
Definition: portstate.c:208
NTSTATUS AtaPortSendRequest(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: portstate.c:831
static NTSTATUS AtaPortEnumeratePort(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:255
static VOID AtaPortRunStateMachine(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:512
static VOID AtaPortEnterStateMachine(_In_ PATAPORT_PORT_DATA PortData)
Definition: portstate.c:591
long _InterlockedOr(_Interlocked_operand_ long volatile *_Value, long _Mask)
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask)
Definition: intrin_arm.h:57
#define KeAcquireSpinLockAtDpcLevel(SpinLock)
Definition: ke.h:125
#define KeReleaseSpinLockFromDpcLevel(SpinLock)
Definition: ke.h:135
Entry
Definition: section.c:5210
#define DECLSPEC_NOINLINE_FROM_PAGED
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE(s)
Definition: solgame.cpp:4
_In_ PVOID Context
Definition: storport.h:2269
KSPIN_LOCK PdoListLock
Definition: atapi.h:445
PDEVICE_OBJECT Pdo
Definition: atapi.h:444
SINGLE_LIST_ENTRY PdoList
Definition: atapi.h:446
IO_REMOVE_LOCK RemoveLock
Definition: atapi.h:434
ATA_WORKER_DEVICE_CONTEXT Worker
Definition: atapi.h:458
ATAPORT_IO_CONTEXT Device
Definition: atapi.h:457
ATAPORT_COMMON_EXTENSION Common
Definition: atapi.h:455
ULONG DeviceFlags
Definition: atapi.h:81
PULONG PowerIdleCounter
Definition: atapi.h:98
ATA_SCSI_ADDRESS AtaScsiAddress
Definition: atapi.h:100
volatile LONG InterruptFlags
Definition: atapi.h:359
ULONG PortNumber
Definition: atapi.h:396
ULONG PortFlags
Definition: atapi.h:335
ATA_WORKER_CONTEXT Worker
Definition: atapi.h:400
KEVENT ThreadEvent
Definition: atapi.h:274
PKTHREAD Thread
Definition: atapi.h:295
volatile LONG EventsPending
Definition: atapi.h:300
volatile LONG EnumStatus
Definition: atapi.h:301
Definition: ketypes.h:751
Definition: ntbasedef.h:640
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:641
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
ULONG AsULONG
Definition: atapi.h:69
UCHAR PathId
Definition: atapi.h:65
UCHAR TargetId
Definition: atapi.h:60
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
_In_ WDF_SPECIAL_FILE_TYPE NotificationType
Definition: wdfdevice.h:1024
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:510
void int int ULONGLONG int va_list * ap
Definition: winesup.h:36
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
#define IoReleaseRemoveLock(_RemoveLock, _Tag)
Definition: iofuncs.h:2764
@ BusRelations
Definition: iotypes.h:2154
#define IO_NO_INCREMENT
Definition: iotypes.h:598
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ Executive
Definition: ketypes.h:467
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:740
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:739
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:741
#define PoSetDeviceBusy(IdlePointer)
#define InterlockedPushEntrySList(SListHead, SListEntry)
Definition: rtlfuncs.h:3406