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.15 2002/04/01 23:51:09 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"
42 // #define ENABLE_RETRIES
44 #define VERSION "0.0.1"
46 #define TAG_SRBT TAG('S', 'r', 'b', 'T')
48 #define INQUIRY_DATA_SIZE 2048
51 static NTSTATUS STDCALL
52 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
55 static NTSTATUS STDCALL
56 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
59 static NTSTATUS STDCALL
60 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
63 static NTSTATUS STDCALL
64 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
67 static NTSTATUS STDCALL
68 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
72 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject
,
74 PSCSI_REQUEST_BLOCK Srb
);
76 /* FUNCTIONS ****************************************************************/
81 // This function initializes the driver.
87 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
89 // IN PUNICODE_STRING RegistryPath Name of registry driver service
96 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
97 IN PUNICODE_STRING RegistryPath
)
99 DbgPrint("Class Driver %s\n", VERSION
);
100 return(STATUS_SUCCESS
);
105 ScsiClassDebugPrint(IN ULONG DebugPrintLevel
,
106 IN PCHAR DebugMessage
,
113 if (DebugPrintLevel
> InternalDebugLevel
)
117 va_start(ap
, DebugMessage
);
118 vsprintf(Buffer
, DebugMessage
, ap
);
126 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject
,
135 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject
,
138 PDEVICE_EXTENSION DeviceExtension
;
139 PIO_STACK_LOCATION CurrentIrpStack
;
140 PIO_STACK_LOCATION NextIrpStack
;
141 LARGE_INTEGER StartingOffset
;
142 LARGE_INTEGER StartingBlock
;
143 PSCSI_REQUEST_BLOCK Srb
;
145 ULONG LogicalBlockAddress
;
146 USHORT TransferBlocks
;
148 DeviceExtension
= DeviceObject
->DeviceExtension
;
149 CurrentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
150 NextIrpStack
= IoGetNextIrpStackLocation(Irp
);
151 StartingOffset
= CurrentIrpStack
->Parameters
.Read
.ByteOffset
;
153 /* Calculate logical block address */
154 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> DeviceExtension
->SectorShift
;
155 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
157 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
159 /* Allocate and initialize an SRB */
160 /* FIXME: use lookaside list instead */
161 Srb
= ExAllocatePool(NonPagedPool
,
162 sizeof(SCSI_REQUEST_BLOCK
));
165 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
166 Srb
->OriginalRequest
= Irp
;
167 Srb
->PathId
= DeviceExtension
->PathId
;
168 Srb
->TargetId
= DeviceExtension
->TargetId
;
169 Srb
->Lun
= DeviceExtension
->Lun
;
170 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
171 Srb
->DataBuffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
172 Srb
->DataTransferLength
= CurrentIrpStack
->Parameters
.Read
.Length
;
173 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
174 Srb
->QueueSortKey
= LogicalBlockAddress
;
176 Srb
->SenseInfoBuffer
= DeviceExtension
->SenseData
;
177 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
180 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * DeviceExtension
->TimeOutValue
;
182 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
187 Cdb
= (PCDB
)Srb
->Cdb
;
189 /* Initialize ATAPI packet (12 bytes) */
193 Cdb
->CDB10
.LogicalUnitNumber
= DeviceExtension
->Lun
;
194 TransferBlocks
= (USHORT
)(CurrentIrpStack
->Parameters
.Read
.Length
>> DeviceExtension
->SectorShift
);
196 /* Copy little endian values into CDB in big endian format */
197 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
198 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
199 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
200 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
202 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
203 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
206 if (CurrentIrpStack
->MajorFunction
== IRP_MJ_READ
)
208 DPRINT("ScsiClassBuildRequest: Read Command\n");
210 Srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
211 Cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
215 DPRINT("ScsiClassBuildRequest: Write Command\n");
217 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
218 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
222 /* if this is not a write-through request, then allow caching */
223 if (!(CurrentIrpStack
->Flags
& SL_WRITE_THROUGH
))
225 Srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
227 else if (DeviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
)
229 /* if write caching is enable then force media access in the cdb */
230 Cdb
->CDB10
.ForceUnitAccess
= TRUE
;
234 /* Update srb flags */
235 Srb
->SrbFlags
|= DeviceExtension
->SrbFlags
;
237 /* Initialize next stack location */
238 NextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
239 NextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
240 NextIrpStack
->DeviceObject
= DeviceObject
;
242 /* Set retry count */
243 NextIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
245 DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp
, Srb
);
246 IoSetCompletionRoutine(Irp
,
256 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject
,
257 PSCSI_INQUIRY_DATA LunInfo
,
259 PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
)
261 PIO_STACK_LOCATION IoStack
;
262 IO_STATUS_BLOCK IoStatusBlock
;
263 SCSI_REQUEST_BLOCK Srb
;
268 DPRINT("ScsiClassClaimDevice() called\n");
270 if (NewPortDeviceObject
!= NULL
)
271 *NewPortDeviceObject
= NULL
;
273 /* initialize an SRB */
275 sizeof(SCSI_REQUEST_BLOCK
));
276 Srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
277 Srb
.PathId
= LunInfo
->PathId
;
278 Srb
.TargetId
= LunInfo
->TargetId
;
279 Srb
.Lun
= LunInfo
->Lun
;
281 (Release
== TRUE
) ? SRB_FUNCTION_RELEASE_DEVICE
: SRB_FUNCTION_CLAIM_DEVICE
;
283 KeInitializeEvent(&Event
,
287 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
298 DPRINT1("Failed to allocate Irp!\n");
299 return(STATUS_INSUFFICIENT_RESOURCES
);
302 /* Link Srb and Irp */
303 IoStack
= IoGetNextIrpStackLocation(Irp
);
304 IoStack
->Parameters
.Scsi
.Srb
= &Srb
;
305 Srb
.OriginalRequest
= Irp
;
307 /* Call SCSI port driver */
308 Status
= IoCallDriver(PortDeviceObject
,
310 if (Status
== STATUS_PENDING
)
312 KeWaitForSingleObject(&Event
,
317 Status
= IoStatusBlock
.Status
;
322 ObDereferenceObject(PortDeviceObject
);
323 return(STATUS_SUCCESS
);
326 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
327 Status
= ObReferenceObjectByPointer(PortDeviceObject
,
332 if (NewPortDeviceObject
!= NULL
)
334 // *NewPortDeviceObject = Srb.DataBuffer;
335 *NewPortDeviceObject
= PortDeviceObject
;
338 return(STATUS_SUCCESS
);
343 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
344 IN PCCHAR ObjectNameBuffer
,
345 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL
,
346 IN OUT PDEVICE_OBJECT
*DeviceObject
,
347 IN PCLASS_INIT_DATA InitializationData
)
349 PDEVICE_OBJECT InternalDeviceObject
;
350 PDEVICE_EXTENSION DeviceExtension
;
351 ANSI_STRING AnsiName
;
352 UNICODE_STRING DeviceName
;
355 DPRINT("ScsiClassCreateDeviceObject() called\n");
357 *DeviceObject
= NULL
;
359 RtlInitAnsiString(&AnsiName
,
362 Status
= RtlAnsiStringToUnicodeString(&DeviceName
,
365 if (!NT_SUCCESS(Status
))
370 DPRINT("Device name: '%wZ'\n", &DeviceName
);
372 Status
= IoCreateDevice(DriverObject
,
373 InitializationData
->DeviceExtensionSize
,
375 InitializationData
->DeviceType
,
376 InitializationData
->DeviceCharacteristics
,
378 &InternalDeviceObject
);
379 if (NT_SUCCESS(Status
))
381 DeviceExtension
= InternalDeviceObject
->DeviceExtension
;
383 DeviceExtension
->ClassError
= InitializationData
->ClassError
;
384 DeviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
385 DeviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
386 DeviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
387 DeviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
388 DeviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
389 DeviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
391 DeviceExtension
->MediaChangeCount
= 0;
393 if (PhysicalDeviceObject
!= NULL
)
395 DeviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
399 DeviceExtension
->PhysicalDevice
= InternalDeviceObject
;
402 *DeviceObject
= InternalDeviceObject
;
405 RtlFreeUnicodeString(&DeviceName
);
412 ScsiClassDeviceControl(PDEVICE_OBJECT DeviceObject
,
420 ScsiClassFindModePage(PCHAR ModeSenseBuffer
,
430 ScsiClassFindUnclaimedDevices(PCLASS_INIT_DATA InitializationData
,
431 PSCSI_ADAPTER_BUS_INFO AdapterInformation
)
433 PSCSI_INQUIRY_DATA UnitInfo
;
434 PINQUIRYDATA InquiryData
;
437 ULONG UnclaimedDevices
= 0;
440 DPRINT("ScsiClassFindUnclaimedDevices() called!\n");
442 DPRINT("NumberOfBuses: %lu\n",AdapterInformation
->NumberOfBuses
);
443 Buffer
= (PUCHAR
)AdapterInformation
;
444 for (Bus
= 0; Bus
< (ULONG
)AdapterInformation
->NumberOfBuses
; Bus
++)
446 DPRINT("Searching bus %lu\n", Bus
);
448 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterInformation
->BusData
[Bus
].InquiryDataOffset
);
450 while (AdapterInformation
->BusData
[Bus
].InquiryDataOffset
)
452 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
454 DPRINT("Device: '%.8s'\n", InquiryData
->VendorId
);
456 if ((InitializationData
->ClassFindDeviceCallBack(InquiryData
) == TRUE
) &&
457 (UnitInfo
->DeviceClaimed
== FALSE
))
462 if (UnitInfo
->NextInquiryDataOffset
== 0)
465 UnitInfo
= (PSCSI_INQUIRY_DATA
) (Buffer
+ UnitInfo
->NextInquiryDataOffset
);
469 return(UnclaimedDevices
);
474 ScsiClassGetCapabilities(PDEVICE_OBJECT PortDeviceObject
,
475 PIO_SCSI_CAPABILITIES
*PortCapabilities
)
477 PIO_SCSI_CAPABILITIES Buffer
;
478 IO_STATUS_BLOCK IoStatusBlock
;
483 *PortCapabilities
= NULL
;
484 Buffer
= ExAllocatePool(NonPagedPool
,
485 sizeof(IO_SCSI_CAPABILITIES
));
488 return(STATUS_INSUFFICIENT_RESOURCES
);
491 KeInitializeEvent(&Event
,
495 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
500 sizeof(IO_SCSI_CAPABILITIES
),
507 return(STATUS_INSUFFICIENT_RESOURCES
);
510 Status
= IoCallDriver(PortDeviceObject
,
512 if (Status
== STATUS_PENDING
)
514 KeWaitForSingleObject(&Event
,
519 Status
= IoStatusBlock
.Status
;
522 if (!NT_SUCCESS(Status
))
528 *PortCapabilities
= Buffer
;
536 ScsiClassGetInquiryData(PDEVICE_OBJECT PortDeviceObject
,
537 PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
)
539 PSCSI_ADAPTER_BUS_INFO Buffer
;
540 IO_STATUS_BLOCK IoStatusBlock
;
545 DPRINT("ScsiClassGetInquiryData() called\n");
548 Buffer
= ExAllocatePool(NonPagedPool
,
552 return(STATUS_INSUFFICIENT_RESOURCES
);
555 KeInitializeEvent(&Event
,
559 Irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
571 return(STATUS_INSUFFICIENT_RESOURCES
);
574 Status
= IoCallDriver(PortDeviceObject
,
576 if (Status
== STATUS_PENDING
)
578 KeWaitForSingleObject(&Event
,
583 Status
= IoStatusBlock
.Status
;
586 if (!NT_SUCCESS(Status
))
592 *ConfigInfo
= Buffer
;
595 DPRINT("ScsiClassGetInquiryData() done\n");
602 ScsiClassInitialize(PVOID Argument1
,
604 PCLASS_INIT_DATA InitializationData
)
606 PCONFIGURATION_INFORMATION ConfigInfo
;
607 PDRIVER_OBJECT DriverObject
= Argument1
;
608 WCHAR NameBuffer
[80];
609 UNICODE_STRING PortName
;
611 PDEVICE_OBJECT PortDeviceObject
;
612 PFILE_OBJECT FileObject
;
613 BOOLEAN DiskFound
= FALSE
;
616 DPRINT("ScsiClassInitialize() called!\n");
618 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
619 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
620 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
621 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
622 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassScsiDispatch
;
623 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceDispatch
;
624 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
625 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
626 if (InitializationData
->ClassStartIo
)
628 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
631 ConfigInfo
= IoGetConfigurationInformation();
633 DPRINT("ScsiPorts: %lu\n", ConfigInfo
->ScsiPortCount
);
635 /* look for ScsiPortX scsi port devices */
636 for (PortNumber
= 0; PortNumber
< ConfigInfo
->ScsiPortCount
; PortNumber
++)
639 L
"\\Device\\ScsiPort%lu",
641 RtlInitUnicodeString(&PortName
,
643 DPRINT("Checking scsi port %ld\n", PortNumber
);
644 Status
= IoGetDeviceObjectPointer(&PortName
,
645 FILE_READ_ATTRIBUTES
,
648 DPRINT("Status 0x%08lX\n", Status
);
649 if (NT_SUCCESS(Status
))
651 DPRINT("ScsiPort%lu found.\n", PortNumber
);
653 /* check scsi port for attached disk drives */
654 if (InitializationData
->ClassFindDevices(DriverObject
,
665 DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber
, Status
);
669 DPRINT("ScsiClassInitialize() done!\n");
671 return((DiskFound
== TRUE
) ? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
);
675 /**********************************************************************
677 * ScsiClassInitializeSrbLookasideList
680 * Initializes a lookaside list for SRBs.
687 * Class specific device extension.
690 * Maximum number of elements of the lookaside list.
697 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension
,
698 ULONG NumberElements
)
700 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
704 sizeof(SCSI_REQUEST_BLOCK
),
706 (USHORT
)NumberElements
);
711 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject
,
719 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject
,
720 PSCSI_REQUEST_BLOCK Srb
,
721 UCHAR MajorFunctionCode
,
726 PDEVICE_EXTENSION DeviceExtension
;
727 PSENSE_DATA SenseData
;
730 DPRINT1("ScsiClassInterpretSenseInfo() called\n");
732 DPRINT1("Srb->SrbStatus %lx\n", Srb
->SrbStatus
);
734 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_PENDING
)
736 *Status
= STATUS_SUCCESS
;
740 DeviceExtension
= DeviceObject
->DeviceExtension
;
741 SenseData
= Srb
->SenseInfoBuffer
;
744 if ((Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
) &&
745 (Srb
->SenseInfoBufferLength
> 0))
747 /* Got valid sense data, interpret them */
749 DPRINT1("ErrorCode: %x\n", SenseData
->ErrorCode
);
750 DPRINT1("SenseKey: %x\n", SenseData
->SenseKey
);
751 DPRINT1("SenseCode: %x\n", SenseData
->AdditionalSenseCode
);
753 switch (SenseData
->SenseKey
& 0xf)
755 /* FIXME: add more sense key codes */
757 case SCSI_SENSE_NOT_READY
:
758 DPRINT1("SCSI_SENSE_NOT_READY\n");
759 *Status
= STATUS_DEVICE_NOT_READY
;
762 case SCSI_SENSE_UNIT_ATTENTION
:
763 DPRINT1("SCSI_SENSE_UNIT_ATTENTION\n");
764 if ((DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) &&
765 (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
))
767 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
768 *Status
= STATUS_VERIFY_REQUIRED
;
773 *Status
= STATUS_IO_DEVICE_ERROR
;
777 case SCSI_SENSE_ILLEGAL_REQUEST
:
778 DPRINT1("SCSI_SENSE_ILLEGAL_REQUEST\n");
779 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
785 DPRINT1("SCSI error (sense key: %x)\n",
786 SenseData
->SenseKey
& 0xf);
787 *Status
= STATUS_IO_DEVICE_ERROR
;
793 /* Got no/invalid sense data, return generic error codes */
794 switch (SRB_STATUS(Srb
->SrbStatus
))
796 /* FIXME: add more srb status codes */
798 case SRB_STATUS_DATA_OVERRUN
:
799 *Status
= STATUS_DATA_OVERRUN
;
804 *Status
= STATUS_IO_DEVICE_ERROR
;
809 /* Call the class driver specific error function */
810 if (DeviceExtension
->ClassError
!= NULL
)
812 DeviceExtension
->ClassError(DeviceObject
,
818 /* FIXME: log severe errors */
820 DPRINT1("ScsiClassInterpretSenseInfo() done\n");
827 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject
,
831 PDEVICE_EXTENSION DeviceExtension
;
832 PIO_STACK_LOCATION IrpStack
;
833 PSCSI_REQUEST_BLOCK Srb
;
837 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
838 DeviceObject
, Irp
, Context
);
840 DeviceExtension
= DeviceObject
->DeviceExtension
;
841 Srb
= (PSCSI_REQUEST_BLOCK
)Context
;
842 DPRINT("Srb %p\n", Srb
);
844 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
846 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
848 Status
= STATUS_SUCCESS
;
852 Retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
854 IrpStack
->MajorFunction
,
856 MAXIMUM_RETRIES
- ((ULONG
)IrpStack
->Parameters
.Others
.Argument4
),
859 DPRINT1("Retry count: %lu\n", (ULONG
)IrpStack
->Parameters
.Others
.Argument4
);
861 if ((Retry
== TRUE
) &&
862 ((ULONG
)IrpStack
->Parameters
.Others
.Argument4
> 0))
864 ((ULONG
)IrpStack
->Parameters
.Others
.Argument4
)--;
865 DPRINT1("Retry count: %lu\n", (ULONG
)IrpStack
->Parameters
.Others
.Argument4
);
867 DPRINT1("Should try again!\n");
869 ScsiClassRetryRequest(DeviceObject
,
872 return(STATUS_MORE_PROCESSING_REQUIRED
);
879 /* FIXME: use lookaside list instead */
880 DPRINT("Freed SRB %p\n", IrpStack
->Parameters
.Scsi
.Srb
);
881 ExFreePool(IrpStack
->Parameters
.Scsi
.Srb
);
883 Irp
->IoStatus
.Status
= Status
;
885 if (!NT_SUCCESS(Status
) &&
886 IoIsErrorUserInduced(Status
))
888 IoSetHardErrorOrVerifyDevice(Irp
,
890 Irp
->IoStatus
.Information
= 0;
893 if (Irp
->PendingReturned
)
895 IoMarkIrpPending(Irp
);
899 if (DeviceExtension
->ClassStartIo
!= NULL
)
901 if (IrpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
903 IoStartNextPacket(DeviceObject
,
908 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status
);
915 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject
,
924 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject
,
925 CHAR ModeSenseBuffer
,
934 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath
)
941 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject
)
943 PDEVICE_EXTENSION DeviceExtension
;
944 PREAD_CAPACITY_DATA CapacityBuffer
;
945 SCSI_REQUEST_BLOCK Srb
;
951 DPRINT("ScsiClassReadDriveCapacity() called\n");
953 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
955 CapacityBuffer
= ExAllocatePool(NonPagedPool
,
956 sizeof(READ_CAPACITY_DATA
));
957 if (CapacityBuffer
== NULL
)
959 return(STATUS_INSUFFICIENT_RESOURCES
);
962 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
965 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
968 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
971 Status
= ScsiClassSendSrbSynchronous(DeviceObject
,
974 sizeof(READ_CAPACITY_DATA
),
976 DPRINT("Status: %lx\n", Status
);
977 DPRINT("Srb: %p\n", &Srb
);
978 if (NT_SUCCESS(Status
))
980 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
981 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
982 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
983 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
986 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
987 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
988 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
989 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
991 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
993 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
994 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
,
995 DeviceExtension
->SectorShift
);
996 DeviceExtension
->PartitionLength
.QuadPart
=
997 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
999 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1001 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
1005 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
1007 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((LastSector
+ 1)/(32 * 64));
1008 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
1009 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
1011 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize
, LastSector
+ 1);
1015 /* Use default values if disk geometry cannot be read */
1016 RtlZeroMemory(&DeviceExtension
->DiskGeometry
,
1017 sizeof(DISK_GEOMETRY
));
1018 DeviceExtension
->DiskGeometry
->BytesPerSector
= 512;
1019 DeviceExtension
->SectorShift
= 9;
1020 DeviceExtension
->PartitionLength
.QuadPart
= 0;
1022 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1024 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
1028 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
1032 ExFreePool(CapacityBuffer
);
1034 DPRINT("ScsiClassReadDriveCapacity() done\n");
1041 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject
)
1048 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject
,
1049 PSCSI_REQUEST_BLOCK Srb
,
1051 PVOID BufferAddress
,
1053 BOOLEAN WriteToDevice
)
1060 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject
,
1061 PSCSI_REQUEST_BLOCK Srb
,
1062 PVOID BufferAddress
,
1064 BOOLEAN WriteToDevice
)
1066 PDEVICE_EXTENSION DeviceExtension
;
1067 IO_STATUS_BLOCK IoStatusBlock
;
1068 PIO_STACK_LOCATION IoStack
;
1077 DPRINT("ScsiClassSendSrbSynchronous() called\n");
1079 RetryCount
= MAXIMUM_RETRIES
;
1080 DeviceExtension
= DeviceObject
->DeviceExtension
;
1082 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1083 Srb
->PathId
= DeviceExtension
->PathId
;
1084 Srb
->TargetId
= DeviceExtension
->TargetId
;
1085 Srb
->Lun
= DeviceExtension
->Lun
;
1086 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1088 /* FIXME: more srb initialization required? */
1090 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1091 Srb
->SenseInfoBuffer
= ExAllocatePool(NonPagedPool
,
1093 if (Srb
->SenseInfoBuffer
== NULL
)
1094 return(STATUS_INSUFFICIENT_RESOURCES
);
1096 if (BufferAddress
== NULL
)
1099 RequestType
= IOCTL_SCSI_EXECUTE_NONE
;
1100 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1104 if (WriteToDevice
== TRUE
)
1106 RequestType
= IOCTL_SCSI_EXECUTE_OUT
;
1107 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
1111 RequestType
= IOCTL_SCSI_EXECUTE_IN
;
1112 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
1116 Srb
->DataTransferLength
= BufferLength
;
1117 Srb
->DataBuffer
= BufferAddress
;
1120 KeInitializeEvent(&Event
,
1124 Irp
= IoBuildDeviceIoControlRequest(RequestType
,
1125 DeviceExtension
->PortDeviceObject
,
1135 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
1136 ExFreePool(Srb
->SenseInfoBuffer
);
1137 return(STATUS_INSUFFICIENT_RESOURCES
);
1140 /* FIXME: more irp initialization required? */
1143 /* Attach Srb to the Irp */
1144 IoStack
= IoGetNextIrpStackLocation(Irp
);
1145 IoStack
->Parameters
.Scsi
.Srb
= Srb
;
1146 Srb
->OriginalRequest
= Irp
;
1149 /* Call the SCSI port driver */
1150 Status
= IoCallDriver(DeviceExtension
->PortDeviceObject
,
1152 if (Status
== STATUS_PENDING
)
1154 KeWaitForSingleObject(&Event
,
1161 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
)
1163 Retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
1167 MAXIMUM_RETRIES
- RetryCount
,
1172 DPRINT1("Should try again!\n");
1178 Status
= STATUS_SUCCESS
;
1181 ExFreePool(Srb
->SenseInfoBuffer
);
1183 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1190 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject
,
1198 /* INTERNAL FUNCTIONS *******************************************************/
1200 static NTSTATUS STDCALL
1201 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1204 PDEVICE_EXTENSION DeviceExtension
;
1206 DPRINT("ScsiClassCreateClose() called\n");
1208 DeviceExtension
= DeviceObject
->DeviceExtension
;
1210 if (DeviceExtension
->ClassCreateClose
)
1211 return(DeviceExtension
->ClassCreateClose(DeviceObject
,
1214 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1215 Irp
->IoStatus
.Information
= 0;
1216 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1218 return(STATUS_SUCCESS
);
1222 static NTSTATUS STDCALL
1223 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject
,
1226 PDEVICE_EXTENSION DeviceExtension
;
1227 PIO_STACK_LOCATION IrpStack
;
1228 ULONG TransferLength
;
1229 ULONG TransferPages
;
1232 DPRINT("ScsiClassReadWrite() called\n");
1234 DeviceExtension
= DeviceObject
->DeviceExtension
;
1235 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1237 DPRINT("Relative Offset: %I64u Length: %lu\n",
1238 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
,
1239 IrpStack
->Parameters
.Read
.Length
);
1241 TransferLength
= IrpStack
->Parameters
.Read
.Length
;
1243 if ((DeviceObject
->Flags
& DO_VERIFY_VOLUME
) &&
1244 !(IrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
1246 IoSetHardErrorOrVerifyDevice(Irp
,
1249 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1250 Irp
->IoStatus
.Information
= 0;
1252 IoCompleteRequest(Irp
,
1254 return(STATUS_VERIFY_REQUIRED
);
1257 /* Class driver verifies the IRP */
1258 Status
= DeviceExtension
->ClassReadWriteVerification(DeviceObject
,
1260 if (!NT_SUCCESS(Status
))
1262 IoCompleteRequest(Irp
,
1266 else if (Status
== STATUS_PENDING
)
1268 IoMarkIrpPending(Irp
);
1269 return(STATUS_PENDING
);
1272 /* Finish a zero-byte transfer */
1273 if (TransferLength
== 0)
1275 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1276 Irp
->IoStatus
.Information
= 0;
1277 IoCompleteRequest(Irp
,
1279 return(STATUS_SUCCESS
);
1282 if (DeviceExtension
->ClassStartIo
!= NULL
)
1284 DPRINT("ScsiClassReadWrite() starting packet\n");
1286 IoMarkIrpPending(Irp
);
1287 IoStartPacket(DeviceObject
,
1292 return(STATUS_PENDING
);
1295 IoMarkIrpPending(Irp
);
1297 /* Adjust partition-relative starting offset to absolute offset */
1298 IrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= DeviceExtension
->StartingOffset
.QuadPart
;
1300 /* Calculate number of pages in this transfer */
1301 TransferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1302 IrpStack
->Parameters
.Read
.Length
);
1305 if (TransferLength
> maximumTransferLength
||
1306 TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
)
1308 /* FIXME: split request */
1312 ScsiClassBuildRequest(DeviceObject
,
1315 DPRINT("ScsiClassReadWrite() done\n");
1317 /* Call the port driver */
1318 return(IoCallDriver(DeviceExtension
->PortDeviceObject
,
1323 static NTSTATUS STDCALL
1324 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject
,
1327 DPRINT1("ScsiClassScsiDispatch() called\n");
1329 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1330 Irp
->IoStatus
.Information
= 0;
1331 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1333 return(STATUS_SUCCESS
);
1337 static NTSTATUS STDCALL
1338 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject
,
1341 PDEVICE_EXTENSION DeviceExtension
;
1343 DPRINT("ScsiClassDeviceDispatch() called\n");
1345 DeviceExtension
= DeviceObject
->DeviceExtension
;
1346 if (DeviceExtension
->ClassDeviceControl
)
1348 return(DeviceExtension
->ClassDeviceControl(DeviceObject
, Irp
));
1351 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1352 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1354 return(STATUS_INVALID_DEVICE_REQUEST
);
1358 static NTSTATUS STDCALL
1359 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
1362 PDEVICE_EXTENSION DeviceExtension
;
1364 DPRINT("ScsiClassShutdownFlush() called\n");
1366 DeviceExtension
= DeviceObject
->DeviceExtension
;
1367 if (DeviceExtension
->ClassShutdownFlush
)
1369 return(DeviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
));
1372 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1373 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1375 return(STATUS_INVALID_DEVICE_REQUEST
);
1380 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject
,
1382 PSCSI_REQUEST_BLOCK Srb
)
1384 PDEVICE_EXTENSION DeviceExtension
;
1385 PIO_STACK_LOCATION CurrentIrpStack
;
1386 PIO_STACK_LOCATION NextIrpStack
;
1387 ULONG TransferLength
;
1389 DPRINT1("ScsiPortRetryRequest() called\n");
1391 DeviceExtension
= DeviceObject
->DeviceExtension
;
1392 CurrentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1393 NextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1395 if (CurrentIrpStack
->MajorFunction
== IRP_MJ_READ
||
1396 CurrentIrpStack
->MajorFunction
== IRP_MJ_WRITE
)
1398 TransferLength
= CurrentIrpStack
->Parameters
.Read
.Length
;
1400 else if (Irp
->MdlAddress
!= NULL
)
1402 TransferLength
= Irp
->MdlAddress
->ByteCount
;
1409 Srb
->DataTransferLength
= TransferLength
;
1411 Srb
->ScsiStatus
= 0;
1412 // Srb->QueueTag = SP_UNTAGGED;
1414 /* Don't modify the flags */
1417 // CurrentIrpStack->MajorFunction = IRP_MJ_SCSI;
1418 // CurrentIrpStack->Parameters.Scsi.Srb = Srb;
1420 // IoSkipCurrentIrpStackLocation(Irp);
1422 *NextIrpStack
= *CurrentIrpStack
;
1423 NextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1424 NextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1427 IoSetCompletionRoutine(Irp
,
1428 ScsiClassIoComplete
,
1434 DPRINT1("ScsiPortRetryRequest() done\n");
1436 IoCallDriver(DeviceExtension
->PortDeviceObject
,