1 /* $Id: class2.c,v 1.4 2002/01/31 14:57:58 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/storage/class2/class2.c
6 * PURPOSE: SCSI class driver
7 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
15 /* INCLUDES *****************************************************************/
17 #include <ddk/ntddk.h>
18 #include "../include/scsi.h"
19 #include "../include/class2.h"
25 #define VERSION "0.0.1"
27 #define INQUIRY_DATA_SIZE 2048
30 static NTSTATUS STDCALL
31 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
34 static NTSTATUS STDCALL
35 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
38 static NTSTATUS STDCALL
39 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
42 static NTSTATUS STDCALL
43 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
46 static NTSTATUS STDCALL
47 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
51 /* FUNCTIONS ****************************************************************/
56 // This function initializes the driver.
62 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
64 // IN PUNICODE_STRING RegistryPath Name of registry driver service
71 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
72 IN PUNICODE_STRING RegistryPath
)
74 DbgPrint("Class Driver %s\n", VERSION
);
75 return(STATUS_SUCCESS
);
80 ScsiClassDebugPrint(IN ULONG DebugPrintLevel
,
81 IN PCHAR DebugMessage
,
88 if (DebugPrintLevel
> InternalDebugLevel
)
92 va_start(ap
, DebugMessage
);
93 vsprintf(Buffer
, DebugMessage
, ap
);
101 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject
,
110 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject
,
113 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
114 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
115 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
116 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
117 LARGE_INTEGER startingBlock
;
118 PSCSI_REQUEST_BLOCK Srb
;
120 ULONG logicalBlockAddress
;
121 USHORT transferBlocks
;
124 // Calculate relative sector address.
127 // logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift));
129 startingBlock
.QuadPart
= startingOffset
.QuadPart
>> deviceExtension
->SectorShift
;
130 logicalBlockAddress
= (ULONG
)startingBlock
.u
.LowPart
;
136 // Srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
137 Srb
= ExAllocatePool(NonPagedPool
,
138 sizeof(SCSI_REQUEST_BLOCK
));
144 // Write length to SRB.
147 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
150 // Set up IRP Address.
153 Srb
->OriginalRequest
= Irp
;
156 // Set up target ID and logical unit number.
159 Srb
->PathId
= deviceExtension
->PathId
;
160 Srb
->TargetId
= deviceExtension
->TargetId
;
161 Srb
->Lun
= deviceExtension
->Lun
;
162 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
163 Srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
166 // Save byte count of transfer in SRB Extension.
169 Srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
172 // Initialize the queue actions field.
175 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
178 // Queue sort key is Relative Block Address.
181 Srb
->QueueSortKey
= logicalBlockAddress
;
184 // Indicate auto request sense by specifying buffer and size.
187 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
188 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
191 // Set timeout value of one unit per 64k bytes of data.
194 Srb
->TimeOutValue
= ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) *
195 deviceExtension
->TimeOutValue
;
206 // Indicate that 10-byte CDB's will be used.
212 // Fill in CDB fields.
215 Cdb
= (PCDB
)Srb
->Cdb
;
218 // Zero 12 bytes for Atapi Packets
224 Cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
225 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
228 // Move little endian values into CDB in big endian format.
231 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
232 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
233 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
234 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
236 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
237 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
240 // Set transfer direction flag and Cdb command.
243 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
)
245 DPRINT1("ScsiClassBuildRequest: Read Command\n");
247 Srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
248 Cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
252 DPRINT("ScsiClassBuildRequest: Write Command\n");
254 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
255 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
259 // If this is not a write-through request, then allow caching.
263 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
))
265 Srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
269 /* If write caching is enable then force media access in the cdb. */
270 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
)
272 Cdb
->CDB10
.ForceUnitAccess
= TRUE
;
277 /* Or in the default flags from the device object. */
278 Srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
281 // Set up major SCSI function.
284 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
287 // Save SRB address in next stack for port driver.
290 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
293 // Save retry count in current IRP stack.
296 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
299 /* Set up IoCompletion routine address. */
300 IoSetCompletionRoutine(Irp
,
310 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject
,
311 PSCSI_INQUIRY_DATA LunInfo
,
313 PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
)
315 PIO_STACK_LOCATION IoStack
;
316 IO_STATUS_BLOCK IoStatusBlock
;
317 SCSI_REQUEST_BLOCK Srb
;
322 DPRINT1("ScsiClassClaimDevice() called\n");
324 if (NewPortDeviceObject
!= NULL
)
325 *NewPortDeviceObject
= NULL
;
327 /* Initialize an SRB */
329 sizeof(SCSI_REQUEST_BLOCK
));
330 Srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
331 Srb
.PathId
= LunInfo
->PathId
;
332 Srb
.TargetId
= LunInfo
->TargetId
;
333 Srb
.Lun
= LunInfo
->Lun
;
335 (Release
== TRUE
) ? SRB_FUNCTION_RELEASE_DEVICE
: SRB_FUNCTION_CLAIM_DEVICE
;
337 KeInitializeEvent(&Event
,
341 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
352 DPRINT1("Failed to allocate Irp!\n");
353 return(STATUS_INSUFFICIENT_RESOURCES
);
356 /* Link Srb and Irp */
357 IoStack
= IoGetNextIrpStackLocation(Irp
);
358 IoStack
->Parameters
.Scsi
.Srb
= &Srb
;
359 Srb
.OriginalRequest
= Irp
;
361 /* Call SCSI port driver */
362 Status
= IoCallDriver(PortDeviceObject
,
364 if (Status
== STATUS_PENDING
)
366 KeWaitForSingleObject(&Event
,
371 Status
= IoStatusBlock
.Status
;
376 ObDereferenceObject(PortDeviceObject
);
377 return(STATUS_SUCCESS
);
380 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
381 Status
= ObReferenceObjectByPointer(PortDeviceObject
,
386 if (NewPortDeviceObject
!= NULL
)
388 // *NewPortDeviceObject = Srb.DataBuffer;
389 *NewPortDeviceObject
= PortDeviceObject
;
392 return(STATUS_SUCCESS
);
397 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
398 IN PCCHAR ObjectNameBuffer
,
399 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
400 IN OUT PDEVICE_OBJECT
*DeviceObject
,
401 IN PCLASS_INIT_DATA InitializationData
)
403 PDEVICE_OBJECT InternalDeviceObject
;
404 PDEVICE_EXTENSION DeviceExtension
;
405 ANSI_STRING AnsiName
;
406 UNICODE_STRING DeviceName
;
409 DPRINT1("ScsiClassCreateDeviceObject() called\n");
411 *DeviceObject
= NULL
;
413 RtlInitAnsiString(&AnsiName
,
416 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
419 if (!NT_SUCCESS(Status
))
424 DPRINT1("Device name: '%wZ'\n", &DeviceName
);
426 Status
= IoCreateDevice(DriverObject
,
427 InitializationData
->DeviceExtensionSize
,
429 InitializationData
->DeviceType
,
430 InitializationData
->DeviceCharacteristics
,
432 &InternalDeviceObject
);
433 if (NT_SUCCESS(Status
))
435 PDEVICE_EXTENSION deviceExtension
= InternalDeviceObject
->DeviceExtension
;
437 DeviceExtension
->ClassError
= InitializationData
->ClassError
;
438 DeviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
439 DeviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
440 DeviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
441 DeviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
442 DeviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
443 DeviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
445 DeviceExtension
->MediaChangeCount
= 0;
447 if (PhysicalDeviceObject
!= NULL
)
449 DeviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
453 DeviceExtension
->PhysicalDevice
= InternalDeviceObject
;
456 *DeviceObject
= InternalDeviceObject
;
459 RtlFreeUnicodeString(&DeviceName
);
466 ScsiClassDeviceControl(PDEVICE_OBJECT DeviceObject
,
474 ScsiClassFindModePage(PCHAR ModeSenseBuffer
,
484 ScsiClassFindUnclaimedDevices(PCLASS_INIT_DATA InitializationData
,
485 PSCSI_ADAPTER_BUS_INFO AdapterInformation
)
487 PSCSI_INQUIRY_DATA UnitInfo
;
488 PINQUIRYDATA InquiryData
;
491 ULONG UnclaimedDevices
= 0;
494 DPRINT("ScsiClassFindUnclaimedDevices() called!\n");
496 DPRINT("NumberOfBuses: %lu\n",AdapterInformation
->NumberOfBuses
);
497 Buffer
= (PUCHAR
)AdapterInformation
;
498 for (Bus
= 0; Bus
< (ULONG
)AdapterInformation
->NumberOfBuses
; Bus
++)
500 DPRINT("Searching bus %lu\n", Bus
);
502 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterInformation
->BusData
[Bus
].InquiryDataOffset
);
504 while (AdapterInformation
->BusData
[Bus
].InquiryDataOffset
)
506 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
508 DPRINT("Device: '%.8s'\n", InquiryData
->VendorId
);
510 if ((InitializationData
->ClassFindDeviceCallBack(InquiryData
) == TRUE
) &&
511 (UnitInfo
->DeviceClaimed
== FALSE
))
516 if (UnitInfo
->NextInquiryDataOffset
== 0)
519 UnitInfo
= (PSCSI_INQUIRY_DATA
) (Buffer
+ UnitInfo
->NextInquiryDataOffset
);
523 return(UnclaimedDevices
);
528 ScsiClassGetCapabilities(PDEVICE_OBJECT PortDeviceObject
,
529 PIO_SCSI_CAPABILITIES
*PortCapabilities
)
531 PIO_SCSI_CAPABILITIES Buffer
;
532 IO_STATUS_BLOCK IoStatusBlock
;
537 *PortCapabilities
= NULL
;
538 Buffer
= ExAllocatePool(NonPagedPool
, /* FIXME: use paged pool */
539 sizeof(IO_SCSI_CAPABILITIES
));
542 return(STATUS_INSUFFICIENT_RESOURCES
);
545 KeInitializeEvent(&Event
,
549 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
554 sizeof(IO_SCSI_CAPABILITIES
),
561 return(STATUS_INSUFFICIENT_RESOURCES
);
564 Status
= IoCallDriver(PortDeviceObject
,
566 if (Status
== STATUS_PENDING
)
568 KeWaitForSingleObject(&Event
,
573 Status
= IoStatusBlock
.Status
;
576 if (!NT_SUCCESS(Status
))
582 *PortCapabilities
= Buffer
;
590 ScsiClassGetInquiryData(PDEVICE_OBJECT PortDeviceObject
,
591 PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
)
593 PSCSI_ADAPTER_BUS_INFO Buffer
;
594 IO_STATUS_BLOCK IoStatusBlock
;
600 Buffer
= ExAllocatePool(NonPagedPool
,
604 return(STATUS_INSUFFICIENT_RESOURCES
);
607 KeInitializeEvent(&Event
,
611 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
623 return(STATUS_INSUFFICIENT_RESOURCES
);
626 Status
= IoCallDriver(PortDeviceObject
,
628 if (Status
== STATUS_PENDING
)
630 KeWaitForSingleObject(&Event
,
635 Status
= IoStatusBlock
.Status
;
638 if (!NT_SUCCESS(Status
))
644 *ConfigInfo
= Buffer
;
652 ScsiClassInitialize(PVOID Argument1
,
654 PCLASS_INIT_DATA InitializationData
)
656 PCONFIGURATION_INFORMATION ConfigInfo
;
657 PDRIVER_OBJECT DriverObject
= Argument1
;
658 WCHAR NameBuffer
[80];
659 UNICODE_STRING PortName
;
661 PDEVICE_OBJECT PortDeviceObject
;
662 PFILE_OBJECT FileObject
;
663 BOOLEAN DiskFound
= FALSE
;
666 DPRINT("ScsiClassInitialize() called!\n");
668 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
669 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
670 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
671 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
672 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassScsiDispatch
;
673 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceDispatch
;
674 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
675 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
676 if (InitializationData
->ClassStartIo
)
678 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
681 ConfigInfo
= IoGetConfigurationInformation();
683 /* look for ScsiPortX scsi port devices */
684 for (PortNumber
= 0; PortNumber
< ConfigInfo
->ScsiPortCount
; PortNumber
++)
687 L
"\\Device\\ScsiPort%lu",
689 RtlInitUnicodeString(&PortName
,
691 DPRINT("Checking scsi port %ld\n", PortNumber
);
692 Status
= IoGetDeviceObjectPointer(&PortName
,
693 FILE_READ_ATTRIBUTES
,
696 DPRINT("Status 0x%08lX\n", Status
);
697 if (NT_SUCCESS(Status
))
699 DPRINT1("ScsiPort%lu found.\n", PortNumber
);
701 /* Check scsi port for attached disk drives */
702 if (InitializationData
->ClassFindDevices(DriverObject
,
713 DPRINT("ScsiClassInitialize() done!\n");
716 return((DiskFound
== TRUE
) ? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
);
721 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension
,
722 ULONG NumberElements
)
729 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject
,
737 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject
,
738 PSCSI_REQUEST_BLOCK Srb
,
739 UCHAR MajorFunctionCode
,
749 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject
,
753 DPRINT1("ScsiClassIoComplete() called\n");
755 if (Irp
->PendingReturned
)
757 IoMarkIrpPending(Irp
);
760 return(Irp
->IoStatus
.Status
);
765 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject
,
774 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject
,
775 CHAR ModeSenseBuffer
,
784 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath
)
791 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject
)
793 PDEVICE_EXTENSION DeviceExtension
;
794 PREAD_CAPACITY_DATA CapacityBuffer
;
795 SCSI_REQUEST_BLOCK Srb
;
801 DPRINT1("ScsiClassReadDriveCapacity() called\n");
803 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
805 CapacityBuffer
= ExAllocatePool(NonPagedPool
, //NonPagedPoolCacheAligned,
806 sizeof(READ_CAPACITY_DATA
));
807 if (CapacityBuffer
== NULL
)
809 return(STATUS_INSUFFICIENT_RESOURCES
);
812 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
815 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
818 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
821 Status
= ScsiClassSendSrbSynchronous(DeviceObject
,
824 sizeof(READ_CAPACITY_DATA
),
826 DPRINT("Status: %lx\n", Status
);
827 DPRINT("Srb: %p\n", &Srb
);
828 if (NT_SUCCESS(Status
))
830 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
831 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
832 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
833 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
836 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
837 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
838 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
839 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
841 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
843 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
844 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
, DeviceExtension
->SectorShift
);
845 DeviceExtension
->PartitionLength
.QuadPart
=
846 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
848 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
850 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
854 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
856 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((LastSector
+ 1)/(32 * 64));
857 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
858 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
860 DPRINT1("SectorSize: %lu SectorCount: %lu\n", SectorSize
, LastSector
+ 1);
863 ExFreePool(CapacityBuffer
);
865 DPRINT1("ScsiClassReadDriveCapacity() done\n");
872 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject
)
879 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject
,
880 PSCSI_REQUEST_BLOCK Srb
,
884 BOOLEAN WriteToDevice
)
891 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject
,
892 PSCSI_REQUEST_BLOCK Srb
,
895 BOOLEAN WriteToDevice
)
897 PDEVICE_EXTENSION DeviceExtension
;
898 IO_STATUS_BLOCK IoStatusBlock
;
899 PIO_STACK_LOCATION IoStack
;
906 DPRINT1("ScsiClassSendSrbSynchronous() called\n");
908 DeviceExtension
= DeviceObject
->DeviceExtension
;
910 Srb
->PathId
= DeviceExtension
->PathId
;
911 Srb
->TargetId
= DeviceExtension
->TargetId
;
912 Srb
->Lun
= DeviceExtension
->Lun
;
913 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
915 /* FIXME: more srb initialization required? */
918 if (BufferAddress
== NULL
)
921 RequestType
= IOCTL_SCSI_EXECUTE_NONE
;
922 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
926 if (WriteToDevice
== TRUE
)
928 RequestType
= IOCTL_SCSI_EXECUTE_OUT
;
929 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
933 RequestType
= IOCTL_SCSI_EXECUTE_IN
;
934 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
938 Srb
->DataTransferLength
= BufferLength
;
939 Srb
->DataBuffer
= BufferAddress
;
942 KeInitializeEvent(&Event
,
946 Irp
= IoBuildDeviceIoControlRequest(RequestType
,
947 DeviceExtension
->PortDeviceObject
,
957 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
958 return(STATUS_INSUFFICIENT_RESOURCES
);
961 /* FIXME: more irp initialization required? */
964 /* Attach Srb to the Irp */
965 IoStack
= IoGetNextIrpStackLocation(Irp
);
966 IoStack
->Parameters
.Scsi
.Srb
= Srb
;
967 Srb
->OriginalRequest
= Irp
;
970 /* Call the SCSI port driver */
971 Status
= IoCallDriver(DeviceExtension
->PortDeviceObject
,
973 if (Status
== STATUS_PENDING
)
975 KeWaitForSingleObject(&Event
,
982 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
)
988 Status
= STATUS_SUCCESS
;
991 DPRINT1("ScsiClassSendSrbSynchronous() done\n");
998 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject
,
1006 /* INTERNAL FUNCTIONS *******************************************************/
1008 static NTSTATUS STDCALL
1009 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1012 PDEVICE_EXTENSION DeviceExtension
;
1014 DPRINT("ScsiClassCreateClose() called\n");
1016 DeviceExtension
= DeviceObject
->DeviceExtension
;
1018 if (DeviceExtension
->ClassCreateClose
)
1019 return(DeviceExtension
->ClassCreateClose(DeviceObject
,
1022 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1023 Irp
->IoStatus
.Information
= 0;
1024 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1026 return(STATUS_SUCCESS
);
1030 static NTSTATUS STDCALL
1031 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
1034 PDEVICE_EXTENSION DeviceExtension
;
1035 PIO_STACK_LOCATION IrpStack
;
1036 ULONG TransferLength
;
1037 ULONG TransferPages
;
1040 DPRINT1("ScsiClassReadWrite() called\n");
1042 DeviceExtension
= DeviceObject
->DeviceExtension
;
1043 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1045 TransferLength
= IrpStack
->Parameters
.Read
.Length
;
1049 if ((DeviceObject
->Flags
& DO_VERIFY_VOLUME
) &&
1050 !(IrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
1052 IoSetHardErrorOrVerifyDevice(Irp
,
1055 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1056 Irp
->IoStatus
.Information
= 0;
1058 IoCompleteRequest(Irp
,
1060 return(STATUS_VERIFY_REQUIRED
);
1064 /* let the class driver perform its verification */
1065 Status
= DeviceExtension
->ClassReadWriteVerification(DeviceObject
,
1067 if (!NT_SUCCESS(Status
))
1069 IoCompleteRequest(Irp
,
1073 else if (Status
== STATUS_PENDING
)
1075 IoMarkIrpPending(Irp
);
1076 return(STATUS_PENDING
);
1080 /* Finish a zero-byte transfer. */
1081 if (TransferLength
== 0)
1083 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1084 Irp
->IoStatus
.Information
= 0;
1085 IoCompleteRequest(Irp
,
1087 return(STATUS_SUCCESS
);
1090 if (DeviceExtension
->ClassStartIo
!= NULL
)
1092 IoMarkIrpPending(Irp
);
1093 IoStartPacket(DeviceObject
,
1098 return(STATUS_PENDING
);
1101 IoMarkIrpPending(Irp
);
1103 /* Adjust partition-relative starting offset to absolute offset */
1104 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= DeviceExtension
->StartingOffset
.QuadPart
;
1106 /* Calculate number of pages in this transfer. */
1107 TransferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1108 IrpStack
->Parameters
.Read
.Length
);
1111 if (IrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
1112 TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
)
1118 ScsiClassBuildRequest(DeviceObject
,
1121 DPRINT1("ScsiClassReadWrite() done\n");
1123 /* Call the port driver */
1124 return(IoCallDriver(DeviceExtension
->PortDeviceObject
,
1129 static NTSTATUS STDCALL
1130 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
1133 DPRINT1("ScsiClassScsiDispatch() called\n");
1135 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1136 Irp
->IoStatus
.Information
= 0;
1137 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1139 return(STATUS_SUCCESS
);
1143 static NTSTATUS STDCALL
1144 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
1147 DPRINT1("ScsiClassDeviceDispatch() called\n");
1149 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1150 Irp
->IoStatus
.Information
= 0;
1151 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1153 return(STATUS_SUCCESS
);
1157 static NTSTATUS STDCALL
1158 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1161 DPRINT1("ScsiClassShutdownFlush() called\n");
1163 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1164 Irp
->IoStatus
.Information
= 0;
1165 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1167 return(STATUS_SUCCESS
);