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 Status
= ForwardIrpAndWait(DeviceExtension
->LowerDevice
, Irp
);
195 if (!NT_SUCCESS(Status
))
197 DPRINT1("ForwardIrpAndWait() failed (Status 0x%08lx)\n", Status
);
202 /* Change to the 'started' state */
203 DeviceExtension
->PnpState
= dsStarted
;
205 /* Copy the raw and translated resource lists into the device extension */
206 if (Stack
->Parameters
.StartDevice
.AllocatedResources
!= NULL
&&
207 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
!= NULL
)
209 DeviceExtension
->AllocatedResources
= CopyResourceList(NonPagedPool
,
210 Stack
->Parameters
.StartDevice
.AllocatedResources
);
211 if (DeviceExtension
->AllocatedResources
== NULL
)
212 return STATUS_NO_MEMORY
;
214 DeviceExtension
->TranslatedResources
= CopyResourceList(NonPagedPool
,
215 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
216 if (DeviceExtension
->TranslatedResources
== NULL
)
217 return STATUS_NO_MEMORY
;
220 /* Get the bus interface of the lower (bus) device */
221 Status
= QueryBusInterface(DeviceExtension
->LowerDevice
,
222 (PGUID
)&GUID_BUS_INTERFACE_STANDARD
,
223 sizeof(BUS_INTERFACE_STANDARD
),
225 &DeviceExtension
->BusInterface
,
227 DPRINT1("Status: 0x%08lx\n", Status
);
228 if (NT_SUCCESS(Status
))
230 DPRINT1("Context: %p\n", DeviceExtension
->BusInterface
.Context
);
231 DeviceExtension
->BusInitialized
= TRUE
;
234 /* Start the miniport (FindAdapter & Initialize) */
235 Status
= PortFdoStartMiniport(DeviceExtension
);
236 if (!NT_SUCCESS(Status
))
238 DPRINT1("FdoStartMiniport() failed (Status 0x%08lx)\n", Status
);
239 DeviceExtension
->PnpState
= dsStopped
;
247 SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject
,
248 ULONG Bus
, ULONG Target
, ULONG Lun
)
250 // IO_STATUS_BLOCK IoStatusBlock;
251 // PIO_STACK_LOCATION IrpStack;
256 PINQUIRYDATA InquiryBuffer
;
257 PUCHAR
/*PSENSE_DATA*/ SenseBuffer
;
258 // BOOLEAN KeepTrying = TRUE;
259 // ULONG RetryCount = 0;
260 SCSI_REQUEST_BLOCK Srb
;
262 // PSCSI_PORT_LUN_EXTENSION LunExtension;
263 // PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
265 PFDO_DEVICE_EXTENSION DeviceExtension
;
266 PVOID SrbExtension
= NULL
;
269 DPRINT1("SpiSendInquiry() called\n");
271 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
273 InquiryBuffer
= ExAllocatePoolWithTag(NonPagedPool
, INQUIRYDATABUFFERSIZE
, TAG_INQUIRY_DATA
);
274 if (InquiryBuffer
== NULL
)
275 return STATUS_INSUFFICIENT_RESOURCES
;
277 SenseBuffer
= ExAllocatePoolWithTag(NonPagedPool
, SENSE_BUFFER_SIZE
, TAG_SENSE_DATA
);
278 if (SenseBuffer
== NULL
)
280 ExFreePoolWithTag(InquiryBuffer
, TAG_INQUIRY_DATA
);
281 return STATUS_INSUFFICIENT_RESOURCES
;
284 if (DeviceExtension
->Miniport
.PortConfig
.SrbExtensionSize
!= 0)
286 SrbExtension
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExtension
->Miniport
.PortConfig
.SrbExtensionSize
, TAG_SENSE_DATA
);
287 if (SrbExtension
== NULL
)
289 ExFreePoolWithTag(SenseBuffer
, TAG_SENSE_DATA
);
290 ExFreePoolWithTag(InquiryBuffer
, TAG_INQUIRY_DATA
);
291 return STATUS_INSUFFICIENT_RESOURCES
;
295 // while (KeepTrying)
297 /* Initialize event for waiting */
298 // KeInitializeEvent(&Event,
299 // NotificationEvent,
303 // Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
308 // INQUIRYDATABUFFERSIZE,
314 // DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
317 // Status = STATUS_INSUFFICIENT_RESOURCES;
318 // KeepTrying = FALSE;
323 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
325 Srb
.Length
= sizeof(SCSI_REQUEST_BLOCK
);
326 // Srb.OriginalRequest = Irp;
328 Srb
.TargetId
= Target
;
330 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
331 Srb
.SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
332 Srb
.TimeOutValue
= 4;
335 Srb
.SenseInfoBuffer
= SenseBuffer
;
336 Srb
.SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
338 Srb
.DataBuffer
= InquiryBuffer
;
339 Srb
.DataTransferLength
= INQUIRYDATABUFFERSIZE
;
341 Srb
.SrbExtension
= SrbExtension
;
343 /* Attach Srb to the Irp */
344 // IrpStack = IoGetNextIrpStackLocation(Irp);
345 // IrpStack->Parameters.Scsi.Srb = &Srb;
349 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_INQUIRY
;
350 Cdb
->CDB6INQUIRY
.LogicalUnitNumber
= Lun
;
351 Cdb
->CDB6INQUIRY
.AllocationLength
= INQUIRYDATABUFFERSIZE
;
353 /* Call the driver */
356 ret
= MiniportStartIo(&DeviceExtension
->Miniport
,
358 DPRINT1("MiniportStartIo returned %u\n", ret
);
360 // Status = IoCallDriver(DeviceObject, Irp);
362 /* Wait for it to complete */
363 // if (Status == STATUS_PENDING)
365 // DPRINT1("SpiSendInquiry(): Waiting for the driver to process request...\n");
366 // KeWaitForSingleObject(&Event,
371 // Status = IoStatusBlock.Status;
374 // DPRINT1("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
376 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_SUCCESS
)
378 /* All fine, copy data over */
379 // RtlCopyMemory(LunInfo->InquiryData,
381 // INQUIRYDATABUFFERSIZE);
384 Status
= STATUS_SUCCESS
;
385 // KeepTrying = FALSE;
389 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb
.SrbStatus
);
391 /* Check if the queue is frozen */
392 if (Srb
.SrbStatus
& SRB_STATUS_QUEUE_FROZEN
)
394 /* Something weird happened, deal with it (unfreeze the queue) */
397 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb
.TargetId
);
399 LunExtension
= SpiGetLunExtension(DeviceExtension
,
404 /* Clear frozen flag */
405 LunExtension
->Flags
&= ~LUNEX_FROZEN_QUEUE
;
407 /* Acquire the spinlock */
408 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &Irql
);
410 /* Process the request */
411 SpiGetNextRequestFromLun(DeviceObject
->DeviceExtension
, LunExtension
);
413 /* SpiGetNextRequestFromLun() releases the spinlock,
414 so we just lower irql back to what it was before */
418 /* Check if data overrun happened */
419 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
)
421 DPRINT("Data overrun at TargetId %d\n", LunInfo
->TargetId
);
423 /* Nothing dramatic, just copy data, but limiting the size */
424 RtlCopyMemory(LunInfo
->InquiryData
,
426 (Srb
.DataTransferLength
> INQUIRYDATABUFFERSIZE
) ?
427 INQUIRYDATABUFFERSIZE
: Srb
.DataTransferLength
);
430 Status
= STATUS_SUCCESS
;
433 else if ((Srb
.SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
434 SenseBuffer
->SenseKey
== SCSI_SENSE_ILLEGAL_REQUEST
)
436 /* LUN is not valid, but some device responds there.
437 Mark it as invalid anyway */
440 Status
= STATUS_INVALID_DEVICE_REQUEST
;
445 /* Retry a couple of times if no timeout happened */
446 if ((RetryCount
< 2) &&
447 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_NO_DEVICE
) &&
448 (SRB_STATUS(Srb
.SrbStatus
) != SRB_STATUS_SELECTION_TIMEOUT
))
455 /* That's all, quit the loop */
458 /* Set status according to SRB status */
459 if (SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_FUNCTION
||
460 SRB_STATUS(Srb
.SrbStatus
) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH
)
462 Status
= STATUS_INVALID_DEVICE_REQUEST
;
466 Status
= STATUS_IO_DEVICE_ERROR
;
474 if (SrbExtension
!= NULL
)
475 ExFreePoolWithTag(SrbExtension
, TAG_SENSE_DATA
);
477 ExFreePoolWithTag(SenseBuffer
, TAG_SENSE_DATA
);
478 ExFreePoolWithTag(InquiryBuffer
, TAG_INQUIRY_DATA
);
480 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status
);
489 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
)
491 ULONG Bus
, Target
, Lun
;
495 DPRINT1("PortFdoScanBus(%p)\n",
498 DPRINT1("NumberOfBuses: %lu\n", DeviceExtension
->Miniport
.PortConfig
.NumberOfBuses
);
499 DPRINT1("MaximumNumberOfTargets: %lu\n", DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfTargets
);
500 DPRINT1("MaximumNumberOfLogicalUnits: %lu\n", DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfLogicalUnits
);
503 for (Bus
= 0; Bus
< DeviceExtension
->Miniport
.PortConfig
.NumberOfBuses
; Bus
++)
505 DPRINT1("Scanning bus %ld\n", Bus
);
507 /* Scan all targets */
508 for (Target
= 0; Target
< DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfTargets
; Target
++)
510 DPRINT1(" Scanning target %ld:%ld\n", Bus
, Target
);
512 /* Scan all logical units */
513 for (Lun
= 0; Lun
< DeviceExtension
->Miniport
.PortConfig
.MaximumNumberOfLogicalUnits
; Lun
++)
515 DPRINT1(" Scanning logical unit %ld:%ld:%ld\n", Bus
, Target
, Lun
);
517 Status
= SpiSendInquiry(DeviceExtension
->Device
, Bus
, Target
, Lun
);
518 DPRINT1("SpiSendInquiry returned 0x%08lx\n", Status
);
525 return STATUS_SUCCESS
;
531 PortFdoQueryBusRelations(
532 _In_ PFDO_DEVICE_EXTENSION DeviceExtension
,
533 _Out_ PULONG_PTR Information
)
535 NTSTATUS Status
= STATUS_SUCCESS
;;
537 DPRINT1("PortFdoQueryBusRelations(%p %p)\n",
538 DeviceExtension
, Information
);
540 Status
= PortFdoScanBus(DeviceExtension
);
550 PortFdoFilterRequirements(
551 PFDO_DEVICE_EXTENSION DeviceExtension
,
554 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
;
556 DPRINT1("PortFdoFilterRequirements(%p %p)\n", DeviceExtension
, Irp
);
558 /* Get the bus number and the slot number */
559 RequirementsList
=(PIO_RESOURCE_REQUIREMENTS_LIST
)Irp
->IoStatus
.Information
;
560 if (RequirementsList
!= NULL
)
562 DeviceExtension
->BusNumber
= RequirementsList
->BusNumber
;
563 DeviceExtension
->SlotNumber
= RequirementsList
->SlotNumber
;
566 return STATUS_SUCCESS
;
573 _In_ PDEVICE_OBJECT DeviceObject
,
576 PFDO_DEVICE_EXTENSION DeviceExtension
;
577 // PIO_STACK_LOCATION Stack;
578 ULONG_PTR Information
= 0;
579 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
581 DPRINT1("PortFdoScsi(%p %p)\n",
584 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
585 ASSERT(DeviceExtension
);
586 ASSERT(DeviceExtension
->ExtensionType
== FdoExtension
);
588 // Stack = IoGetCurrentIrpStackLocation(Irp);
591 Irp
->IoStatus
.Information
= Information
;
592 Irp
->IoStatus
.Status
= Status
;
593 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
602 _In_ PDEVICE_OBJECT DeviceObject
,
605 PFDO_DEVICE_EXTENSION DeviceExtension
;
606 PIO_STACK_LOCATION Stack
;
607 ULONG_PTR Information
= 0;
608 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
610 DPRINT1("PortFdoPnp(%p %p)\n",
613 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
614 ASSERT(DeviceExtension
);
615 ASSERT(DeviceExtension
->ExtensionType
== FdoExtension
);
617 Stack
= IoGetCurrentIrpStackLocation(Irp
);
619 switch (Stack
->MinorFunction
)
621 case IRP_MN_START_DEVICE
: /* 0x00 */
622 DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
623 Status
= PortFdoStartDevice(DeviceExtension
, Irp
);
626 case IRP_MN_QUERY_REMOVE_DEVICE
: /* 0x01 */
627 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
630 case IRP_MN_REMOVE_DEVICE
: /* 0x02 */
631 DPRINT1("IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
634 case IRP_MN_CANCEL_REMOVE_DEVICE
: /* 0x03 */
635 DPRINT1("IRP_MJ_PNP / IRP_MN_CANCEL_REMOVE_DEVICE\n");
638 case IRP_MN_STOP_DEVICE
: /* 0x04 */
639 DPRINT1("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
642 case IRP_MN_QUERY_STOP_DEVICE
: /* 0x05 */
643 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_STOP_DEVICE\n");
646 case IRP_MN_CANCEL_STOP_DEVICE
: /* 0x06 */
647 DPRINT1("IRP_MJ_PNP / IRP_MN_CANCEL_STOP_DEVICE\n");
650 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* 0x07 */
651 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
652 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
655 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
656 Status
= PortFdoQueryBusRelations(DeviceExtension
, &Information
);
659 case RemovalRelations
:
660 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
661 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
664 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
665 Stack
->Parameters
.QueryDeviceRelations
.Type
);
666 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
670 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* 0x0d */
671 DPRINT1("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
672 PortFdoFilterRequirements(DeviceExtension
, Irp
);
673 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
675 case IRP_MN_QUERY_PNP_DEVICE_STATE
: /* 0x14 */
676 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
679 case IRP_MN_DEVICE_USAGE_NOTIFICATION
: /* 0x16 */
680 DPRINT1("IRP_MJ_PNP / IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
683 case IRP_MN_SURPRISE_REMOVAL
: /* 0x17 */
684 DPRINT1("IRP_MJ_PNP / IRP_MN_SURPRISE_REMOVAL\n");
688 DPRINT1("IRP_MJ_PNP / Unknown IOCTL 0x%lx\n", Stack
->MinorFunction
);
689 return ForwardIrpAndForget(DeviceExtension
->LowerDevice
, Irp
);
692 Irp
->IoStatus
.Information
= Information
;
693 Irp
->IoStatus
.Status
= Status
;
694 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);