3 * Copyright (C) 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: class2.c,v 1.11 2002/03/20 19:55:08 ekohl Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/class2/class2.c
24 * PURPOSE: SCSI class driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
33 /* INCLUDES *****************************************************************/
35 #include <ddk/ntddk.h>
36 #include "../include/scsi.h"
37 #include "../include/class2.h"
43 #define VERSION "0.0.1"
45 #define INQUIRY_DATA_SIZE 2048
48 static NTSTATUS STDCALL
49 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
52 static NTSTATUS STDCALL
53 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
56 static NTSTATUS STDCALL
57 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
60 static NTSTATUS STDCALL
61 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
64 static NTSTATUS STDCALL
65 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
69 /* FUNCTIONS ****************************************************************/
74 // This function initializes the driver.
80 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
82 // IN PUNICODE_STRING RegistryPath Name of registry driver service
89 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
90 IN PUNICODE_STRING RegistryPath
)
92 DbgPrint("Class Driver %s\n", VERSION
);
93 return(STATUS_SUCCESS
);
98 ScsiClassDebugPrint(IN ULONG DebugPrintLevel
,
99 IN PCHAR DebugMessage
,
106 if (DebugPrintLevel
> InternalDebugLevel
)
110 va_start(ap
, DebugMessage
);
111 vsprintf(Buffer
, DebugMessage
, ap
);
119 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject
,
128 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject
,
131 PDEVICE_EXTENSION DeviceExtension
;
132 PIO_STACK_LOCATION CurrentIrpStack
;
133 PIO_STACK_LOCATION NextIrpStack
;
134 LARGE_INTEGER StartingOffset
;
135 LARGE_INTEGER StartingBlock
;
136 PSCSI_REQUEST_BLOCK Srb
;
138 ULONG LogicalBlockAddress
;
139 USHORT TransferBlocks
;
141 DeviceExtension
= DeviceObject
->DeviceExtension
;
142 CurrentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
143 NextIrpStack
= IoGetNextIrpStackLocation(Irp
);
144 StartingOffset
= CurrentIrpStack
->Parameters
.Read
.ByteOffset
;
146 /* calculate logical block address */
147 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> DeviceExtension
->SectorShift
;
148 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
150 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
152 /* allocate and initialize an SRB */
153 /* FIXME: use lookaside list instead */
154 Srb
= ExAllocatePool(NonPagedPool
,
155 sizeof(SCSI_REQUEST_BLOCK
));
158 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
159 Srb
->OriginalRequest
= Irp
;
160 Srb
->PathId
= DeviceExtension
->PathId
;
161 Srb
->TargetId
= DeviceExtension
->TargetId
;
162 Srb
->Lun
= DeviceExtension
->Lun
;
163 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
164 Srb
->DataBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
165 Srb
->DataTransferLength
= CurrentIrpStack
->Parameters
.Read
.Length
;
166 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
167 Srb
->QueueSortKey
= LogicalBlockAddress
;
169 Srb
->SenseInfoBuffer
= DeviceExtension
->SenseData
;
170 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
173 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * DeviceExtension
->TimeOutValue
;
175 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
180 Cdb
= (PCDB
)Srb
->Cdb
;
182 /* Initialize ATAPI packet (12 bytes) */
186 Cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
187 TransferBlocks
= (USHORT
)(CurrentIrpStack
->Parameters
.Read
.Length
>> DeviceExtension
->SectorShift
);
189 /* Copy little endian values into CDB in big endian format */
190 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
191 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
192 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
193 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
195 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
196 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
199 if (CurrentIrpStack
->MajorFunction
== IRP_MJ_READ
)
201 DPRINT("ScsiClassBuildRequest: Read Command\n");
203 Srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
204 Cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
208 DPRINT("ScsiClassBuildRequest: Write Command\n");
210 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
211 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
216 /* if this is not a write-through request, then allow caching */
217 if (!(CurrentIrpStack
->Flags
& SL_WRITE_THROUGH
))
219 Srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
223 /* if write caching is enable then force media access in the cdb */
224 if (DeviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
)
226 Cdb
->CDB10
.ForceUnitAccess
= TRUE
;
231 /* or in the default flags from the device object. */
232 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
235 NextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
236 NextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
237 NextIrpStack
->DeviceObject
= DeviceObject
;
240 /* save retry count in current IRP stack */
241 CurrentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
244 DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp
, Srb
);
245 IoSetCompletionRoutine(Irp
,
255 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject
,
256 PSCSI_INQUIRY_DATA LunInfo
,
258 PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
)
260 PIO_STACK_LOCATION IoStack
;
261 IO_STATUS_BLOCK IoStatusBlock
;
262 SCSI_REQUEST_BLOCK Srb
;
267 DPRINT("ScsiClassClaimDevice() called\n");
269 if (NewPortDeviceObject
!= NULL
)
270 *NewPortDeviceObject
= NULL
;
272 /* initialize an SRB */
274 sizeof(SCSI_REQUEST_BLOCK
));
275 Srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
276 Srb
.PathId
= LunInfo
->PathId
;
277 Srb
.TargetId
= LunInfo
->TargetId
;
278 Srb
.Lun
= LunInfo
->Lun
;
280 (Release
== TRUE
) ? SRB_FUNCTION_RELEASE_DEVICE
: SRB_FUNCTION_CLAIM_DEVICE
;
282 KeInitializeEvent(&Event
,
286 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
297 DPRINT1("Failed to allocate Irp!\n");
298 return(STATUS_INSUFFICIENT_RESOURCES
);
301 /* Link Srb and Irp */
302 IoStack
= IoGetNextIrpStackLocation(Irp
);
303 IoStack
->Parameters
.Scsi
.Srb
= &Srb
;
304 Srb
.OriginalRequest
= Irp
;
306 /* Call SCSI port driver */
307 Status
= IoCallDriver(PortDeviceObject
,
309 if (Status
== STATUS_PENDING
)
311 KeWaitForSingleObject(&Event
,
316 Status
= IoStatusBlock
.Status
;
321 ObDereferenceObject(PortDeviceObject
);
322 return(STATUS_SUCCESS
);
325 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
326 Status
= ObReferenceObjectByPointer(PortDeviceObject
,
331 if (NewPortDeviceObject
!= NULL
)
333 // *NewPortDeviceObject = Srb.DataBuffer;
334 *NewPortDeviceObject
= PortDeviceObject
;
337 return(STATUS_SUCCESS
);
342 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
343 IN PCCHAR ObjectNameBuffer
,
344 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
345 IN OUT PDEVICE_OBJECT
*DeviceObject
,
346 IN PCLASS_INIT_DATA InitializationData
)
348 PDEVICE_OBJECT InternalDeviceObject
;
349 PDEVICE_EXTENSION DeviceExtension
;
350 ANSI_STRING AnsiName
;
351 UNICODE_STRING DeviceName
;
354 DPRINT("ScsiClassCreateDeviceObject() called\n");
356 *DeviceObject
= NULL
;
358 RtlInitAnsiString(&AnsiName
,
361 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
364 if (!NT_SUCCESS(Status
))
369 DPRINT("Device name: '%wZ'\n", &DeviceName
);
371 Status
= IoCreateDevice(DriverObject
,
372 InitializationData
->DeviceExtensionSize
,
374 InitializationData
->DeviceType
,
375 InitializationData
->DeviceCharacteristics
,
377 &InternalDeviceObject
);
378 if (NT_SUCCESS(Status
))
380 DeviceExtension
= InternalDeviceObject
->DeviceExtension
;
382 DeviceExtension
->ClassError
= InitializationData
->ClassError
;
383 DeviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
384 DeviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
385 DeviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
386 DeviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
387 DeviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
388 DeviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
390 DeviceExtension
->MediaChangeCount
= 0;
392 if (PhysicalDeviceObject
!= NULL
)
394 DeviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
398 DeviceExtension
->PhysicalDevice
= InternalDeviceObject
;
401 *DeviceObject
= InternalDeviceObject
;
404 RtlFreeUnicodeString(&DeviceName
);
411 ScsiClassDeviceControl(PDEVICE_OBJECT DeviceObject
,
419 ScsiClassFindModePage(PCHAR ModeSenseBuffer
,
429 ScsiClassFindUnclaimedDevices(PCLASS_INIT_DATA InitializationData
,
430 PSCSI_ADAPTER_BUS_INFO AdapterInformation
)
432 PSCSI_INQUIRY_DATA UnitInfo
;
433 PINQUIRYDATA InquiryData
;
436 ULONG UnclaimedDevices
= 0;
439 DPRINT("ScsiClassFindUnclaimedDevices() called!\n");
441 DPRINT("NumberOfBuses: %lu\n",AdapterInformation
->NumberOfBuses
);
442 Buffer
= (PUCHAR
)AdapterInformation
;
443 for (Bus
= 0; Bus
< (ULONG
)AdapterInformation
->NumberOfBuses
; Bus
++)
445 DPRINT("Searching bus %lu\n", Bus
);
447 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterInformation
->BusData
[Bus
].InquiryDataOffset
);
449 while (AdapterInformation
->BusData
[Bus
].InquiryDataOffset
)
451 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
453 DPRINT("Device: '%.8s'\n", InquiryData
->VendorId
);
455 if ((InitializationData
->ClassFindDeviceCallBack(InquiryData
) == TRUE
) &&
456 (UnitInfo
->DeviceClaimed
== FALSE
))
461 if (UnitInfo
->NextInquiryDataOffset
== 0)
464 UnitInfo
= (PSCSI_INQUIRY_DATA
) (Buffer
+ UnitInfo
->NextInquiryDataOffset
);
468 return(UnclaimedDevices
);
473 ScsiClassGetCapabilities(PDEVICE_OBJECT PortDeviceObject
,
474 PIO_SCSI_CAPABILITIES
*PortCapabilities
)
476 PIO_SCSI_CAPABILITIES Buffer
;
477 IO_STATUS_BLOCK IoStatusBlock
;
482 *PortCapabilities
= NULL
;
483 Buffer
= ExAllocatePool(NonPagedPool
,
484 sizeof(IO_SCSI_CAPABILITIES
));
487 return(STATUS_INSUFFICIENT_RESOURCES
);
490 KeInitializeEvent(&Event
,
494 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
499 sizeof(IO_SCSI_CAPABILITIES
),
506 return(STATUS_INSUFFICIENT_RESOURCES
);
509 Status
= IoCallDriver(PortDeviceObject
,
511 if (Status
== STATUS_PENDING
)
513 KeWaitForSingleObject(&Event
,
518 Status
= IoStatusBlock
.Status
;
521 if (!NT_SUCCESS(Status
))
527 *PortCapabilities
= Buffer
;
535 ScsiClassGetInquiryData(PDEVICE_OBJECT PortDeviceObject
,
536 PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
)
538 PSCSI_ADAPTER_BUS_INFO Buffer
;
539 IO_STATUS_BLOCK IoStatusBlock
;
544 DPRINT("ScsiClassGetInquiryData() called\n");
547 Buffer
= ExAllocatePool(NonPagedPool
,
551 return(STATUS_INSUFFICIENT_RESOURCES
);
554 KeInitializeEvent(&Event
,
558 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
570 return(STATUS_INSUFFICIENT_RESOURCES
);
573 Status
= IoCallDriver(PortDeviceObject
,
575 if (Status
== STATUS_PENDING
)
577 KeWaitForSingleObject(&Event
,
582 Status
= IoStatusBlock
.Status
;
585 if (!NT_SUCCESS(Status
))
591 *ConfigInfo
= Buffer
;
594 DPRINT("ScsiClassGetInquiryData() done\n");
601 ScsiClassInitialize(PVOID Argument1
,
603 PCLASS_INIT_DATA InitializationData
)
605 PCONFIGURATION_INFORMATION ConfigInfo
;
606 PDRIVER_OBJECT DriverObject
= Argument1
;
607 WCHAR NameBuffer
[80];
608 UNICODE_STRING PortName
;
610 PDEVICE_OBJECT PortDeviceObject
;
611 PFILE_OBJECT FileObject
;
612 BOOLEAN DiskFound
= FALSE
;
615 DPRINT("ScsiClassInitialize() called!\n");
617 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
618 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
619 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
620 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
621 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassScsiDispatch
;
622 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceDispatch
;
623 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
624 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
625 if (InitializationData
->ClassStartIo
)
627 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
630 ConfigInfo
= IoGetConfigurationInformation();
632 DPRINT("ScsiPorts: %lu\n", ConfigInfo
->ScsiPortCount
);
634 /* look for ScsiPortX scsi port devices */
635 for (PortNumber
= 0; PortNumber
< ConfigInfo
->ScsiPortCount
; PortNumber
++)
638 L
"\\Device\\ScsiPort%lu",
640 RtlInitUnicodeString(&PortName
,
642 DPRINT("Checking scsi port %ld\n", PortNumber
);
643 Status
= IoGetDeviceObjectPointer(&PortName
,
644 FILE_READ_ATTRIBUTES
,
647 DPRINT("Status 0x%08lX\n", Status
);
648 if (NT_SUCCESS(Status
))
650 DPRINT("ScsiPort%lu found.\n", PortNumber
);
652 /* check scsi port for attached disk drives */
653 if (InitializationData
->ClassFindDevices(DriverObject
,
664 DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber
, Status
);
668 DPRINT("ScsiClassInitialize() done!\n");
670 return((DiskFound
== TRUE
) ? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
);
675 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension
,
676 ULONG NumberElements
)
683 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject
,
691 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject
,
692 PSCSI_REQUEST_BLOCK Srb
,
693 UCHAR MajorFunctionCode
,
703 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject
,
707 PDEVICE_EXTENSION DeviceExtension
;
708 PIO_STACK_LOCATION IrpStack
;
709 PSCSI_REQUEST_BLOCK Srb
;
712 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
713 DeviceObject
, Irp
, Context
);
715 DeviceExtension
= DeviceObject
->DeviceExtension
;
716 Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
717 DPRINT("Srb %p\n", Srb
);
719 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
722 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
724 Status
= STATUS_SUCCESS
;
728 /* FIXME: improve error handling */
729 DPRINT1("Srb->SrbStatus %lx\n", Srb
->SrbStatus
);
731 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_PENDING
)
733 Status
= STATUS_SUCCESS
;
736 Status
= STATUS_UNSUCCESSFUL
;
740 /* FIXME: use lookaside list instead */
741 DPRINT("Freed SRB %p\n", IrpStack
->Parameters
.Scsi
.Srb
);
742 ExFreePool(IrpStack
->Parameters
.Scsi
.Srb
);
744 // Irp->IoStatus.Status = Status;
746 if (!NT_SUCCESS(Status
) &&
747 IoIsErrorUserInduced(Status
))
749 IoSetHardErrorOrVerifyDevice(Irp
,
751 Irp
->IoStatus
.Information
= 0;
754 if (Irp
->PendingReturned
)
756 IoMarkIrpPending(Irp
);
760 if (DeviceExtension
->ClassStartIo
!= NULL
)
762 if (IrpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
764 IoStartNextPacket(DeviceObject
,
769 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status
);
772 return(STATUS_SUCCESS
);
777 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject
,
786 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject
,
787 CHAR ModeSenseBuffer
,
796 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath
)
803 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject
)
805 PDEVICE_EXTENSION DeviceExtension
;
806 PREAD_CAPACITY_DATA CapacityBuffer
;
807 SCSI_REQUEST_BLOCK Srb
;
813 DPRINT("ScsiClassReadDriveCapacity() called\n");
815 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
817 CapacityBuffer
= ExAllocatePool(NonPagedPool
,
818 sizeof(READ_CAPACITY_DATA
));
819 if (CapacityBuffer
== NULL
)
821 return(STATUS_INSUFFICIENT_RESOURCES
);
824 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
827 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
830 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
833 Status
= ScsiClassSendSrbSynchronous(DeviceObject
,
836 sizeof(READ_CAPACITY_DATA
),
838 DPRINT("Status: %lx\n", Status
);
839 DPRINT("Srb: %p\n", &Srb
);
840 if (NT_SUCCESS(Status
))
842 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
843 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
844 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
845 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
848 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
849 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
850 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
851 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
853 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
855 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
856 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
,
857 DeviceExtension
->SectorShift
);
858 DeviceExtension
->PartitionLength
.QuadPart
=
859 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
861 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
863 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
867 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
869 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((LastSector
+ 1)/(32 * 64));
870 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
871 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
873 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize
, LastSector
+ 1);
876 ExFreePool(CapacityBuffer
);
878 DPRINT("ScsiClassReadDriveCapacity() done\n");
885 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject
)
892 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject
,
893 PSCSI_REQUEST_BLOCK Srb
,
897 BOOLEAN WriteToDevice
)
904 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject
,
905 PSCSI_REQUEST_BLOCK Srb
,
908 BOOLEAN WriteToDevice
)
910 PDEVICE_EXTENSION DeviceExtension
;
911 IO_STATUS_BLOCK IoStatusBlock
;
912 PIO_STACK_LOCATION IoStack
;
919 DPRINT("ScsiClassSendSrbSynchronous() called\n");
921 DeviceExtension
= DeviceObject
->DeviceExtension
;
923 Srb
->PathId
= DeviceExtension
->PathId
;
924 Srb
->TargetId
= DeviceExtension
->TargetId
;
925 Srb
->Lun
= DeviceExtension
->Lun
;
926 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
928 /* FIXME: more srb initialization required? */
931 if (BufferAddress
== NULL
)
934 RequestType
= IOCTL_SCSI_EXECUTE_NONE
;
935 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
939 if (WriteToDevice
== TRUE
)
941 RequestType
= IOCTL_SCSI_EXECUTE_OUT
;
942 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
946 RequestType
= IOCTL_SCSI_EXECUTE_IN
;
947 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
951 Srb
->DataTransferLength
= BufferLength
;
952 Srb
->DataBuffer
= BufferAddress
;
955 KeInitializeEvent(&Event
,
959 Irp
= IoBuildDeviceIoControlRequest(RequestType
,
960 DeviceExtension
->PortDeviceObject
,
970 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
971 return(STATUS_INSUFFICIENT_RESOURCES
);
974 /* FIXME: more irp initialization required? */
977 /* Attach Srb to the Irp */
978 IoStack
= IoGetNextIrpStackLocation(Irp
);
979 IoStack
->Parameters
.Scsi
.Srb
= Srb
;
980 Srb
->OriginalRequest
= Irp
;
983 /* Call the SCSI port driver */
984 Status
= IoCallDriver(DeviceExtension
->PortDeviceObject
,
986 if (Status
== STATUS_PENDING
)
988 KeWaitForSingleObject(&Event
,
995 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
)
998 DPRINT1("Fix return value!\n");
999 Status
= STATUS_UNSUCCESSFUL
;
1003 Status
= STATUS_SUCCESS
;
1006 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1013 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject
,
1021 /* INTERNAL FUNCTIONS *******************************************************/
1023 static NTSTATUS STDCALL
1024 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1027 PDEVICE_EXTENSION DeviceExtension
;
1029 DPRINT("ScsiClassCreateClose() called\n");
1031 DeviceExtension
= DeviceObject
->DeviceExtension
;
1033 if (DeviceExtension
->ClassCreateClose
)
1034 return(DeviceExtension
->ClassCreateClose(DeviceObject
,
1037 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1038 Irp
->IoStatus
.Information
= 0;
1039 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1041 return(STATUS_SUCCESS
);
1045 static NTSTATUS STDCALL
1046 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
1049 PDEVICE_EXTENSION DeviceExtension
;
1050 PIO_STACK_LOCATION IrpStack
;
1051 ULONG TransferLength
;
1052 ULONG TransferPages
;
1055 DPRINT("ScsiClassReadWrite() called\n");
1057 DeviceExtension
= DeviceObject
->DeviceExtension
;
1058 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1060 DPRINT("Relative Offset: %I64u Length: %lu\n",
1061 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
,
1062 IrpStack
->Parameters
.Read
.Length
);
1064 TransferLength
= IrpStack
->Parameters
.Read
.Length
;
1066 if ((DeviceObject
->Flags
& DO_VERIFY_VOLUME
) &&
1067 !(IrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
1069 IoSetHardErrorOrVerifyDevice(Irp
,
1072 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1073 Irp
->IoStatus
.Information
= 0;
1075 IoCompleteRequest(Irp
,
1077 return(STATUS_VERIFY_REQUIRED
);
1081 /* let the class driver perform its verification */
1082 Status
= DeviceExtension
->ClassReadWriteVerification(DeviceObject
,
1084 if (!NT_SUCCESS(Status
))
1086 IoCompleteRequest(Irp
,
1090 else if (Status
== STATUS_PENDING
)
1092 IoMarkIrpPending(Irp
);
1093 return(STATUS_PENDING
);
1097 /* Finish a zero-byte transfer. */
1098 if (TransferLength
== 0)
1100 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1101 Irp
->IoStatus
.Information
= 0;
1102 IoCompleteRequest(Irp
,
1104 return(STATUS_SUCCESS
);
1107 if (DeviceExtension
->ClassStartIo
!= NULL
)
1109 DPRINT("ScsiClassReadWrite() starting packet\n");
1111 IoMarkIrpPending(Irp
);
1112 IoStartPacket(DeviceObject
,
1117 return(STATUS_PENDING
);
1120 IoMarkIrpPending(Irp
);
1122 /* Adjust partition-relative starting offset to absolute offset */
1123 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= DeviceExtension
->StartingOffset
.QuadPart
;
1125 /* Calculate number of pages in this transfer. */
1126 TransferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1127 IrpStack
->Parameters
.Read
.Length
);
1130 if (TransferLength
> maximumTransferLength
||
1131 TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
)
1133 /* FIXME: split request */
1137 ScsiClassBuildRequest(DeviceObject
,
1140 DPRINT("ScsiClassReadWrite() done\n");
1142 /* Call the port driver */
1143 return(IoCallDriver(DeviceExtension
->PortDeviceObject
,
1148 static NTSTATUS STDCALL
1149 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
1152 DPRINT1("ScsiClassScsiDispatch() called\n");
1154 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1155 Irp
->IoStatus
.Information
= 0;
1156 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1158 return(STATUS_SUCCESS
);
1162 static NTSTATUS STDCALL
1163 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
1166 PDEVICE_EXTENSION DeviceExtension
;
1168 DPRINT("ScsiClassDeviceDispatch() called\n");
1170 DeviceExtension
= DeviceObject
->DeviceExtension
;
1171 if (DeviceExtension
->ClassDeviceControl
)
1173 return(DeviceExtension
->ClassDeviceControl(DeviceObject
, Irp
));
1176 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1177 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1179 return(STATUS_INVALID_DEVICE_REQUEST
);
1183 static NTSTATUS STDCALL
1184 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1187 PDEVICE_EXTENSION DeviceExtension
;
1189 DPRINT("ScsiClassShutdownFlush() called\n");
1191 DeviceExtension
= DeviceObject
->DeviceExtension
;
1192 if (DeviceExtension
->ClassShutdownFlush
)
1194 return(DeviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
));
1197 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1198 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1200 return(STATUS_INVALID_DEVICE_REQUEST
);