2 * PROJECT: ReactOS Storport Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Storport FDO code
5 * COPYRIGHT: Copyright 2017 Eric Kohl (eric.kohl@reactos.org)
8 /* INCLUDES *******************************************************************/
16 /* FUNCTIONS ******************************************************************/
21 PortFdoInterruptRoutine(
22 _In_ PKINTERRUPT Interrupt
,
23 _In_ PVOID ServiceContext
)
25 PFDO_DEVICE_EXTENSION DeviceExtension
;
27 DPRINT1("PortFdoInterruptRoutine(%p %p)\n",
28 Interrupt
, ServiceContext
);
30 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)ServiceContext
;
32 return MiniportHwInterrupt(&DeviceExtension
->Miniport
);
38 PortFdoConnectInterrupt(
39 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
)
43 KINTERRUPT_MODE InterruptMode
;
48 DPRINT1("PortFdoConnectInterrupt(%p)\n",
51 /* No resources, no interrupt. Done! */
52 if (DeviceExtension
->AllocatedResources
== NULL
||
53 DeviceExtension
->TranslatedResources
== NULL
)
55 DPRINT1("Checkpoint\n");
56 return STATUS_SUCCESS
;
59 /* Get the interrupt data from the resource list */
60 Status
= GetResourceListInterrupt(DeviceExtension
,
66 if (!NT_SUCCESS(Status
))
68 DPRINT1("GetResourceListInterrupt() failed (Status 0x%08lx)\n", Status
);
72 DPRINT1("Vector: %lu\n", Vector
);
73 DPRINT1("Irql: %lu\n", Irql
);
75 DPRINT1("Affinity: 0x%08lx\n", Affinity
);
77 /* Connect the interrupt */
78 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
79 PortFdoInterruptRoutine
,
89 if (NT_SUCCESS(Status
))
91 DeviceExtension
->InterruptIrql
= Irql
;
95 DPRINT1("IoConnectInterrupt() failed (Status 0x%08lx)\n", Status
);
104 PortFdoStartMiniport(
105 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
)
107 PHW_INITIALIZATION_DATA InitData
;
108 INTERFACE_TYPE InterfaceType
;
111 DPRINT1("PortFdoStartDevice(%p)\n", DeviceExtension
);
113 /* Get the interface type of the lower device */
114 InterfaceType
= GetBusInterface(DeviceExtension
->LowerDevice
);
115 if (InterfaceType
== InterfaceTypeUndefined
)
116 return STATUS_NO_SUCH_DEVICE
;
118 /* Get the driver init data for the given interface type */
119 InitData
= PortGetDriverInitData(DeviceExtension
->DriverExtension
,
121 if (InitData
== NULL
)
122 return STATUS_NO_SUCH_DEVICE
;
124 /* Initialize the miniport */
125 Status
= MiniportInitialize(&DeviceExtension
->Miniport
,
128 if (!NT_SUCCESS(Status
))
130 DPRINT1("MiniportInitialize() failed (Status 0x%08lx)\n", Status
);
134 /* Call the miniports FindAdapter function */
135 Status
= MiniportFindAdapter(&DeviceExtension
->Miniport
);
136 if (!NT_SUCCESS(Status
))
138 DPRINT1("MiniportFindAdapter() failed (Status 0x%08lx)\n", Status
);
142 /* Connect the configured interrupt */
143 Status
= PortFdoConnectInterrupt(DeviceExtension
);
144 if (!NT_SUCCESS(Status
))
146 DPRINT1("PortFdoConnectInterrupt() failed (Status 0x%08lx)\n", Status
);
150 /* Call the miniports HwInitialize function */
151 Status
= MiniportHwInitialize(&DeviceExtension
->Miniport
);
152 if (!NT_SUCCESS(Status
))
154 DPRINT1("MiniportHwInitialize() failed (Status 0x%08lx)\n", Status
);
158 /* Call the HwPassiveInitRoutine function, if available */
159 if (DeviceExtension
->HwPassiveInitRoutine
!= NULL
)
161 DPRINT1("Calling HwPassiveInitRoutine()\n");
162 if (!DeviceExtension
->HwPassiveInitRoutine(&DeviceExtension
->Miniport
.MiniportExtension
->HwDeviceExtension
))
164 DPRINT1("HwPassiveInitRoutine() failed\n");
165 return STATUS_UNSUCCESSFUL
;
169 return STATUS_SUCCESS
;
177 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
,
180 PIO_STACK_LOCATION Stack
;
183 DPRINT1("PortFdoStartDevice(%p %p)\n",
184 DeviceExtension
, Irp
);
186 ASSERT(DeviceExtension
->ExtensionType
== FdoExtension
);
188 /* Get the current stack location */
189 Stack
= IoGetCurrentIrpStackLocation(Irp
);
191 /* Start the lower device if the FDO is in 'stopped' state */
192 if (DeviceExtension
->PnpState
== dsStopped
)
194 if (IoForwardIrpSynchronously(DeviceExtension
->LowerDevice
, Irp
))
196 Status
= Irp
->IoStatus
.Status
;
200 Status
= STATUS_UNSUCCESSFUL
;
203 if (!NT_SUCCESS(Status
))
205 DPRINT1("Lower device failed the IRP (Status 0x%08lx)\n", Status
);
210 /* Change to the 'started' state */
211 DeviceExtension
->PnpState
= dsStarted
;
213 /* Copy the raw and translated resource lists into the device extension */
214 if (Stack
->Parameters
.StartDevice
.AllocatedResources
!= NULL
&&
215 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
!= NULL
)
217 DeviceExtension
->AllocatedResources
= CopyResourceList(NonPagedPool
,
218 Stack
->Parameters
.StartDevice
.AllocatedResources
);
219 if (DeviceExtension
->AllocatedResources
== NULL
)
220 return STATUS_NO_MEMORY
;
222 DeviceExtension
->TranslatedResources
= CopyResourceList(NonPagedPool
,
223 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
224 if (DeviceExtension
->TranslatedResources
== NULL
)
225 return STATUS_NO_MEMORY
;
228 /* Get the bus interface of the lower (bus) device */
229 Status
= QueryBusInterface(DeviceExtension
->LowerDevice
,
230 (PGUID
)&GUID_BUS_INTERFACE_STANDARD
,
231 sizeof(BUS_INTERFACE_STANDARD
),
233 &DeviceExtension
->BusInterface
,
235 DPRINT1("Status: 0x%08lx\n", Status
);
236 if (NT_SUCCESS(Status
))
238 DPRINT1("Context: %p\n", DeviceExtension
->BusInterface
.Context
);
239 DeviceExtension
->BusInitialized
= TRUE
;
242 /* Start the miniport (FindAdapter & Initialize) */
243 Status
= PortFdoStartMiniport(DeviceExtension
);
244 if (!NT_SUCCESS(Status
))
246 DPRINT1("FdoStartMiniport() failed (Status 0x%08lx)\n", Status
);
247 DeviceExtension
->PnpState
= dsStopped
;
257 _In_ PPDO_DEVICE_EXTENSION PdoExtension
)
259 IO_STATUS_BLOCK IoStatusBlock
;
260 PIO_STACK_LOCATION IrpStack
;
265 PSENSE_DATA SenseBuffer
;
266 BOOLEAN KeepTrying
= TRUE
;
267 ULONG RetryCount
= 0;
268 SCSI_REQUEST_BLOCK Srb
;
270 // PSCSI_PORT_LUN_EXTENSION LunExtension;
271 // PFDO_DEVICE_EXTENSION DeviceExtension;
273 DPRINT("PortSendInquiry(%p)\n", PdoExtension
);
275 if (PdoExtension
->InquiryBuffer
== NULL
)
277 PdoExtension
->InquiryBuffer
= ExAllocatePoolWithTag(NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_INQUIRY_DATA
);
278 if (PdoExtension
->InquiryBuffer
== NULL
)
279 return STATUS_INSUFFICIENT_RESOURCES
;
282 SenseBuffer
= ExAllocatePoolWithTag(NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SENSE_DATA
);
283 if (SenseBuffer
== NULL
)
285 return STATUS_INSUFFICIENT_RESOURCES
;
290 /* Initialize event for waiting */
291 KeInitializeEvent(&Event
,
296 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN
,
297 PdoExtension
->Device
,
300 PdoExtension
->InquiryBuffer
,
301 INQUIRYDATABUFFERSIZE
,
307 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
310 Status
= STATUS_INSUFFICIENT_RESOURCES
;
316 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
318 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
319 Srb
.OriginalRequest
= Irp
;
320 Srb
.PathId
= PdoExtension
->Bus
;
321 Srb
.TargetId
= PdoExtension
->Target
;
322 Srb
.Lun
= PdoExtension
->Lun
;
323 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
324 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
325 Srb
.TimeOutValue
= 4;
328 Srb
.SenseInfoBuffer
= SenseBuffer
;
329 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
331 Srb
.DataBuffer
= PdoExtension
->InquiryBuffer
;
332 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
334 /* Attach Srb to the Irp */
335 IrpStack
= IoGetNextIrpStackLocation(Irp
);
336 IrpStack
->Parameters
.Scsi
.Srb
= &Srb
;
340 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
341 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= PdoExtension
->Lun
;
342 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
344 /* Call the driver */
345 Status
= IoCallDriver(PdoExtension
->Device
, Irp
);
347 /* Wait for it to complete */
348 if (Status
== STATUS_PENDING
)
350 DPRINT1("PortSendInquiry(): Waiting for the driver to process request...\n");
351 KeWaitForSingleObject(&Event
,
356 Status
= IoStatusBlock
.Status
;
359 DPRINT("PortSendInquiry(): Request processed by driver, status = 0x%08X\n", Status
);
361 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
363 DPRINT("Found a device!\n");
366 Status
= STATUS_SUCCESS
;
371 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
373 /* Check if the queue is frozen */
374 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
376 /* Something weird happened, deal with it (unfreeze the queue) */
379 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
381 // LunExtension = SpiGetLunExtension(DeviceExtension,
383 // LunInfo->TargetId,
386 /* Clear frozen flag */
387 // LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
389 /* Acquire the spinlock */
390 // KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
392 /* Process the request */
393 // SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
395 /* SpiGetNextRequestFromLun() releases the spinlock,
396 so we just lower irql back to what it was before */
397 // KeLowerIrql(Irql);
400 /* Check if data overrun happened */
401 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
403 DPRINT("Data overrun at TargetId %d\n", PdoExtension
->Target
);
406 Status
= STATUS_SUCCESS
;
409 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
410 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
412 /* LUN is not valid, but some device responds there.
413 Mark it as invalid anyway */
416 Status
= STATUS_INVALID_DEVICE_REQUEST
;
421 /* Retry a couple of times if no timeout happened */
422 if ((RetryCount
< 2) &&
423 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
424 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
431 /* That's all, quit the loop */
434 /* Set status according to SRB status */
435 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
436 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
438 Status
= STATUS_INVALID_DEVICE_REQUEST
;
442 Status
= STATUS_IO_DEVICE_ERROR
;
448 /* Free the sense buffer */
449 ExFreePoolWithTag(SenseBuffer
, TAG_SENSE_DATA
);
451 DPRINT("PortSendInquiry() done with Status 0x%08X\n", Status
);
461 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
)
463 PPDO_DEVICE_EXTENSION PdoExtension
;
464 ULONG Bus
, Target
; //, Lun;
467 DPRINT("PortFdoScanBus(%p)\n", DeviceExtension
);
469 DPRINT("NumberOfBuses: %lu\n", DeviceExtension
->Miniport
.PortConfig
.NumberOfBuses
);
470 DPRINT("MaximumNumberOfTargets: %lu\n", DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfTargets
);
471 DPRINT("MaximumNumberOfLogicalUnits: %lu\n", DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfLogicalUnits
);
474 for (Bus
= 0; Bus
< DeviceExtension
->Miniport
.PortConfig
.NumberOfBuses
; Bus
++)
476 DPRINT("Scanning bus %ld\n", Bus
);
478 /* Scan all targets */
479 for (Target
= 0; Target
< DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfTargets
; Target
++)
481 DPRINT(" Scanning target %ld:%ld\n", Bus
, Target
);
483 DPRINT(" Scanning logical unit %ld:%ld:%ld\n", Bus
, Target
, 0);
484 Status
= PortCreatePdo(DeviceExtension
, Bus
, Target
, 0, &PdoExtension
);
485 if (NT_SUCCESS(Status
))
488 Status
= PortSendInquiry(PdoExtension
);
489 DPRINT("PortSendInquiry returned 0x%08lx\n", Status
);
490 if (!NT_SUCCESS(Status
))
492 PortDeletePdo(PdoExtension
);
496 DPRINT("VendorId: %.8s\n", PdoExtension
->InquiryBuffer
->VendorId
);
497 DPRINT("ProductId: %.16s\n", PdoExtension
->InquiryBuffer
->ProductId
);
498 DPRINT("ProductRevisionLevel: %.4s\n", PdoExtension
->InquiryBuffer
->ProductRevisionLevel
);
499 DPRINT("VendorSpecific: %.20s\n", PdoExtension
->InquiryBuffer
->VendorSpecific
);
504 /* Scan all logical units */
505 for (Lun
= 1; Lun
< DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfLogicalUnits
; Lun
++)
507 DPRINT(" Scanning logical unit %ld:%ld:%ld\n", Bus
, Target
, Lun
);
508 Status
= PortSendInquiry(DeviceExtension
->Device
, Bus
, Target
, Lun
);
509 DPRINT("PortSendInquiry returned 0x%08lx\n", Status
);
510 if (!NT_SUCCESS(Status
))
517 DPRINT("PortFdoScanBus() done!\n");
519 return STATUS_SUCCESS
;
525 PortFdoQueryBusRelations(
526 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
,
527 _Out_ PULONG_PTR Information
)
529 NTSTATUS Status
= STATUS_SUCCESS
;;
531 DPRINT1("PortFdoQueryBusRelations(%p %p)\n",
532 DeviceExtension
, Information
);
534 Status
= PortFdoScanBus(DeviceExtension
);
536 DPRINT1("Units found: %lu\n", DeviceExtension
->PdoCount
);
546 PortFdoFilterRequirements(
547 PFDO_DEVICE_EXTENSION DeviceExtension
,
550 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
;
552 DPRINT1("PortFdoFilterRequirements(%p %p)\n", DeviceExtension
, Irp
);
554 /* Get the bus number and the slot number */
555 RequirementsList
=(PIO_RESOURCE_REQUIREMENTS_LIST
)Irp
->IoStatus
.Information
;
556 if (RequirementsList
!= NULL
)
558 DeviceExtension
->BusNumber
= RequirementsList
->BusNumber
;
559 DeviceExtension
->SlotNumber
= RequirementsList
->SlotNumber
;
562 return STATUS_SUCCESS
;
569 _In_ PDEVICE_OBJECT DeviceObject
,
572 PFDO_DEVICE_EXTENSION DeviceExtension
;
573 // PIO_STACK_LOCATION Stack;
574 ULONG_PTR Information
= 0;
575 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
577 DPRINT("PortFdoScsi(%p %p)\n", DeviceObject
, Irp
);
579 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
580 ASSERT(DeviceExtension
);
581 ASSERT(DeviceExtension
->ExtensionType
== FdoExtension
);
583 // Stack = IoGetCurrentIrpStackLocation(Irp);
586 Irp
->IoStatus
.Information
= Information
;
587 Irp
->IoStatus
.Status
= Status
;
588 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
597 _In_ PDEVICE_OBJECT DeviceObject
,
600 PFDO_DEVICE_EXTENSION DeviceExtension
;
601 PIO_STACK_LOCATION Stack
;
602 ULONG_PTR Information
= 0;
603 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
605 DPRINT1("PortFdoPnp(%p %p)\n",
608 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
609 ASSERT(DeviceExtension
);
610 ASSERT(DeviceExtension
->ExtensionType
== FdoExtension
);
612 Stack
= IoGetCurrentIrpStackLocation(Irp
);
614 switch (Stack
->MinorFunction
)
616 case IRP_MN_START_DEVICE
: /* 0x00 */
617 DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
618 Status
= PortFdoStartDevice(DeviceExtension
, Irp
);
621 case IRP_MN_QUERY_REMOVE_DEVICE
: /* 0x01 */
622 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
625 case IRP_MN_REMOVE_DEVICE
: /* 0x02 */
626 DPRINT1("IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
629 case IRP_MN_CANCEL_REMOVE_DEVICE
: /* 0x03 */
630 DPRINT1("IRP_MJ_PNP / IRP_MN_CANCEL_REMOVE_DEVICE\n");
633 case IRP_MN_STOP_DEVICE
: /* 0x04 */
634 DPRINT1("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
637 case IRP_MN_QUERY_STOP_DEVICE
: /* 0x05 */
638 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_STOP_DEVICE\n");
641 case IRP_MN_CANCEL_STOP_DEVICE
: /* 0x06 */
642 DPRINT1("IRP_MJ_PNP / IRP_MN_CANCEL_STOP_DEVICE\n");
645 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* 0x07 */
646 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
647 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
650 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
651 Status
= PortFdoQueryBusRelations(DeviceExtension
, &Information
);
654 case RemovalRelations
:
655 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
656 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
659 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
660 Stack
->Parameters
.QueryDeviceRelations
.Type
);
661 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
665 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* 0x0d */
666 DPRINT1("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
667 PortFdoFilterRequirements(DeviceExtension
, Irp
);
668 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
670 case IRP_MN_QUERY_PNP_DEVICE_STATE
: /* 0x14 */
671 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
674 case IRP_MN_DEVICE_USAGE_NOTIFICATION
: /* 0x16 */
675 DPRINT1("IRP_MJ_PNP / IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
678 case IRP_MN_SURPRISE_REMOVAL
: /* 0x17 */
679 DPRINT1("IRP_MJ_PNP / IRP_MN_SURPRISE_REMOVAL\n");
683 DPRINT1("IRP_MJ_PNP / Unknown IOCTL 0x%lx\n", Stack
->MinorFunction
);
684 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
687 Irp
->IoStatus
.Information
= Information
;
688 Irp
->IoStatus
.Status
= Status
;
689 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);