2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/class2/class2.c
5 * PURPOSE: SCSI Class driver routines
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
12 #include <include/class2.h>
15 /* Part of the drive letter hack */
23 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
24 #pragma alloc_text(PAGE, ScsiClassInitialize)
25 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
26 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
27 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
28 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
32 #define INQUIRY_DATA_SIZE 2048
33 #define START_UNIT_TIMEOUT 30
35 /* Disk layout used by Windows NT4 and earlier versions. */
36 //#define DEFAULT_SECTORS_PER_TRACK 32
37 //#define DEFAULT_TRACKS_PER_CYLINDER 64
39 /* Disk layout used by Windows 2000 and later versions. */
40 #define DEFAULT_SECTORS_PER_TRACK 63
41 #define DEFAULT_TRACKS_PER_CYLINDER 255
46 IN PDEVICE_OBJECT DeviceObject
,
53 IN PDEVICE_OBJECT DeviceObject
,
59 ScsiClassDeviceControlDispatch(
60 PDEVICE_OBJECT DeviceObject
,
66 ScsiClassDeviceControl(
67 PDEVICE_OBJECT DeviceObject
,
73 ScsiClassInternalIoControl (
74 IN PDEVICE_OBJECT DeviceObject
,
80 ScsiClassShutdownFlush(
81 IN PDEVICE_OBJECT DeviceObject
,
88 IN PDRIVER_OBJECT DriverObject
,
89 IN PUNICODE_STRING RegistryPath
93 // Class internal routines
100 PDEVICE_OBJECT DeviceObject
,
102 PSCSI_REQUEST_BLOCK Srb
,
109 IN PDEVICE_OBJECT DeviceObject
115 IN PDEVICE_OBJECT DeviceObject
,
122 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
130 IN PDRIVER_OBJECT DriverObject
,
131 IN PUNICODE_STRING RegistryPath
134 return STATUS_SUCCESS
;
137 /* The following hack to assign drive letters with a non-PnP storage stack */
139 typedef struct _CLASS_DEVICE_INFO
{
143 PDEVICE_OBJECT LowerDevice
;
144 } CLASS_DEVICE_INFO
, *PCLASS_DEVICE_INFO
;
146 typedef struct _CLASS_DRIVER_EXTENSION
{
148 UNICODE_STRING RegistryPath
;
149 CLASS_INIT_DATA InitializationData
;
150 } CLASS_DRIVER_EXTENSION
, *PCLASS_DRIVER_EXTENSION
;
154 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
157 UNICODE_STRING DriveLetterU
;
160 DriveLetterU
.Buffer
= Buffer1
;
161 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
163 /* Delete the symbolic link to PhysicalDriveX */
164 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DeviceInfo
->DriveNumber
) * sizeof(WCHAR
);
165 IoDeleteSymbolicLink(&DriveLetterU
);
167 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
169 for (Index
= 0; Index
< sizeof(ULONG
) * 8; Index
++)
171 if (DeviceInfo
->Partitions
& (1 << Index
))
173 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
174 IoDeleteSymbolicLink(&DriveLetterU
);
175 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
182 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
186 UNICODE_STRING DriveLetterU
, PartitionU
;
188 ULONG Index
, PartitionNumber
, DeviceNumber
, DriveNumber
;
189 OBJECT_ATTRIBUTES ObjectAttributes
;
190 IO_STATUS_BLOCK Iosb
;
191 HANDLE PartitionHandle
;
193 /* We assume this device does not current have a drive letter */
199 DriveLetterU
.Buffer
= Buffer1
;
200 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
201 PartitionU
.Buffer
= Buffer2
;
202 PartitionU
.MaximumLength
= sizeof(Buffer2
);
204 /* Determine the correct disk number */
207 /* Check that the disk exists */
208 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\HardDisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
209 InitializeObjectAttributes(&ObjectAttributes
,
211 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
214 Status
= ZwOpenFile(&PartitionHandle
,
215 FILE_READ_ATTRIBUTES
,
220 if (!NT_SUCCESS(Status
))
222 /* Return the last one that worked */
227 ZwClose(PartitionHandle
);
230 } while (Status
== STATUS_SUCCESS
);
232 /* Determine the correct drive number */
235 /* Check that the drive exists */
236 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
237 InitializeObjectAttributes(&ObjectAttributes
,
239 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
242 Status
= ZwOpenFile(&PartitionHandle
,
243 FILE_READ_ATTRIBUTES
,
248 if (NT_SUCCESS(Status
))
250 ZwClose(PartitionHandle
);
253 } while (Status
== STATUS_SUCCESS
);
255 /* Create the symbolic link to PhysicalDriveX */
256 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
257 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
259 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
260 if (!NT_SUCCESS(Status
))
262 /* Failed to create symbolic link */
266 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
270 /* Check that the disk exists */
271 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", DeviceNumber
, PartitionNumber
) * sizeof(WCHAR
);
272 InitializeObjectAttributes(&ObjectAttributes
,
274 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
277 Status
= ZwOpenFile(&PartitionHandle
,
278 FILE_READ_ATTRIBUTES
,
283 if (!NT_SUCCESS(Status
))
287 ZwClose(PartitionHandle
);
289 /* Assign it a drive letter */
292 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
294 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
297 } while (Status
!= STATUS_SUCCESS
);
299 DeviceInfo
->Partitions
|= (1 << (Index
- 1));
301 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
306 DeviceInfo
->DeviceNumber
= DeviceNumber
;
307 DeviceInfo
->DriveNumber
= DriveNumber
;
309 return STATUS_SUCCESS
;
315 IN PDEVICE_OBJECT DeviceObject
,
318 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
320 if (IrpSp
->MinorFunction
== IRP_MN_START_DEVICE
)
322 IoSkipCurrentIrpStackLocation(Irp
);
323 return STATUS_SUCCESS
;
325 else if (IrpSp
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
327 PCLASS_DEVICE_INFO DeviceInfo
= DeviceObject
->DeviceExtension
;
329 ScsiClassRemoveDriveLetter(DeviceInfo
);
331 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
332 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
334 IoDetachDevice(DeviceInfo
->LowerDevice
);
335 IoDeleteDevice(DeviceObject
);
336 return STATUS_SUCCESS
;
340 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
341 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
342 return STATUS_NOT_SUPPORTED
;
349 IN PDRIVER_OBJECT DriverObject
,
350 IN PDEVICE_OBJECT PhysicalDeviceObject
)
352 PCLASS_DRIVER_EXTENSION DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
353 PCLASS_DEVICE_INFO DeviceInfo
;
354 PDEVICE_OBJECT DeviceObject
;
357 if (DriverExtension
->InitializationData
.ClassFindDevices(DriverObject
, &DriverExtension
->RegistryPath
, &DriverExtension
->InitializationData
,
358 PhysicalDeviceObject
, DriverExtension
->PortNumber
))
360 /* Create a device object */
361 Status
= IoCreateDevice(DriverObject
,
362 sizeof(CLASS_DEVICE_INFO
),
368 if (!NT_SUCCESS(Status
))
373 DeviceInfo
= DeviceObject
->DeviceExtension
;
374 RtlZeroMemory(DeviceInfo
, sizeof(CLASS_DEVICE_INFO
));
376 /* Attach it to the PDO */
377 DeviceInfo
->LowerDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
379 /* Check that the kernel has already assigned drive letters */
380 if (KeLoaderBlock
== NULL
)
382 /* Assign a drive letter */
383 ScsiClassAssignDriveLetter(DeviceInfo
);
387 /* The kernel will handle it */
390 /* Move to the next port number */
391 DriverExtension
->PortNumber
++;
395 /* Failed to find device */
396 DbgPrint("FAILED TO FIND DEVICE!\n");
399 return STATUS_SUCCESS
;
401 /* ---- End hack ---- */
410 IN PCLASS_INIT_DATA InitializationData
417 This routine is called by a class driver during its
418 DriverEntry routine to initialize the driver.
422 Argument1 - Driver Object.
423 Argument2 - Registry Path.
424 InitializationData - Device-specific driver's initialization data.
428 A valid return code for a DriverEntry routine.
435 PDRIVER_OBJECT DriverObject
= Argument1
;
436 PDEVICE_OBJECT portDeviceObject
;
438 STRING deviceNameString
;
439 UNICODE_STRING unicodeDeviceName
;
440 PFILE_OBJECT fileObject
;
441 CCHAR deviceNameBuffer
[256];
442 BOOLEAN deviceFound
= FALSE
;
443 PCLASS_DRIVER_EXTENSION DriverExtension
;
444 PUNICODE_STRING RegistryPath
= Argument2
;
446 DebugPrint((3,"\n\nSCSI Class Driver\n"));
449 // Validate the length of this structure. This is effectively a
453 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
455 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
456 return (ULONG
) STATUS_REVISION_MISMATCH
;
460 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
461 // are not required entry points.
464 if ((!InitializationData
->ClassFindDevices
) ||
465 (!InitializationData
->ClassDeviceControl
) ||
466 (!((InitializationData
->ClassReadWriteVerification
) ||
467 (InitializationData
->ClassStartIo
)))) {
470 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
472 return (ULONG
) STATUS_REVISION_MISMATCH
;
475 status
= IoAllocateDriverObjectExtension(DriverObject
,
477 sizeof(CLASS_DRIVER_EXTENSION
),
478 (PVOID
*)&DriverExtension
);
479 if (!NT_SUCCESS(status
))
482 RtlCopyMemory(&DriverExtension
->InitializationData
, InitializationData
, sizeof(CLASS_INIT_DATA
));
483 DriverExtension
->PortNumber
= 0;
485 DriverExtension
->RegistryPath
.Buffer
= ExAllocatePool(PagedPool
, RegistryPath
->MaximumLength
);
486 if (!DriverExtension
->RegistryPath
.Buffer
)
487 return STATUS_NO_MEMORY
;
489 DriverExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
490 DriverExtension
->RegistryPath
.MaximumLength
= RegistryPath
->MaximumLength
;
492 RtlCopyMemory(DriverExtension
->RegistryPath
.Buffer
,
493 RegistryPath
->Buffer
,
494 RegistryPath
->Length
);
497 // Update driver object with entry points.
500 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
501 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
502 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
503 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
504 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ScsiClassPlugPlay
;
505 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
506 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
507 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
508 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
509 DriverObject
->DriverExtension
->AddDevice
= ScsiClassAddDevice
;
511 if (InitializationData
->ClassStartIo
) {
512 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
516 // Open port driver controller device objects by name.
521 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", DriverExtension
->PortNumber
);
523 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
525 RtlInitString(&deviceNameString
, deviceNameBuffer
);
527 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
531 if (!NT_SUCCESS(status
)){
535 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
536 FILE_READ_ATTRIBUTES
,
540 if (NT_SUCCESS(status
)) {
543 // Call the device-specific driver's FindDevice routine.
546 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
547 portDeviceObject
, DriverExtension
->PortNumber
)) {
554 // Check next SCSI adapter.
557 DriverExtension
->PortNumber
++;
559 } while(NT_SUCCESS(status
));
561 /* We don't want to fail init just because we don't have devices right now */
562 return STATUS_SUCCESS
; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
568 ScsiClassCreateClose(
569 IN PDEVICE_OBJECT DeviceObject
,
577 SCSI class driver create and close routine. This is called by the I/O system
578 when the device is opened or closed.
582 DriverObject - Pointer to driver object created by system.
588 Device-specific drivers return value or STATUS_SUCCESS.
593 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
596 // Invoke the device-specific routine, if one exists. Otherwise complete
600 if (deviceExtension
->ClassCreateClose
) {
602 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
605 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
607 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
608 return(STATUS_SUCCESS
);
617 IN PDEVICE_OBJECT DeviceObject
,
625 This is the system entry point for read and write requests. The device-specific handler is invoked
626 to perform any validation necessary. The number of bytes in the request are
627 checked against the maximum byte counts that the adapter supports and requests are broken up into
628 smaller sizes if necessary.
642 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
643 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
645 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
646 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
649 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
650 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
653 // if DO_VERIFY_VOLUME bit is set
654 // in device object flags, fail request.
657 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
659 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
660 Irp
->IoStatus
.Information
= 0;
662 IoCompleteRequest(Irp
, 0);
663 return STATUS_VERIFY_REQUIRED
;
667 // Invoke the device specific routine to do whatever it needs to verify
671 ASSERT(deviceExtension
->ClassReadWriteVerification
);
673 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
675 if (!NT_SUCCESS(status
)) {
678 // It is up to the device specific driver to set the Irp status.
681 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
683 } else if (status
== STATUS_PENDING
) {
685 IoMarkIrpPending(Irp
);
686 return STATUS_PENDING
;
690 // Check for a zero length IO, as several macros will turn this into
691 // seemingly a 0xffffffff length request.
694 if (transferByteCount
== 0) {
695 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
696 Irp
->IoStatus
.Information
= 0;
697 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
698 return STATUS_SUCCESS
;
702 if (deviceExtension
->ClassStartIo
) {
704 IoMarkIrpPending(Irp
);
706 IoStartPacket(DeviceObject
,
711 return STATUS_PENDING
;
715 // Mark IRP with status pending.
718 IoMarkIrpPending(Irp
);
721 // Add partition byte offset to make starting byte relative to
722 // beginning of disk. In addition, add in skew for DM Driver, if any.
725 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
726 deviceExtension
->DMByteSkew
);
729 // Calculate number of pages in this transfer.
732 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
733 currentIrpStack
->Parameters
.Read
.Length
);
736 // Check if request length is greater than the maximum number of
737 // bytes that the hardware can transfer.
740 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
741 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
743 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
744 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
745 maximumTransferLength
));
746 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
747 currentIrpStack
->Parameters
.Read
.Length
));
750 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
752 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
753 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
757 // Check that maximum transfer size is not zero.
760 if (maximumTransferLength
== 0) {
761 maximumTransferLength
= PAGE_SIZE
;
765 // Mark IRP with status pending.
768 IoMarkIrpPending(Irp
);
771 // Request greater than port driver maximum.
772 // Break up into smaller routines.
775 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
778 return STATUS_PENDING
;
782 // Build SRB and CDB for this IRP.
785 ScsiClassBuildRequest(DeviceObject
, Irp
);
788 // Return the results of the call to the port driver.
791 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
793 } // end ScsiClassReadWrite()
798 ScsiClassGetCapabilities(
799 IN PDEVICE_OBJECT PortDeviceObject
,
800 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
807 This routine builds and sends a request to the port driver to
808 get a pointer to a structure that describes the adapter's
809 capabilities/limitations. This routine is sychronous.
813 PortDeviceObject - Port driver device object representing the HBA.
815 PortCapabilities - Location to store pointer to capabilities structure.
819 Nt status indicating the results of the operation.
823 This routine should only be called at initialization time.
829 IO_STATUS_BLOCK ioStatus
;
836 // Create notification event object to be used to signal the
837 // request completion.
840 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
843 // Build the synchronous request to be sent to the port driver
844 // to perform the request.
847 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
858 return STATUS_INSUFFICIENT_RESOURCES
;
862 // Pass request to port driver and wait for request to complete.
865 status
= IoCallDriver(PortDeviceObject
, irp
);
867 if (status
== STATUS_PENDING
) {
868 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
869 return(ioStatus
.Status
);
874 } // end ScsiClassGetCapabilities()
879 ScsiClassGetInquiryData(
880 IN PDEVICE_OBJECT PortDeviceObject
,
881 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
888 This routine sends a request to a port driver to return
889 configuration information. Space for the information is
890 allocated by this routine. The caller is responsible for
891 freeing the configuration information. This routine is
896 PortDeviceObject - Port driver device object representing the HBA.
898 ConfigInfo - Returns a pointer to the configuration information.
902 Nt status indicating the results of the operation.
906 This routine should be called only at initialization time.
912 IO_STATUS_BLOCK ioStatus
;
915 PSCSI_ADAPTER_BUS_INFO buffer
;
919 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
920 *ConfigInfo
= buffer
;
922 if (buffer
== NULL
) {
923 return(STATUS_INSUFFICIENT_RESOURCES
);
927 // Create notification event object to be used to signal the inquiry
928 // request completion.
931 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
934 // Build the synchronous request to be sent to the port driver
935 // to perform the inquiries.
938 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
949 return(STATUS_INSUFFICIENT_RESOURCES
);
953 // Pass request to port driver and wait for request to complete.
956 status
= IoCallDriver(PortDeviceObject
, irp
);
958 if (status
== STATUS_PENDING
) {
959 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
960 status
= ioStatus
.Status
;
963 if (!NT_SUCCESS(status
)) {
966 // Free the buffer on an error.
976 } // end ScsiClassGetInquiryData()
981 ScsiClassReadDriveCapacity(
982 IN PDEVICE_OBJECT DeviceObject
989 This routine sends a READ CAPACITY to the requested device, updates
990 the geometry information in the device object and returns
991 when it is complete. This routine is synchronous.
995 DeviceObject - Supplies a pointer to the device object that represents
996 the device whose capacity is to be read.
1004 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1008 PREAD_CAPACITY_DATA readCapacityBuffer
;
1009 SCSI_REQUEST_BLOCK srb
;
1013 // Allocate read capacity buffer from nonpaged pool.
1016 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
1017 sizeof(READ_CAPACITY_DATA
));
1019 if (!readCapacityBuffer
) {
1020 return(STATUS_INSUFFICIENT_RESOURCES
);
1023 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1026 // Build the read capacity CDB.
1030 cdb
= (PCDB
)srb
.Cdb
;
1033 // Set timeout value from device extension.
1036 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1038 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1042 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
1045 sizeof(READ_CAPACITY_DATA
),
1048 if (NT_SUCCESS(status
)) {
1051 // Copy sector size from read capacity buffer to device extension
1052 // in reverse byte order.
1055 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
1056 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
1058 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
1059 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
1061 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
1062 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
1064 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
1065 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
1068 // Copy last sector in reverse byte order.
1071 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
1072 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
1074 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
1075 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
1077 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
1078 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
1080 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
1081 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
1084 // Calculate sector to byte shift.
1087 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
1089 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
1090 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
1092 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
1096 // Calculate media capacity in bytes.
1099 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
1102 // Calculate number of cylinders.
1105 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
1107 deviceExtension
->PartitionLength
.QuadPart
=
1108 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
1110 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1113 // This device supports removable media.
1116 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1121 // Assume media type is fixed disk.
1124 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1128 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
1131 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
1134 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
1137 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
1140 if (status
== STATUS_VERIFY_REQUIRED
) {
1143 // Routine ScsiClassSendSrbSynchronous does not retry
1144 // requests returned with this status.
1145 // Read Capacities should be retried
1159 if (!NT_SUCCESS(status
)) {
1162 // If the read capacity fails, set the geometry to reasonable parameter
1163 // so things don't fail at unexpected places. Zero the geometry
1164 // except for the bytes per sector and sector shift.
1167 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
1168 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1169 deviceExtension
->SectorShift
= 9;
1170 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
1172 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1175 // This device supports removable media.
1178 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1183 // Assume media type is fixed disk.
1186 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1191 // Deallocate read capacity buffer.
1194 ExFreePool(readCapacityBuffer
);
1198 } // end ScsiClassReadDriveCapacity()
1203 ScsiClassReleaseQueue(
1204 IN PDEVICE_OBJECT DeviceObject
1209 Routine Description:
1211 This routine issues an internal device control command
1212 to the port driver to release a frozen queue. The call
1213 is issued asynchronously as ScsiClassReleaseQueue will be invoked
1214 from the IO completion DPC (and will have no context to
1215 wait for a synchronous call to complete).
1219 DeviceObject - The device object for the logical unit with
1228 PIO_STACK_LOCATION irpStack
;
1230 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1231 PCOMPLETION_CONTEXT context
;
1232 PSCSI_REQUEST_BLOCK srb
;
1236 // Allocate context from nonpaged pool.
1239 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1240 sizeof(COMPLETION_CONTEXT
));
1243 // Save the device object in the context for use by the completion
1247 context
->DeviceObject
= DeviceObject
;
1248 srb
= &context
->Srb
;
1254 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1257 // Write length to SRB.
1260 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1263 // Set up SCSI bus address.
1266 srb
->PathId
= deviceExtension
->PathId
;
1267 srb
->TargetId
= deviceExtension
->TargetId
;
1268 srb
->Lun
= deviceExtension
->Lun
;
1271 // If this device is removable then flush the queue. This will also
1275 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1277 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
1281 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
1286 // Build the asynchronous request to be sent to the port driver.
1289 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1294 // We have no better way of dealing with this at the moment
1297 KeBugCheck((ULONG
)0x0000002DL
);
1301 IoSetCompletionRoutine(irp
,
1302 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1308 irpStack
= IoGetNextIrpStackLocation(irp
);
1310 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1312 srb
->OriginalRequest
= irp
;
1315 // Store the SRB address in next stack for port driver.
1318 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1321 // Since this routine can cause outstanding requests to be completed, and
1322 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1323 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1324 // issuing the request
1327 currentIrql
= KeGetCurrentIrql();
1329 if(currentIrql
< DISPATCH_LEVEL
) {
1330 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1331 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1332 KeLowerIrql(currentIrql
);
1334 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1339 } // end ScsiClassReleaseQueue()
1345 IN PDEVICE_OBJECT DeviceObject
1350 Routine Description:
1352 Send command to SCSI unit to start or power up.
1353 Because this command is issued asynchronounsly, that is, without
1354 waiting on it to complete, the IMMEDIATE flag is not set. This
1355 means that the CDB will not return until the drive has powered up.
1356 This should keep subsequent requests from being submitted to the
1357 device before it has completely spun up.
1358 This routine is called from the InterpretSense routine, when a
1359 request sense returns data indicating that a drive must be
1364 DeviceObject - The device object for the logical unit with
1373 PIO_STACK_LOCATION irpStack
;
1375 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1376 PSCSI_REQUEST_BLOCK srb
;
1377 PCOMPLETION_CONTEXT context
;
1381 // Allocate Srb from nonpaged pool.
1384 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1385 sizeof(COMPLETION_CONTEXT
));
1388 // Save the device object in the context for use by the completion
1392 context
->DeviceObject
= DeviceObject
;
1393 srb
= &context
->Srb
;
1399 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1402 // Write length to SRB.
1405 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1408 // Set up SCSI bus address.
1411 srb
->PathId
= deviceExtension
->PathId
;
1412 srb
->TargetId
= deviceExtension
->TargetId
;
1413 srb
->Lun
= deviceExtension
->Lun
;
1415 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1418 // Set timeout value large enough for drive to spin up.
1421 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1424 // Set the transfer length.
1427 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1430 // Build the start unit CDB.
1434 cdb
= (PCDB
)srb
->Cdb
;
1436 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1437 cdb
->START_STOP
.Start
= 1;
1438 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1441 // Build the asynchronous request to be sent to the port driver.
1442 // Since this routine is called from a DPC the IRP should always be
1446 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1447 IoSetCompletionRoutine(irp
,
1448 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1454 irpStack
= IoGetNextIrpStackLocation(irp
);
1455 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1456 srb
->OriginalRequest
= irp
;
1459 // Store the SRB address in next stack for port driver.
1462 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1465 // Call the port driver with the IRP.
1468 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1472 } // end StartUnit()
1477 ScsiClassAsynchronousCompletion(
1478 PDEVICE_OBJECT DeviceObject
,
1484 Routine Description:
1486 This routine is called when an asynchronous I/O request
1487 which was issused by the class driver completes. Examples of such requests
1488 are release queue or START UNIT. This routine releases the queue if
1489 necessary. It then frees the context and the IRP.
1493 DeviceObject - The device object for the logical unit; however since this
1494 is the top stack location the value is NULL.
1496 Irp - Supplies a pointer to the Irp to be processed.
1498 Context - Supplies the context to be used to process this request.
1507 PCOMPLETION_CONTEXT context
= Context
;
1508 PSCSI_REQUEST_BLOCK srb
;
1510 srb
= &context
->Srb
;
1513 // If this is an execute srb, then check the return status and make sure.
1514 // the queue is not frozen.
1517 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1520 // Check for a frozen queue.
1523 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1526 // Unfreeze the queue getting the device object from the context.
1529 ScsiClassReleaseQueue(context
->DeviceObject
);
1534 // Free the context and the Irp.
1537 if (Irp
->MdlAddress
!= NULL
) {
1538 MmUnlockPages(Irp
->MdlAddress
);
1539 IoFreeMdl(Irp
->MdlAddress
);
1541 Irp
->MdlAddress
= NULL
;
1544 ExFreePool(context
);
1548 // Indicate the I/O system should stop processing the Irp completion.
1551 return STATUS_MORE_PROCESSING_REQUIRED
;
1553 } // ScsiClassAsynchronousCompletion()
1558 ScsiClassSplitRequest(
1559 IN PDEVICE_OBJECT DeviceObject
,
1561 IN ULONG MaximumBytes
1566 Routine Description:
1568 Break request into smaller requests. Each new request will be the
1569 maximum transfer size that the port driver can handle or if it
1570 is the final request, it may be the residual size.
1572 The number of IRPs required to process this request is written in the
1573 current stack of the original IRP. Then as each new IRP completes
1574 the count in the original IRP is decremented. When the count goes to
1575 zero, the original IRP is completed.
1579 DeviceObject - Pointer to the class device object to be addressed.
1581 Irp - Pointer to Irp the orginal request.
1590 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1591 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1592 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1593 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1594 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1595 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1596 ULONG dataLength
= MaximumBytes
;
1597 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1599 PSCSI_REQUEST_BLOCK srb
;
1601 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1602 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1605 // If all partial transfers complete successfully then the status and
1606 // bytes transferred are already set up. Failing a partial-transfer IRP
1607 // will set status to error and bytes transferred to 0 during
1608 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1609 // asynchronous partial transfers. This is an optimization for the
1613 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1614 Irp
->IoStatus
.Information
= transferByteCount
;
1617 // Save number of IRPs to complete count on current stack
1621 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1623 for (i
= 0; i
< irpCount
; i
++) {
1626 PIO_STACK_LOCATION newIrpStack
;
1629 // Allocate new IRP.
1632 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1634 if (newIrp
== NULL
) {
1636 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1639 // If an Irp can't be allocated then the orginal request cannot
1640 // be executed. If this is the first request then just fail the
1641 // orginal request; otherwise just return. When the pending
1642 // requests complete, they will complete the original request.
1643 // In either case set the IRP status to failure.
1646 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1647 Irp
->IoStatus
.Information
= 0;
1650 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1656 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1659 // Write MDL address to new IRP. In the port driver the SRB data
1660 // buffer field is used as an offset into the MDL, so the same MDL
1661 // can be used for each partial transfer. This saves having to build
1662 // a new MDL for each partial transfer.
1665 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1668 // At this point there is no current stack. IoSetNextIrpStackLocation
1669 // will make the first stack location the current stack so that the
1670 // SRB address can be written there.
1673 IoSetNextIrpStackLocation(newIrp
);
1674 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1676 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1677 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1678 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1679 newIrpStack
->DeviceObject
= DeviceObject
;
1682 // Build SRB and CDB.
1685 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1688 // Adjust SRB for this partial transfer.
1691 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1693 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1694 srb
->DataBuffer
= dataBuffer
;
1697 // Write original IRP address to new IRP.
1700 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1703 // Set the completion routine to ScsiClassIoCompleteAssociated.
1706 IoSetCompletionRoutine(newIrp
,
1707 ScsiClassIoCompleteAssociated
,
1714 // Call port driver with new request.
1717 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1720 // Set up for next request.
1723 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1725 transferByteCount
-= MaximumBytes
;
1727 if (transferByteCount
> MaximumBytes
) {
1729 dataLength
= MaximumBytes
;
1733 dataLength
= transferByteCount
;
1737 // Adjust disk byte offset.
1740 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1745 } // end ScsiClassSplitRequest()
1750 ScsiClassIoComplete(
1751 IN PDEVICE_OBJECT DeviceObject
,
1758 Routine Description:
1760 This routine executes when the port driver has completed a request.
1761 It looks at the SRB status in the completing SRB and if not success
1762 it checks for valid request sense buffer information. If valid, the
1763 info is used to update status with more precise message of type of
1764 error. This routine deallocates the SRB.
1768 DeviceObject - Supplies the device object which represents the logical
1771 Irp - Supplies the Irp which has completed.
1773 Context - Supplies a pointer to the SRB.
1782 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1783 PSCSI_REQUEST_BLOCK srb
= Context
;
1784 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1789 // Check SRB status for success of completing request.
1792 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1794 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1797 // Release the queue if it is frozen.
1800 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1801 ScsiClassReleaseQueue(DeviceObject
);
1804 retry
= ScsiClassInterpretSenseInfo(
1807 irpStack
->MajorFunction
,
1808 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1809 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1813 // If the status is verified required and the this request
1814 // should bypass verify required then retry the request.
1817 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1818 status
== STATUS_VERIFY_REQUIRED
) {
1820 status
= STATUS_IO_DEVICE_ERROR
;
1824 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1830 DebugPrint((1, "Retry request %lx\n", Irp
));
1831 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1832 return STATUS_MORE_PROCESSING_REQUIRED
;
1837 // Set status for successful request.
1840 status
= STATUS_SUCCESS
;
1842 } // end if (SRB_STATUS(srb->SrbStatus) ...
1845 // Return SRB to list.
1848 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1852 // Set status in completing IRP.
1855 Irp
->IoStatus
.Status
= status
;
1856 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1857 ASSERT(Irp
->IoStatus
.Information
);
1861 // Set the hard error if necessary.
1864 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1867 // Store DeviceObject for filesystem, and clear
1868 // in IoStatus.Information field.
1871 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1872 Irp
->IoStatus
.Information
= 0;
1876 // If pending has be returned for this irp then mark the current stack as
1880 if (Irp
->PendingReturned
) {
1881 IoMarkIrpPending(Irp
);
1884 if (deviceExtension
->ClassStartIo
) {
1885 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1886 IoStartNextPacket(DeviceObject
, FALSE
);
1892 } // end ScsiClassIoComplete()
1897 ScsiClassIoCompleteAssociated(
1898 IN PDEVICE_OBJECT DeviceObject
,
1905 Routine Description:
1907 This routine executes when the port driver has completed a request.
1908 It looks at the SRB status in the completing SRB and if not success
1909 it checks for valid request sense buffer information. If valid, the
1910 info is used to update status with more precise message of type of
1911 error. This routine deallocates the SRB. This routine is used for
1912 requests which were build by split request. After it has processed
1913 the request it decrements the Irp count in the master Irp. If the
1914 count goes to zero then the master Irp is completed.
1918 DeviceObject - Supplies the device object which represents the logical
1921 Irp - Supplies the Irp which has completed.
1923 Context - Supplies a pointer to the SRB.
1932 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1933 PSCSI_REQUEST_BLOCK srb
= Context
;
1934 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1935 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1941 // Check SRB status for success of completing request.
1944 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1946 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1949 // Release the queue if it is frozen.
1952 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1953 ScsiClassReleaseQueue(DeviceObject
);
1956 retry
= ScsiClassInterpretSenseInfo(
1959 irpStack
->MajorFunction
,
1960 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1961 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1965 // If the status is verified required and the this request
1966 // should bypass verify required then retry the request.
1969 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1970 status
== STATUS_VERIFY_REQUIRED
) {
1972 status
= STATUS_IO_DEVICE_ERROR
;
1976 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1979 // Retry request. If the class driver has supplied a StartIo,
1980 // call it directly for retries.
1983 DebugPrint((1, "Retry request %lx\n", Irp
));
1986 if (!deviceExtension->ClassStartIo) {
1987 RetryRequest(DeviceObject, Irp, srb, TRUE);
1989 deviceExtension->ClassStartIo(DeviceObject, Irp);
1993 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1995 return STATUS_MORE_PROCESSING_REQUIRED
;
2003 // Set status for successful request.
2006 status
= STATUS_SUCCESS
;
2008 } // end if (SRB_STATUS(srb->SrbStatus) ...
2011 // Return SRB to list.
2014 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
2018 // Set status in completing IRP.
2021 Irp
->IoStatus
.Status
= status
;
2023 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
2026 // Get next stack location. This original request is unused
2027 // except to keep track of the completing partial IRPs so the
2028 // stack location is valid.
2031 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
2034 // Update status only if error so that if any partial transfer
2035 // completes with error, then the original IRP will return with
2036 // error. If any of the asynchronous partial transfer IRPs fail,
2037 // with an error then the original IRP will return 0 bytes transfered.
2038 // This is an optimization for successful transfers.
2041 if (!NT_SUCCESS(status
)) {
2043 originalIrp
->IoStatus
.Status
= status
;
2044 originalIrp
->IoStatus
.Information
= 0;
2047 // Set the hard error if necessary.
2050 if (IoIsErrorUserInduced(status
)) {
2053 // Store DeviceObject for filesystem.
2056 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
2061 // Decrement and get the count of remaining IRPs.
2064 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
2066 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
2070 // Old bug could cause irp count to negative
2073 ASSERT(irpCount
>= 0);
2075 if (irpCount
== 0) {
2078 // All partial IRPs have completed.
2082 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
2085 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
2088 // If the class driver has supplied a startio, start the
2092 if (deviceExtension
->ClassStartIo
) {
2093 IoStartNextPacket(DeviceObject
, FALSE
);
2098 // Deallocate IRP and indicate the I/O system should not attempt any more
2103 return STATUS_MORE_PROCESSING_REQUIRED
;
2105 } // end ScsiClassIoCompleteAssociated()
2110 ScsiClassSendSrbSynchronous(
2111 PDEVICE_OBJECT DeviceObject
,
2112 PSCSI_REQUEST_BLOCK Srb
,
2113 PVOID BufferAddress
,
2115 BOOLEAN WriteToDevice
2120 Routine Description:
2122 This routine is called by SCSI device controls to complete an
2123 SRB and send it to the port driver synchronously (ie wait for
2124 completion). The CDB is already completed along with the SRB CDB
2125 size and request timeout value.
2129 DeviceObject - Supplies the device object which represents the logical
2132 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2134 BufferAddress - Supplies the address of the buffer.
2136 BufferLength - Supplies the length in bytes of the buffer.
2138 WriteToDevice - Indicates the data should be transfer to the device.
2142 Nt status indicating the final results of the operation.
2147 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2148 IO_STATUS_BLOCK ioStatus
;
2149 ULONG controlType
, mjFunction
;
2151 PIO_STACK_LOCATION irpStack
;
2153 PUCHAR senseInfoBuffer
;
2154 ULONG retryCount
= MAXIMUM_RETRIES
;
2157 LARGE_INTEGER dummy
;
2164 // Write length to SRB.
2167 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2170 // Set SCSI bus address.
2173 Srb
->PathId
= deviceExtension
->PathId
;
2174 Srb
->TargetId
= deviceExtension
->TargetId
;
2175 Srb
->Lun
= deviceExtension
->Lun
;
2176 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2179 // NOTICE: The SCSI-II specification indicates that this field should be
2180 // zero; however, some target controllers ignore the logical unit number
2181 // in the INDENTIFY message and only look at the logical unit number field
2185 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
2188 // Enable auto request sense.
2191 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
2194 // Sense buffer is in aligned nonpaged pool.
2197 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
2199 if (senseInfoBuffer
== NULL
) {
2202 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
2203 return(STATUS_INSUFFICIENT_RESOURCES
);
2206 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
2207 Srb
->DataBuffer
= BufferAddress
;
2210 // Start retries here.
2216 // Set the event object to the unsignaled state.
2217 // It will be used to signal request completion.
2220 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
2223 // Set controlType and Srb direction flags.
2226 if (BufferAddress
!= NULL
) {
2228 if (WriteToDevice
) {
2230 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
2231 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
2232 mjFunction
= IRP_MJ_WRITE
;
2236 controlType
= IOCTL_SCSI_EXECUTE_IN
;
2237 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
2238 mjFunction
= IRP_MJ_READ
;
2244 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
2245 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
2246 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
2250 // Build device I/O control request with data transfer.
2252 irp
= IoBuildAsynchronousFsdRequest(
2254 deviceExtension
->DeviceObject
,
2256 (BufferAddress
) ? BufferLength
: 0,
2261 ExFreePool(senseInfoBuffer
);
2262 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2263 return(STATUS_INSUFFICIENT_RESOURCES
);
2267 irp
->UserEvent
= &event
;
2270 // Disable synchronous transfer for these requests.
2273 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2276 // Set the transfer length.
2279 Srb
->DataTransferLength
= BufferLength
;
2285 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
2288 // Set completion routine
2289 IoSetCompletionRoutine(
2291 ClassCompletionRoutine
,
2298 // Get next stack location.
2301 irpStack
= IoGetNextIrpStackLocation(irp
);
2303 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2304 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2307 // Set up SRB for execute scsi request. Save SRB address in next stack
2308 // for the port driver.
2311 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2314 // Set up IRP Address.
2317 Srb
->OriginalRequest
= irp
;
2320 // Call the port driver with the request and wait for it to complete.
2323 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2325 if (status
== STATUS_PENDING
) {
2326 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2330 // Check that request completed without error.
2333 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2336 // Release the queue if it is frozen.
2339 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2340 ScsiClassReleaseQueue(DeviceObject
);
2344 // Update status and determine if request should be retried.
2347 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2351 MAXIMUM_RETRIES
- retryCount
,
2356 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2357 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2358 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2360 LARGE_INTEGER delay
;
2363 // Delay for 2 seconds.
2366 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2369 // Stall for a while to let the controller spinup.
2372 KeDelayExecutionThread(KernelMode
,
2379 // If retries are not exhausted then retry this operation.
2389 status
= STATUS_SUCCESS
;
2392 ExFreePool(senseInfoBuffer
);
2395 } // end ScsiClassSendSrbSynchronous()
2400 ScsiClassInterpretSenseInfo(
2401 IN PDEVICE_OBJECT DeviceObject
,
2402 IN PSCSI_REQUEST_BLOCK Srb
,
2403 IN UCHAR MajorFunctionCode
,
2404 IN ULONG IoDeviceCode
,
2405 IN ULONG RetryCount
,
2406 OUT NTSTATUS
*Status
2411 Routine Description:
2413 This routine interprets the data returned from the SCSI
2414 request sense. It determines the status to return in the
2415 IRP and whether this request can be retried.
2419 DeviceObject - Supplies the device object associated with this request.
2421 Srb - Supplies the scsi request block which failed.
2423 MajorFunctionCode - Supplies the function code to be used for logging.
2425 IoDeviceCode - Supplies the device code to be used for logging.
2427 Status - Returns the status for the request.
2431 BOOLEAN TRUE: Drivers should retry this request.
2432 FALSE: Drivers should not retry this request.
2437 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2438 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2439 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2440 BOOLEAN retry
= TRUE
;
2441 BOOLEAN logError
= FALSE
;
2442 ULONG badSector
= 0;
2447 PIO_ERROR_LOG_PACKET errorLogEntry
;
2454 // Check that request sense buffer is valid.
2458 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2459 for (i
= 1; i
< 12; i
++) {
2460 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2462 DebugPrint((3,"\n"));
2465 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2466 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2468 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2469 senseBuffer
->ErrorCode
));
2470 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2471 senseBuffer
->SenseKey
));
2472 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2473 senseBuffer
->AdditionalSenseCode
));
2474 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2475 senseBuffer
->AdditionalSenseCodeQualifier
));
2478 // Zero the additional sense code and additional sense code qualifier
2479 // if they were not returned by the device.
2482 readSector
= senseBuffer
->AdditionalSenseLength
+
2483 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2485 if (readSector
> Srb
->SenseInfoBufferLength
) {
2486 readSector
= Srb
->SenseInfoBufferLength
;
2489 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2490 senseBuffer
->AdditionalSenseCode
= 0;
2493 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2494 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2497 switch (senseBuffer
->SenseKey
& 0xf) {
2499 case SCSI_SENSE_NOT_READY
:
2501 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2502 *Status
= STATUS_DEVICE_NOT_READY
;
2504 switch (senseBuffer
->AdditionalSenseCode
) {
2506 case SCSI_ADSENSE_LUN_NOT_READY
:
2508 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2510 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2512 case SCSI_SENSEQ_BECOMING_READY
:
2514 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2515 " In process of becoming ready\n"));
2518 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2520 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2521 " Manual intervention required\n"));
2522 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2526 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2528 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2532 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2536 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2537 " Initializing command required\n"));
2540 // This sense code/additional sense code
2541 // combination may indicate that the device
2542 // needs to be started. Send an start unit if this
2543 // is a disk device.
2546 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2547 StartUnit(DeviceObject
);
2552 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2556 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2559 "ScsiClassInterpretSenseInfo:"
2560 " No Media in device.\n"));
2561 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2565 // signal autorun that there isn't any media in the device
2568 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2569 (!deviceExtension
->MediaChangeNoMedia
)) {
2570 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2573 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2574 "Detected No Media In Device "
2575 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2576 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2580 } // end switch (senseBuffer->AdditionalSenseCode)
2584 case SCSI_SENSE_DATA_PROTECT
:
2586 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2587 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2591 case SCSI_SENSE_MEDIUM_ERROR
:
2593 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2594 *Status
= STATUS_DEVICE_DATA_ERROR
;
2599 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2602 case SCSI_SENSE_HARDWARE_ERROR
:
2604 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2605 *Status
= STATUS_IO_DEVICE_ERROR
;
2609 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2613 case SCSI_SENSE_ILLEGAL_REQUEST
:
2615 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2616 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2618 switch (senseBuffer
->AdditionalSenseCode
) {
2620 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2621 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2625 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2626 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2627 *Status
= STATUS_NONEXISTENT_SECTOR
;
2631 case SCSI_ADSENSE_INVALID_LUN
:
2632 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2633 *Status
= STATUS_NO_SUCH_DEVICE
;
2637 case SCSI_ADSENSE_MUSIC_AREA
:
2638 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2642 case SCSI_ADSENSE_DATA_AREA
:
2643 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2647 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2648 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2652 case SCSI_ADSENSE_INVALID_CDB
:
2653 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2656 // Check if write cache enabled.
2659 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2662 // Assume FUA is not supported.
2665 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2674 } // end switch (senseBuffer->AdditionalSenseCode)
2678 case SCSI_SENSE_UNIT_ATTENTION
:
2680 switch (senseBuffer
->AdditionalSenseCode
) {
2681 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2682 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2684 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2686 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2689 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2690 "New Media Found - Setting MediaChanged event"
2691 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2692 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2697 case SCSI_ADSENSE_BUS_RESET
:
2698 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2702 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2705 } // end switch (senseBuffer->AdditionalSenseCode)
2707 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2708 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2711 // Set bit to indicate that media may have changed
2712 // and volume needs verification.
2715 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2717 *Status
= STATUS_VERIFY_REQUIRED
;
2722 *Status
= STATUS_IO_DEVICE_ERROR
;
2727 // A media change may have occured so increment the change
2728 // count for the physical device
2731 physicalExtension
->MediaChangeCount
++;
2733 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2734 "count for device %d is %d\n",
2735 physicalExtension
->DeviceNumber
,
2736 physicalExtension
->MediaChangeCount
));
2740 case SCSI_SENSE_ABORTED_COMMAND
:
2742 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2743 *Status
= STATUS_IO_DEVICE_ERROR
;
2746 case SCSI_SENSE_RECOVERED_ERROR
:
2748 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2749 *Status
= STATUS_SUCCESS
;
2754 switch(senseBuffer
->AdditionalSenseCode
) {
2755 case SCSI_ADSENSE_SEEK_ERROR
:
2756 case SCSI_ADSENSE_TRACK_ERROR
:
2757 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2760 case SCSI_ADSENSE_REC_DATA_NOECC
:
2761 case SCSI_ADSENSE_REC_DATA_ECC
:
2762 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2766 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2769 } // end switch(senseBuffer->AdditionalSenseCode)
2771 if (senseBuffer
->IncorrectLength
) {
2773 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2774 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2779 case SCSI_SENSE_NO_SENSE
:
2782 // Check other indicators.
2785 if (senseBuffer
->IncorrectLength
) {
2787 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2788 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2793 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2794 *Status
= STATUS_IO_DEVICE_ERROR
;
2802 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2803 *Status
= STATUS_IO_DEVICE_ERROR
;
2806 } // end switch (senseBuffer->SenseKey & 0xf)
2809 // Try to determine the bad sector from the inquiry data.
2812 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2813 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2814 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2816 for (index
= 0; index
< 4; index
++) {
2817 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2821 for (index
= 0; index
< 4; index
++) {
2822 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2825 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2826 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2829 // Make sure the bad sector is within the read sectors.
2832 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2833 badSector
= readSector
;
2840 // Request sense buffer not valid. No sense information
2841 // to pinpoint the error. Return general request fail.
2844 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2845 SRB_STATUS(Srb
->SrbStatus
)));
2848 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2849 case SRB_STATUS_INVALID_LUN
:
2850 case SRB_STATUS_INVALID_TARGET_ID
:
2851 case SRB_STATUS_NO_DEVICE
:
2852 case SRB_STATUS_NO_HBA
:
2853 case SRB_STATUS_INVALID_PATH_ID
:
2854 *Status
= STATUS_NO_SUCH_DEVICE
;
2858 case SRB_STATUS_COMMAND_TIMEOUT
:
2859 case SRB_STATUS_ABORTED
:
2860 case SRB_STATUS_TIMEOUT
:
2863 // Update the error count for the device.
2866 deviceExtension
->ErrorCount
++;
2867 *Status
= STATUS_IO_TIMEOUT
;
2870 case SRB_STATUS_SELECTION_TIMEOUT
:
2872 logStatus
= 0;//IO_ERR_NOT_READY;
2874 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2878 case SRB_STATUS_DATA_OVERRUN
:
2879 *Status
= STATUS_DATA_OVERRUN
;
2883 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2886 // Update the error count for the device.
2889 deviceExtension
->ErrorCount
++;
2890 *Status
= STATUS_IO_DEVICE_ERROR
;
2893 // If there was phase sequence error then limit the number of
2897 if (RetryCount
> 1 ) {
2903 case SRB_STATUS_REQUEST_FLUSHED
:
2906 // If the status needs verification bit is set. Then set
2907 // the status to need verification and no retry; otherwise,
2908 // just retry the request.
2911 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2913 *Status
= STATUS_VERIFY_REQUIRED
;
2916 *Status
= STATUS_IO_DEVICE_ERROR
;
2921 case SRB_STATUS_INVALID_REQUEST
:
2924 // An invalid request was attempted.
2927 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2931 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2932 case SRB_STATUS_PARITY_ERROR
:
2935 // Update the error count for the device.
2938 deviceExtension
->ErrorCount
++;
2941 // Fall through to below.
2944 case SRB_STATUS_BUS_RESET
:
2945 *Status
= STATUS_IO_DEVICE_ERROR
;
2948 case SRB_STATUS_ERROR
:
2950 *Status
= STATUS_IO_DEVICE_ERROR
;
2951 if (Srb
->ScsiStatus
== 0) {
2954 // This is some strange return code. Update the error
2955 // count for the device.
2958 deviceExtension
->ErrorCount
++;
2960 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2962 *Status
= STATUS_DEVICE_NOT_READY
;
2964 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2966 *Status
= STATUS_DEVICE_BUSY
;
2975 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2977 *Status
= STATUS_IO_DEVICE_ERROR
;
2983 // If the error count has exceeded the error limit, then disable
2984 // any tagged queuing, multiple requests per lu queueing
2985 // and sychronous data transfers.
2988 if (deviceExtension
->ErrorCount
== 4) {
2991 // Clearing the no queue freeze flag prevents the port driver
2992 // from sending multiple requests per logical unit.
2995 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2996 SRB_FLAGS_NO_QUEUE_FREEZE
);
2998 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2999 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
3001 } else if (deviceExtension
->ErrorCount
== 8) {
3004 // If a second threshold is reached, disable disconnects.
3007 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
3008 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
3013 // If there is a class specific error handler call it.
3016 if (deviceExtension
->ClassError
!= NULL
) {
3018 deviceExtension
->ClassError(DeviceObject
,
3025 // Log an error if necessary.
3030 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3032 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
3034 if (errorLogEntry
== NULL
) {
3037 // Return if no packet could be allocated.
3044 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
3045 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3047 errorLogEntry
->FinalStatus
= *Status
;
3051 // Calculate the device offset if there is a geometry.
3054 if (deviceExtension
->DiskGeometry
!= NULL
) {
3056 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
3057 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
3058 errorLogEntry
->DeviceOffset
,
3059 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
3062 errorLogEntry
->ErrorCode
= logStatus
;
3063 errorLogEntry
->SequenceNumber
= 0;
3064 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
3065 errorLogEntry
->IoControlCode
= IoDeviceCode
;
3066 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
3067 errorLogEntry
->UniqueErrorValue
= uniqueId
;
3068 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
3069 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
3070 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
3071 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
3072 errorLogEntry
->DumpData
[3] = 0;
3073 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
3075 if (senseBuffer
!= NULL
) {
3076 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
3077 senseBuffer
->AdditionalSenseCode
<< 8 |
3078 senseBuffer
->AdditionalSenseCodeQualifier
;
3083 // Write the error log packet.
3086 IoWriteErrorLogEntry(errorLogEntry
);
3091 } // end ScsiClassInterpretSenseInfo()
3097 PDEVICE_OBJECT DeviceObject
,
3099 PSCSI_REQUEST_BLOCK Srb
,
3105 Routine Description:
3107 This routine reinitializes the necessary fields, and sends the request
3112 DeviceObject - Supplies the device object associated with this request.
3114 Irp - Supplies the request to be retried.
3116 Srb - Supplies a Pointer to the SCSI request block to be retied.
3118 Assocaiated - Indicates this is an assocatied Irp created by split request.
3127 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3128 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3129 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3130 ULONG transferByteCount
;
3133 // Determine the transfer count of the request. If this is a read or a
3134 // write then the transfer count is in the Irp stack. Otherwise assume
3135 // the MDL contains the correct length. If there is no MDL then the
3136 // transfer length must be zero.
3139 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
3140 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
3142 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3144 } else if (Irp
->MdlAddress
!= NULL
) {
3147 // Note this assumes that only read and write requests are spilt and
3148 // other request do not need to be. If the data buffer address in
3149 // the MDL and the SRB don't match then transfer length is most
3150 // likely incorrect.
3153 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3154 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
3158 transferByteCount
= 0;
3162 // Reset byte count of transfer in SRB Extension.
3165 Srb
->DataTransferLength
= transferByteCount
;
3168 // Zero SRB statuses.
3171 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
3174 // Set the no disconnect flag, disable synchronous data transfers and
3175 // disable tagged queuing. This fixes some errors.
3178 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
3179 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3181 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
3182 Srb
->QueueTag
= SP_UNTAGGED
;
3185 // Set up major SCSI function.
3188 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3191 // Save SRB address in next stack for port driver.
3194 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
3197 // Set up IoCompletion routine address.
3202 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
3206 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3210 // Pass the request to the port driver.
3213 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3215 } // end RetryRequest()
3219 ScsiClassBuildRequest(
3220 PDEVICE_OBJECT DeviceObject
,
3226 Routine Description:
3228 This routine allocates and builds an Srb for a read or write request.
3229 The block address and length are supplied by the Irp. The retry count
3230 is stored in the current stack for use by ScsiClassIoComplete which
3231 processes these requests when they complete. The Irp is ready to be
3232 passed to the port driver when this routine returns.
3236 DeviceObject - Supplies the device object associated with this request.
3238 Irp - Supplies the request to be retried.
3242 If the IRP is for a disk transfer, the byteoffset field
3243 will already have been adjusted to make it relative to
3244 the beginning of the disk.
3254 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3255 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3256 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3257 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3258 PSCSI_REQUEST_BLOCK srb
;
3260 ULONG logicalBlockAddress
;
3261 USHORT transferBlocks
;
3264 // Calculate relative sector address.
3267 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
3273 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
3278 // Write length to SRB.
3281 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3284 // Set up IRP Address.
3287 srb
->OriginalRequest
= Irp
;
3290 // Set up target ID and logical unit number.
3293 srb
->PathId
= deviceExtension
->PathId
;
3294 srb
->TargetId
= deviceExtension
->TargetId
;
3295 srb
->Lun
= deviceExtension
->Lun
;
3296 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3297 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3300 // Save byte count of transfer in SRB Extension.
3303 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3306 // Initialize the queue actions field.
3309 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3312 // Queue sort key is Relative Block Address.
3315 srb
->QueueSortKey
= logicalBlockAddress
;
3318 // Indicate auto request sense by specifying buffer and size.
3321 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3322 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3325 // Set timeout value of one unit per 64k bytes of data.
3328 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3329 deviceExtension
->TimeOutValue
;
3335 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3339 // Indicate that 10-byte CDB's will be used.
3342 srb
->CdbLength
= 10;
3345 // Fill in CDB fields.
3348 cdb
= (PCDB
)srb
->Cdb
;
3351 // Zero 12 bytes for Atapi Packets
3354 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3356 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3357 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3360 // Move little endian values into CDB in big endian format.
3363 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3364 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3365 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3366 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3368 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3369 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3372 // Set transfer direction flag and Cdb command.
3375 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3377 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3379 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3380 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3384 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3386 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3387 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3391 // If this is not a write-through request, then allow caching.
3394 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3396 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3401 // If write caching is enable then force media access in the
3405 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3406 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3411 // Or in the default flags from the device object.
3414 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3417 // Set up major SCSI function.
3420 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3423 // Save SRB address in next stack for port driver.
3426 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3429 // Save retry count in current IRP stack.
3432 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3435 // Set up IoCompletion routine address.
3438 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3442 } // end ScsiClassBuildRequest()
3447 IN PDEVICE_OBJECT DeviceObject
,
3448 IN PCHAR ModeSenseBuffer
,
3455 Routine Description:
3457 This routine sends a mode sense command to a target ID and returns
3458 when it is complete.
3462 DeviceObject - Supplies the device object associated with this request.
3464 ModeSenseBuffer - Supplies a buffer to store the sense data.
3466 Length - Supplies the length in bytes of the mode sense buffer.
3468 PageMode - Supplies the page or pages of mode sense data to be retrived.
3472 Length of the transferred data is returned.
3476 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3478 SCSI_REQUEST_BLOCK srb
;
3482 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3485 // Build the MODE SENSE CDB.
3489 cdb
= (PCDB
)srb
.Cdb
;
3492 // Set timeout value from device extension.
3495 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3497 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3498 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3499 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3503 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3510 if (status
== STATUS_VERIFY_REQUIRED
) {
3513 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3514 // this status. MODE SENSE commands should be retried anyway.
3526 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3527 status
= STATUS_SUCCESS
;
3530 if (NT_SUCCESS(status
)) {
3531 return(srb
.DataTransferLength
);
3536 } // end ScsiClassModeSense()
3541 ScsiClassFindModePage(
3542 IN PCHAR ModeSenseBuffer
,
3550 Routine Description:
3552 This routine scans through the mode sense data and finds the requested
3553 mode sense page code.
3556 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3558 Length - Indicates the length of valid data.
3560 PageMode - Supplies the page mode to be searched for.
3562 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3566 A pointer to the the requested mode page. If the mode page was not found
3567 then NULL is return.
3572 ULONG parameterHeaderLength
;
3574 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3575 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3579 // Skip the mode select header and block descriptors.
3582 if (Length
< parameterHeaderLength
) {
3588 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3589 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3592 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3593 // requested page until the limit is reached.
3597 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3599 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3600 return(ModeSenseBuffer
);
3604 // Advance to the next page.
3607 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3615 ScsiClassSendSrbAsynchronous(
3616 PDEVICE_OBJECT DeviceObject
,
3617 PSCSI_REQUEST_BLOCK Srb
,
3619 PVOID BufferAddress
,
3621 BOOLEAN WriteToDevice
3625 Routine Description:
3627 This routine takes a partially built Srb and an Irp and sends it down to
3631 DeviceObject - Supplies the device object for the orginal request.
3633 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3634 CDB and the SRB timeout value must be filled in. The SRB must not be
3635 allocated from zone.
3637 Irp - Supplies the requesting Irp.
3639 BufferAddress - Supplies a pointer to the buffer to be transfered.
3641 BufferLength - Supplies the length of data transfer.
3643 WriteToDevice - Indicates the data transfer will be from system memory to
3648 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3653 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3654 PIO_STACK_LOCATION irpStack
;
3659 // Write length to SRB.
3662 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3665 // Set SCSI bus address.
3668 Srb
->PathId
= deviceExtension
->PathId
;
3669 Srb
->TargetId
= deviceExtension
->TargetId
;
3670 Srb
->Lun
= deviceExtension
->Lun
;
3672 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3675 // This is a violation of the SCSI spec but it is required for
3679 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3682 // Indicate auto request sense by specifying buffer and size.
3685 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3686 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3687 Srb
->DataBuffer
= BufferAddress
;
3689 if (BufferAddress
!= NULL
) {
3692 // Build Mdl if necessary.
3695 if (Irp
->MdlAddress
== NULL
) {
3697 if (IoAllocateMdl(BufferAddress
,
3703 return(STATUS_INSUFFICIENT_RESOURCES
);
3706 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3711 // Make sure the buffer requested matches the MDL.
3714 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3721 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3729 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3733 // Disable synchronous transfer for these requests.
3736 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3739 // Set the transfer length.
3742 Srb
->DataTransferLength
= BufferLength
;
3748 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3753 // Save a few parameters in the current stack location.
3756 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3759 // Save retry count in current Irp stack.
3762 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3765 // Set up IoCompletion routine address.
3768 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3771 // Get next stack location and
3772 // set major function code.
3775 irpStack
= IoGetNextIrpStackLocation(Irp
);
3777 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3780 // Save SRB address in next stack for port driver.
3783 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3786 // Set up Irp Address.
3789 Srb
->OriginalRequest
= Irp
;
3792 // Call the port driver to process the request.
3795 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3802 ScsiClassDeviceControlDispatch(
3803 PDEVICE_OBJECT DeviceObject
,
3809 Routine Description:
3811 The routine is the common class driver device control dispatch entry point.
3812 This routine is invokes the device-specific drivers DeviceControl routine,
3813 (which may call the Class driver's common DeviceControl routine).
3817 DeviceObject - Supplies a pointer to the device object for this request.
3819 Irp - Supplies the Irp making the request.
3823 Returns the status returned from the device-specific driver.
3829 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3833 // Call the class specific driver DeviceControl routine.
3834 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3837 ASSERT(deviceExtension
->ClassDeviceControl
);
3839 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3845 ScsiClassDeviceControl(
3846 PDEVICE_OBJECT DeviceObject
,
3851 Routine Description:
3853 The routine is the common class driver device control dispatch function.
3854 This routine is called by a class driver when it get an unrecognized
3855 device control request. This routine will perform the correct action for
3856 common requests such as lock media. If the device request is unknown it
3857 passed down to the next level.
3861 DeviceObject - Supplies a pointer to the device object for this request.
3863 Irp - Supplies the Irp making the request.
3867 Returns back a STATUS_PENDING or a completion status.
3872 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3873 PIO_STACK_LOCATION nextStack
;
3874 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3875 PSCSI_REQUEST_BLOCK srb
;
3878 ULONG modifiedIoControlCode
;
3880 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3881 IOCTL_STORAGE_RESET_DEVICE
) {
3883 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3884 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3885 status
= STATUS_UNSUCCESSFUL
;
3886 goto SetStatusAndReturn
;
3890 // If this is a pass through I/O control, set the minor function code
3891 // and device address and pass it to the port driver.
3894 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3895 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3897 PSCSI_PASS_THROUGH scsiPass
;
3899 nextStack
= IoGetNextIrpStackLocation(Irp
);
3902 // Validiate the user buffer.
3905 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3907 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3908 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3909 status
= STATUS_INVALID_PARAMETER
;
3910 goto SetStatusAndReturn
;
3914 // Force the SCSI address to the correct value.
3917 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3918 scsiPass
->PathId
= deviceExtension
->PathId
;
3919 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3920 scsiPass
->Lun
= deviceExtension
->Lun
;
3923 // NOTICE: The SCSI-II specificaiton indicates that this field
3924 // should be zero; however, some target controllers ignore the logical
3925 // unit number in the INDENTIFY message and only look at the logical
3926 // unit number field in the CDB.
3929 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3931 nextStack
->Parameters
= irpStack
->Parameters
;
3932 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3933 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3935 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3936 goto SetStatusAndReturn
;
3939 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3941 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3943 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3944 sizeof(SCSI_ADDRESS
)) {
3947 // Indicate unsuccessful status and no data transferred.
3950 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3951 Irp
->IoStatus
.Information
= 0;
3952 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3953 status
= STATUS_BUFFER_TOO_SMALL
;
3954 goto SetStatusAndReturn
;
3958 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3959 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3960 scsiAddress
->PathId
= deviceExtension
->PathId
;
3961 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3962 scsiAddress
->Lun
= deviceExtension
->Lun
;
3963 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3964 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3965 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3966 status
= STATUS_SUCCESS
;
3967 goto SetStatusAndReturn
;
3970 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3974 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3975 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3976 status
= STATUS_INSUFFICIENT_RESOURCES
;
3977 goto SetStatusAndReturn
;
3981 // Write zeros to Srb.
3984 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3986 cdb
= (PCDB
)srb
->Cdb
;
3989 // Change the device type to disk for the switch statement.
3992 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3993 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3995 switch (modifiedIoControlCode
) {
3997 case IOCTL_DISK_CHECK_VERIFY
: {
4000 PIO_STACK_LOCATION newStack
;
4002 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
4005 // If a buffer for a media change count was provided, make sure it's
4006 // big enough to hold the result
4009 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
4012 // If the buffer is too small to hold the media change count
4013 // then return an error to the caller
4016 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4019 DebugPrint((3,"ScsiDeviceIoControl: media count "
4020 "buffer too small\n"));
4022 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4023 Irp
->IoStatus
.Information
= 0;
4025 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4026 status
= STATUS_BUFFER_TOO_SMALL
;
4027 goto SetStatusAndReturn
;
4032 // The caller has provided a valid buffer. Allocate an additional
4033 // irp and stick the CheckVerify completion routine on it. We will
4034 // then send this down to the port driver instead of the irp the
4038 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
4042 // Allocate a new irp to send the TestUnitReady to the port driver
4045 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
4048 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4049 Irp
->IoStatus
.Information
= 0;
4051 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4052 status
= STATUS_INSUFFICIENT_RESOURCES
;
4053 goto SetStatusAndReturn
;
4058 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
4059 IoSetNextIrpStackLocation(irp2
);
4062 // Set the top stack location and shove the master Irp into the
4066 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4067 newStack
->Parameters
.Others
.Argument1
= Irp
;
4068 newStack
->DeviceObject
= DeviceObject
;
4071 // Stick the check verify completion routine onto the stack
4072 // and prepare the irp for the port driver
4075 IoSetCompletionRoutine(irp2
,
4076 ScsiClassCheckVerifyComplete
,
4082 IoSetNextIrpStackLocation(irp2
);
4083 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4084 newStack
->DeviceObject
= DeviceObject
;
4087 // Mark the master irp as pending - whether the lower level
4088 // driver completes it immediately or not this should allow it
4089 // to go all the way back up.
4092 IoMarkIrpPending(Irp
);
4103 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
4106 // Set timeout value.
4109 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4112 // Since this routine will always hand the request to the
4113 // port driver if there isn't a data transfer to be done
4114 // we don't have to worry about completing the request here
4118 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4128 case IOCTL_DISK_MEDIA_REMOVAL
: {
4130 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
4133 // Prevent/Allow media removal.
4136 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4138 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4139 sizeof(PREVENT_MEDIA_REMOVAL
)) {
4142 // Indicate unsuccessful status and no data transferred.
4145 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4146 Irp
->IoStatus
.Information
= 0;
4148 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4149 status
= STATUS_BUFFER_TOO_SMALL
;
4150 goto SetStatusAndReturn
;
4154 // Get physical device extension. This is where the
4155 // lock count is stored.
4158 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
4161 // If command succeeded then increment or decrement lock counter.
4164 if (MediaRemoval
->PreventMediaRemoval
) {
4167 // This is a lock command. Reissue the command in case bus or device
4168 // was reset and lock cleared.
4171 InterlockedIncrement(&deviceExtension
->LockCount
);
4174 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4175 deviceExtension
->LockCount
,
4176 deviceExtension
->DeviceNumber
));
4181 // This is an unlock command.
4184 if (!deviceExtension
->LockCount
||
4185 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
4188 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4189 deviceExtension
->LockCount
,
4190 deviceExtension
->DeviceNumber
));
4193 // Don't unlock because someone still wants it locked.
4196 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4198 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4199 status
= STATUS_SUCCESS
;
4200 goto SetStatusAndReturn
;
4204 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4205 deviceExtension
->LockCount
,
4206 deviceExtension
->DeviceNumber
));
4211 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
4214 // TRUE - prevent media removal.
4215 // FALSE - allow media removal.
4218 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
4221 // Set timeout value.
4224 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4225 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4233 // Some devices will not support lock/unlock.
4234 // Pretend that it worked.
4240 case IOCTL_DISK_RESERVE
: {
4243 // Reserve logical unit.
4248 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
4251 // Set timeout value.
4254 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4256 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4266 case IOCTL_DISK_RELEASE
: {
4269 // Release logical unit.
4274 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
4277 // Set timeout value.
4280 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4282 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4292 case IOCTL_DISK_EJECT_MEDIA
: {
4300 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4301 cdb
->START_STOP
.LoadEject
= 1;
4302 cdb
->START_STOP
.Start
= 0;
4305 // Set timeout value.
4308 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4309 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4318 case IOCTL_DISK_LOAD_MEDIA
: {
4324 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4328 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4329 cdb
->START_STOP
.LoadEject
= 1;
4330 cdb
->START_STOP
.Start
= 1;
4333 // Set timeout value.
4336 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4337 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4347 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4350 // Search for devices that have been powered on since the last
4351 // device search or system initialization.
4354 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4355 status
= DriverEntry(DeviceObject
->DriverObject
,
4358 Irp
->IoStatus
.Status
= status
;
4360 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4367 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4370 // Pass the device control to the next driver.
4376 // Copy the Irp stack parameters to the next stack location.
4379 nextStack
= IoGetNextIrpStackLocation(Irp
);
4380 nextStack
->Parameters
= irpStack
->Parameters
;
4381 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4382 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4384 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4388 } // end switch( ...
4398 ScsiClassShutdownFlush(
4399 IN PDEVICE_OBJECT DeviceObject
,
4405 Routine Description:
4407 This routine is called for a shutdown and flush IRPs. These are sent by the
4408 system before it actually shuts down or when the file system does a flush.
4409 If it exists, the device-specific driver's routine will be invoked. If there
4410 wasn't one specified, the Irp will be completed with an Invalid device request.
4414 DriverObject - Pointer to device object to being shutdown by system.
4425 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4427 if (deviceExtension
->ClassShutdownFlush
) {
4430 // Call the device-specific driver's routine.
4433 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4437 // Device-specific driver doesn't support this.
4440 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4441 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4443 return STATUS_INVALID_DEVICE_REQUEST
;
4449 ScsiClassFindUnclaimedDevices(
4450 IN PCLASS_INIT_DATA InitializationData
,
4451 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4455 ULONG scsiBus
,deviceCount
= 0;
4456 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4457 PSCSI_INQUIRY_DATA lunInfo
;
4458 PINQUIRYDATA inquiryData
;
4460 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4463 // Get the SCSI bus scan data for this bus.
4466 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4469 // Search list for unclaimed disk devices.
4472 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4474 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4476 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4478 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4483 if (lunInfo
->NextInquiryDataOffset
== 0) {
4487 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4497 ScsiClassCreateDeviceObject(
4498 IN PDRIVER_OBJECT DriverObject
,
4499 IN PCCHAR ObjectNameBuffer
,
4500 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4501 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4502 IN PCLASS_INIT_DATA InitializationData
4507 Routine Description:
4509 This routine creates an object for the physical device specified and
4510 sets up the deviceExtension's function pointers for each entry point
4511 in the device-specific driver.
4515 DriverObject - Pointer to driver object created by system.
4517 ObjectNameBuffer - Dir. name of the object to create.
4519 PhysicalDeviceObject - Pointer to the physical (class) device object for
4520 this logical unit or NULL if this is it.
4522 DeviceObject - Pointer to the device object pointer we will return.
4524 InitializationData - Pointer to the init data created by the device-specific driver.
4533 STRING ntNameString
;
4534 UNICODE_STRING ntUnicodeString
;
4536 PDEVICE_OBJECT deviceObject
= NULL
;
4538 *DeviceObject
= NULL
;
4541 "ScsiClassCreateDeviceObject: Create device object %s\n",
4544 RtlInitString(&ntNameString
,
4547 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4551 if (!NT_SUCCESS(status
)) {
4554 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4557 ntUnicodeString
.Buffer
= NULL
;
4561 status
= IoCreateDevice(DriverObject
,
4562 InitializationData
->DeviceExtensionSize
,
4564 InitializationData
->DeviceType
,
4565 InitializationData
->DeviceCharacteristics
,
4570 if (!NT_SUCCESS(status
)) {
4573 "CreateDiskDeviceObjects: Can not create device object %s\n",
4578 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4581 // Fill in entry points
4584 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4585 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4586 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4587 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4588 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4589 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4590 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4592 deviceExtension
->MediaChangeCount
= 0;
4595 // If a pointer to the physical device object was passed in then use
4596 // that. If the value was NULL, then this is the physical device so
4597 // use the pointer to the device we just created.
4600 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4601 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4603 deviceExtension
->PhysicalDevice
= deviceObject
;
4607 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4609 *DeviceObject
= deviceObject
;
4611 RtlFreeUnicodeString(&ntUnicodeString
);
4614 // Indicate the ntUnicodeString is free.
4617 ntUnicodeString
.Buffer
= NULL
;
4625 ScsiClassClaimDevice(
4626 IN PDEVICE_OBJECT PortDeviceObject
,
4627 IN PSCSI_INQUIRY_DATA LunInfo
,
4629 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4633 Routine Description:
4635 This function claims a device in the port driver. The port driver object
4636 is updated with the correct driver object if the device is successfully
4641 PortDeviceObject - Supplies the base port device object.
4643 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4645 Release - Indicates the logical unit should be released rather than claimed.
4647 NewPortDeviceObject - Returns the updated port device object to be used
4648 for all future accesses.
4652 Returns a status indicating success or failure of the operation.
4657 IO_STATUS_BLOCK ioStatus
;
4659 PIO_STACK_LOCATION irpStack
;
4662 SCSI_REQUEST_BLOCK srb
;
4666 if (NewPortDeviceObject
!= NULL
) {
4667 *NewPortDeviceObject
= NULL
;
4671 // Clear the SRB fields.
4674 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4677 // Write length to SRB.
4680 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4683 // Set SCSI bus address.
4686 srb
.PathId
= LunInfo
->PathId
;
4687 srb
.TargetId
= LunInfo
->TargetId
;
4688 srb
.Lun
= LunInfo
->Lun
;
4690 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4691 SRB_FUNCTION_CLAIM_DEVICE
;
4694 // Set the event object to the unsignaled state.
4695 // It will be used to signal request completion.
4698 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4701 // Build synchronous request with no transfer.
4704 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4716 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4717 return STATUS_INSUFFICIENT_RESOURCES
;
4720 irpStack
= IoGetNextIrpStackLocation(irp
);
4723 // Save SRB address in next stack for port driver.
4726 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4729 // Set up IRP Address.
4732 srb
.OriginalRequest
= irp
;
4735 // Call the port driver with the request and wait for it to complete.
4738 status
= IoCallDriver(PortDeviceObject
, irp
);
4739 if (status
== STATUS_PENDING
) {
4741 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4742 status
= ioStatus
.Status
;
4746 // If this is a release request, then just decrement the reference count
4747 // and return. The status does not matter.
4752 ObDereferenceObject(PortDeviceObject
);
4753 return STATUS_SUCCESS
;
4756 if (!NT_SUCCESS(status
)) {
4760 ASSERT(srb
.DataBuffer
!= NULL
);
4763 // Reference the new port driver object so that it will not go away while
4764 // it is being used.
4767 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4772 if (!NT_SUCCESS(status
)) {
4778 // Return the new port device object pointer.
4781 if (NewPortDeviceObject
!= NULL
) {
4782 *NewPortDeviceObject
= srb
.DataBuffer
;
4791 ScsiClassInternalIoControl (
4792 IN PDEVICE_OBJECT DeviceObject
,
4798 Routine Description:
4800 This routine passes internal device controls to the port driver.
4801 Internal device controls are used by higher level class drivers to
4802 send scsi requests to a device that are not normally sent by a generic
4805 The path ID, target ID and logical unit ID are set in the srb so the
4806 higher level driver does not have to figure out what values are actually
4811 DeviceObject - Supplies a pointer to the device object for this request.
4813 Irp - Supplies the Irp making the request.
4817 Returns back a STATUS_PENDING or a completion status.
4821 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4822 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4823 PSCSI_REQUEST_BLOCK srb
;
4826 // Get a pointer to the SRB.
4829 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4832 // Set SCSI bus address.
4835 srb
->PathId
= deviceExtension
->PathId
;
4836 srb
->TargetId
= deviceExtension
->TargetId
;
4837 srb
->Lun
= deviceExtension
->Lun
;
4840 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4841 // zero; however, some target controllers ignore the logical unit number
4842 // in the INDENTIFY message and only look at the logical unit number field
4846 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4849 // Set the parameters in the next stack location.
4852 irpStack
= IoGetNextIrpStackLocation(Irp
);
4854 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4855 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4856 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4858 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4859 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4865 IN PDEVICE_OBJECT DeviceObject
,
4872 Routine Description:
4874 This routine is called when an internal device control I/O request
4875 has completed. It marks the IRP pending if necessary and returns the
4876 status of the request.
4880 DeviceObject - Target device object.
4882 Irp - Completed request.
4888 Returns the status of the completed request.
4893 UNREFERENCED_PARAMETER(Context
);
4894 UNREFERENCED_PARAMETER(DeviceObject
);
4897 // If pending is returned for this Irp then mark current stack
4901 if (Irp
->PendingReturned
) {
4903 IoMarkIrpPending( Irp
);
4906 return Irp
->IoStatus
.Status
;
4912 ScsiClassInitializeSrbLookasideList(
4913 IN PDEVICE_EXTENSION DeviceExtension
,
4914 IN ULONG NumberElements
4919 Routine Description:
4921 This routine sets up a lookaside listhead for srbs.
4925 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4927 NumberElements - Supplies the maximum depth of the lookaside list.
4937 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4940 NonPagedPoolMustSucceed
,
4941 SCSI_REQUEST_BLOCK_SIZE
,
4943 (USHORT
)NumberElements
);
4950 ScsiClassQueryTimeOutRegistryValue(
4951 IN PUNICODE_STRING RegistryPath
4956 Routine Description:
4958 This routine determines whether a reg key for a user-specified timeout value exists.
4962 RegistryPath - Pointer to the hardware reg. entry describing the key.
4966 New default timeout for a class of devices.
4972 // Find the appropriate reg. key
4975 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4982 if (!RegistryPath
) {
4986 parameters
= ExAllocatePool(NonPagedPool
,
4987 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4993 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4994 path
= ExAllocatePool(NonPagedPool
, size
);
4997 ExFreePool(parameters
);
5001 RtlZeroMemory(path
,size
);
5002 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
5006 // Check for the Timeout value.
5009 RtlZeroMemory(parameters
,
5010 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
5012 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
5013 parameters
[0].Name
= L
"TimeOutValue";
5014 parameters
[0].EntryContext
= &timeOut
;
5015 parameters
[0].DefaultType
= REG_DWORD
;
5016 parameters
[0].DefaultData
= &zero
;
5017 parameters
[0].DefaultLength
= sizeof(ULONG
);
5019 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
5025 if (!(NT_SUCCESS(status
))) {
5029 ExFreePool(parameters
);
5033 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
5043 ScsiClassCheckVerifyComplete(
5044 IN PDEVICE_OBJECT DeviceObject
,
5051 Routine Description:
5053 This routine executes when the port driver has completed a check verify
5054 ioctl. It will set the status of the master Irp, copy the media change
5055 count and complete the request.
5059 DeviceObject - Supplies the device object which represents the logical
5062 Irp - Supplies the Irp which has completed.
5073 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5074 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5075 PDEVICE_EXTENSION physicalExtension
=
5076 deviceExtension
->PhysicalDevice
->DeviceExtension
;
5079 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
5082 // Copy the media change count and status
5085 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
5086 physicalExtension
->MediaChangeCount
;
5088 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
5089 "device %d is %d\n",
5090 physicalExtension
->DeviceNumber
,
5091 physicalExtension
->MediaChangeCount
));
5093 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
5094 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
5096 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
5100 return STATUS_MORE_PROCESSING_REQUIRED
;
5105 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
5109 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
5110 PKEVENT Event
= Irp
->UserEvent
;
5113 *IoStatusBlock
= Irp
->IoStatus
;
5114 Irp
->UserIosb
= NULL
;
5115 Irp
->UserEvent
= NULL
;
5119 Mdl
= Irp
->MdlAddress
;
5121 // if necessary - unlock pages
5122 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
5123 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
5132 // free irp and set event to unsignaled state
5134 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
5136 return STATUS_MORE_PROCESSING_REQUIRED
;