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.14 2002/03/25 21:55:51 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 TAG_SRBT TAG('S', 'r', 'b', 'T')
47 #define INQUIRY_DATA_SIZE 2048
50 static NTSTATUS STDCALL
51 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
54 static NTSTATUS STDCALL
55 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
58 static NTSTATUS STDCALL
59 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
62 static NTSTATUS STDCALL
63 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
66 static NTSTATUS STDCALL
67 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
71 /* FUNCTIONS ****************************************************************/
76 // This function initializes the driver.
82 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
84 // IN PUNICODE_STRING RegistryPath Name of registry driver service
91 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
92 IN PUNICODE_STRING RegistryPath
)
94 DbgPrint("Class Driver %s\n", VERSION
);
95 return(STATUS_SUCCESS
);
100 ScsiClassDebugPrint(IN ULONG DebugPrintLevel
,
101 IN PCHAR DebugMessage
,
108 if (DebugPrintLevel
> InternalDebugLevel
)
112 va_start(ap
, DebugMessage
);
113 vsprintf(Buffer
, DebugMessage
, ap
);
121 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject
,
130 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject
,
133 PDEVICE_EXTENSION DeviceExtension
;
134 PIO_STACK_LOCATION CurrentIrpStack
;
135 PIO_STACK_LOCATION NextIrpStack
;
136 LARGE_INTEGER StartingOffset
;
137 LARGE_INTEGER StartingBlock
;
138 PSCSI_REQUEST_BLOCK Srb
;
140 ULONG LogicalBlockAddress
;
141 USHORT TransferBlocks
;
143 DeviceExtension
= DeviceObject
->DeviceExtension
;
144 CurrentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
145 NextIrpStack
= IoGetNextIrpStackLocation(Irp
);
146 StartingOffset
= CurrentIrpStack
->Parameters
.Read
.ByteOffset
;
148 /* Calculate logical block address */
149 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> DeviceExtension
->SectorShift
;
150 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
152 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
154 /* Allocate and initialize an SRB */
155 /* FIXME: use lookaside list instead */
156 Srb
= ExAllocatePool(NonPagedPool
,
157 sizeof(SCSI_REQUEST_BLOCK
));
160 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
161 Srb
->OriginalRequest
= Irp
;
162 Srb
->PathId
= DeviceExtension
->PathId
;
163 Srb
->TargetId
= DeviceExtension
->TargetId
;
164 Srb
->Lun
= DeviceExtension
->Lun
;
165 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
166 Srb
->DataBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
167 Srb
->DataTransferLength
= CurrentIrpStack
->Parameters
.Read
.Length
;
168 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
169 Srb
->QueueSortKey
= LogicalBlockAddress
;
171 Srb
->SenseInfoBuffer
= DeviceExtension
->SenseData
;
172 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
175 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * DeviceExtension
->TimeOutValue
;
177 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
182 Cdb
= (PCDB
)Srb
->Cdb
;
184 /* Initialize ATAPI packet (12 bytes) */
188 Cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
189 TransferBlocks
= (USHORT
)(CurrentIrpStack
->Parameters
.Read
.Length
>> DeviceExtension
->SectorShift
);
191 /* Copy little endian values into CDB in big endian format */
192 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
193 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
194 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
195 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
197 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
198 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
201 if (CurrentIrpStack
->MajorFunction
== IRP_MJ_READ
)
203 DPRINT("ScsiClassBuildRequest: Read Command\n");
205 Srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
206 Cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
210 DPRINT("ScsiClassBuildRequest: Write Command\n");
212 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
213 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
218 /* if this is not a write-through request, then allow caching */
219 if (!(CurrentIrpStack
->Flags
& SL_WRITE_THROUGH
))
221 Srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
225 /* if write caching is enable then force media access in the cdb */
226 if (DeviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
)
228 Cdb
->CDB10
.ForceUnitAccess
= TRUE
;
233 /* Update srb flags */
234 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
237 NextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
238 NextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
239 NextIrpStack
->DeviceObject
= DeviceObject
;
241 /* Save retry count in current IRP stack */
242 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
);
674 /**********************************************************************
676 * ScsiClassInitializeSrbLookasideList
679 * Initializes a lookaside list for SRBs.
686 * Class specific device extension.
689 * Maximum number of elements of the lookaside list.
696 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension
,
697 ULONG NumberElements
)
699 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
703 sizeof(SCSI_REQUEST_BLOCK
),
705 (USHORT
)NumberElements
);
710 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject
,
718 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject
,
719 PSCSI_REQUEST_BLOCK Srb
,
720 UCHAR MajorFunctionCode
,
726 DPRINT1("ScsiClassInterpretSenseInfo() called\n");
728 DPRINT1("Srb->SrbStatus %lx\n", Srb
->SrbStatus
);
730 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_PENDING
)
732 *Status
= STATUS_SUCCESS
;
736 *Status
= STATUS_UNSUCCESSFUL
;
739 DPRINT1("ScsiClassInterpretSenseInfo() done\n");
746 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject
,
750 PDEVICE_EXTENSION DeviceExtension
;
751 PIO_STACK_LOCATION IrpStack
;
752 PSCSI_REQUEST_BLOCK Srb
;
756 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
757 DeviceObject
, Irp
, Context
);
759 DeviceExtension
= DeviceObject
->DeviceExtension
;
760 Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
761 DPRINT("Srb %p\n", Srb
);
763 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
765 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
767 Status
= STATUS_SUCCESS
;
771 Retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
773 IrpStack
->MajorFunction
,
775 MAXIMUM_RETRIES
- ((ULONG
)IrpStack
->Parameters
.Others
.Argument4
),
778 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
785 DPRINT1("Should try again!\n");
790 /* FIXME: use lookaside list instead */
791 DPRINT("Freed SRB %p\n", IrpStack
->Parameters
.Scsi
.Srb
);
792 ExFreePool(IrpStack
->Parameters
.Scsi
.Srb
);
794 Irp
->IoStatus
.Status
= Status
;
796 if (!NT_SUCCESS(Status
) &&
797 IoIsErrorUserInduced(Status
))
799 IoSetHardErrorOrVerifyDevice(Irp
,
801 Irp
->IoStatus
.Information
= 0;
804 if (Irp
->PendingReturned
)
806 IoMarkIrpPending(Irp
);
810 if (DeviceExtension
->ClassStartIo
!= NULL
)
812 if (IrpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
814 IoStartNextPacket(DeviceObject
,
819 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status
);
826 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject
,
835 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject
,
836 CHAR ModeSenseBuffer
,
845 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath
)
852 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject
)
854 PDEVICE_EXTENSION DeviceExtension
;
855 PREAD_CAPACITY_DATA CapacityBuffer
;
856 SCSI_REQUEST_BLOCK Srb
;
862 DPRINT("ScsiClassReadDriveCapacity() called\n");
864 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
866 CapacityBuffer
= ExAllocatePool(NonPagedPool
,
867 sizeof(READ_CAPACITY_DATA
));
868 if (CapacityBuffer
== NULL
)
870 return(STATUS_INSUFFICIENT_RESOURCES
);
873 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
876 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
879 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
882 Status
= ScsiClassSendSrbSynchronous(DeviceObject
,
885 sizeof(READ_CAPACITY_DATA
),
887 DPRINT("Status: %lx\n", Status
);
888 DPRINT("Srb: %p\n", &Srb
);
889 if (NT_SUCCESS(Status
))
891 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
892 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
893 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
894 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
897 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
898 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
899 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
900 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
902 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
904 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
905 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
,
906 DeviceExtension
->SectorShift
);
907 DeviceExtension
->PartitionLength
.QuadPart
=
908 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
910 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
912 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
916 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
918 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((LastSector
+ 1)/(32 * 64));
919 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
920 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
922 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize
, LastSector
+ 1);
926 /* Use default values if disk geometry cannot be read */
927 RtlZeroMemory(&DeviceExtension
->DiskGeometry
,
928 sizeof(DISK_GEOMETRY
));
929 DeviceExtension
->DiskGeometry
->BytesPerSector
= 512;
930 DeviceExtension
->SectorShift
= 9;
931 DeviceExtension
->PartitionLength
.QuadPart
= 0;
933 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
935 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
939 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
943 ExFreePool(CapacityBuffer
);
945 DPRINT("ScsiClassReadDriveCapacity() done\n");
952 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject
)
959 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject
,
960 PSCSI_REQUEST_BLOCK Srb
,
964 BOOLEAN WriteToDevice
)
971 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject
,
972 PSCSI_REQUEST_BLOCK Srb
,
975 BOOLEAN WriteToDevice
)
977 PDEVICE_EXTENSION DeviceExtension
;
978 IO_STATUS_BLOCK IoStatusBlock
;
979 PIO_STACK_LOCATION IoStack
;
988 DPRINT("ScsiClassSendSrbSynchronous() called\n");
990 RetryCount
= MAXIMUM_RETRIES
;
991 DeviceExtension
= DeviceObject
->DeviceExtension
;
993 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
994 Srb
->PathId
= DeviceExtension
->PathId
;
995 Srb
->TargetId
= DeviceExtension
->TargetId
;
996 Srb
->Lun
= DeviceExtension
->Lun
;
997 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
999 /* FIXME: more srb initialization required? */
1001 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1002 Srb
->SenseInfoBuffer
= ExAllocatePool(NonPagedPool
,
1004 if (Srb
->SenseInfoBuffer
== NULL
)
1005 return(STATUS_INSUFFICIENT_RESOURCES
);
1007 if (BufferAddress
== NULL
)
1010 RequestType
= IOCTL_SCSI_EXECUTE_NONE
;
1011 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1015 if (WriteToDevice
== TRUE
)
1017 RequestType
= IOCTL_SCSI_EXECUTE_OUT
;
1018 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
1022 RequestType
= IOCTL_SCSI_EXECUTE_IN
;
1023 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
1027 Srb
->DataTransferLength
= BufferLength
;
1028 Srb
->DataBuffer
= BufferAddress
;
1031 KeInitializeEvent(&Event
,
1035 Irp
= IoBuildDeviceIoControlRequest(RequestType
,
1036 DeviceExtension
->PortDeviceObject
,
1046 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
1047 ExFreePool(Srb
->SenseInfoBuffer
);
1048 return(STATUS_INSUFFICIENT_RESOURCES
);
1051 /* FIXME: more irp initialization required? */
1054 /* Attach Srb to the Irp */
1055 IoStack
= IoGetNextIrpStackLocation(Irp
);
1056 IoStack
->Parameters
.Scsi
.Srb
= Srb
;
1057 Srb
->OriginalRequest
= Irp
;
1060 /* Call the SCSI port driver */
1061 Status
= IoCallDriver(DeviceExtension
->PortDeviceObject
,
1063 if (Status
== STATUS_PENDING
)
1065 KeWaitForSingleObject(&Event
,
1072 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
)
1074 Retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
1078 MAXIMUM_RETRIES
- RetryCount
,
1083 DPRINT1("Should try again!\n");
1089 Status
= STATUS_SUCCESS
;
1092 ExFreePool(Srb
->SenseInfoBuffer
);
1094 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1101 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject
,
1109 /* INTERNAL FUNCTIONS *******************************************************/
1111 static NTSTATUS STDCALL
1112 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1115 PDEVICE_EXTENSION DeviceExtension
;
1117 DPRINT("ScsiClassCreateClose() called\n");
1119 DeviceExtension
= DeviceObject
->DeviceExtension
;
1121 if (DeviceExtension
->ClassCreateClose
)
1122 return(DeviceExtension
->ClassCreateClose(DeviceObject
,
1125 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1126 Irp
->IoStatus
.Information
= 0;
1127 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1129 return(STATUS_SUCCESS
);
1133 static NTSTATUS STDCALL
1134 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
1137 PDEVICE_EXTENSION DeviceExtension
;
1138 PIO_STACK_LOCATION IrpStack
;
1139 ULONG TransferLength
;
1140 ULONG TransferPages
;
1143 DPRINT("ScsiClassReadWrite() called\n");
1145 DeviceExtension
= DeviceObject
->DeviceExtension
;
1146 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1148 DPRINT("Relative Offset: %I64u Length: %lu\n",
1149 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
,
1150 IrpStack
->Parameters
.Read
.Length
);
1152 TransferLength
= IrpStack
->Parameters
.Read
.Length
;
1154 if ((DeviceObject
->Flags
& DO_VERIFY_VOLUME
) &&
1155 !(IrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
1157 IoSetHardErrorOrVerifyDevice(Irp
,
1160 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1161 Irp
->IoStatus
.Information
= 0;
1163 IoCompleteRequest(Irp
,
1165 return(STATUS_VERIFY_REQUIRED
);
1168 /* Class driver verifies the IRP */
1169 Status
= DeviceExtension
->ClassReadWriteVerification(DeviceObject
,
1171 if (!NT_SUCCESS(Status
))
1173 IoCompleteRequest(Irp
,
1177 else if (Status
== STATUS_PENDING
)
1179 IoMarkIrpPending(Irp
);
1180 return(STATUS_PENDING
);
1183 /* Finish a zero-byte transfer */
1184 if (TransferLength
== 0)
1186 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1187 Irp
->IoStatus
.Information
= 0;
1188 IoCompleteRequest(Irp
,
1190 return(STATUS_SUCCESS
);
1193 if (DeviceExtension
->ClassStartIo
!= NULL
)
1195 DPRINT("ScsiClassReadWrite() starting packet\n");
1197 IoMarkIrpPending(Irp
);
1198 IoStartPacket(DeviceObject
,
1203 return(STATUS_PENDING
);
1206 IoMarkIrpPending(Irp
);
1208 /* Adjust partition-relative starting offset to absolute offset */
1209 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= DeviceExtension
->StartingOffset
.QuadPart
;
1211 /* Calculate number of pages in this transfer */
1212 TransferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1213 IrpStack
->Parameters
.Read
.Length
);
1216 if (TransferLength
> maximumTransferLength
||
1217 TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
)
1219 /* FIXME: split request */
1223 ScsiClassBuildRequest(DeviceObject
,
1226 DPRINT("ScsiClassReadWrite() done\n");
1228 /* Call the port driver */
1229 return(IoCallDriver(DeviceExtension
->PortDeviceObject
,
1234 static NTSTATUS STDCALL
1235 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
1238 DPRINT1("ScsiClassScsiDispatch() called\n");
1240 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1241 Irp
->IoStatus
.Information
= 0;
1242 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1244 return(STATUS_SUCCESS
);
1248 static NTSTATUS STDCALL
1249 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
1252 PDEVICE_EXTENSION DeviceExtension
;
1254 DPRINT("ScsiClassDeviceDispatch() called\n");
1256 DeviceExtension
= DeviceObject
->DeviceExtension
;
1257 if (DeviceExtension
->ClassDeviceControl
)
1259 return(DeviceExtension
->ClassDeviceControl(DeviceObject
, Irp
));
1262 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1263 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1265 return(STATUS_INVALID_DEVICE_REQUEST
);
1269 static NTSTATUS STDCALL
1270 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1273 PDEVICE_EXTENSION DeviceExtension
;
1275 DPRINT("ScsiClassShutdownFlush() called\n");
1277 DeviceExtension
= DeviceObject
->DeviceExtension
;
1278 if (DeviceExtension
->ClassShutdownFlush
)
1280 return(DeviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
));
1283 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1284 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1286 return(STATUS_INVALID_DEVICE_REQUEST
);