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>
19 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
20 #pragma alloc_text(PAGE, ScsiClassInitialize)
21 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
22 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
23 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
24 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
28 #define INQUIRY_DATA_SIZE 2048
29 #define START_UNIT_TIMEOUT 30
31 /* Disk layout used by Windows NT4 and earlier versions. */
32 //#define DEFAULT_SECTORS_PER_TRACK 32
33 //#define DEFAULT_TRACKS_PER_CYLINDER 64
35 /* Disk layout used by Windows 2000 and later versions. */
36 #define DEFAULT_SECTORS_PER_TRACK 63
37 #define DEFAULT_TRACKS_PER_CYLINDER 255
42 IN PDEVICE_OBJECT DeviceObject
,
49 IN PDEVICE_OBJECT DeviceObject
,
55 ScsiClassDeviceControlDispatch(
56 PDEVICE_OBJECT DeviceObject
,
62 ScsiClassDeviceControl(
63 PDEVICE_OBJECT DeviceObject
,
69 ScsiClassInternalIoControl (
70 IN PDEVICE_OBJECT DeviceObject
,
76 ScsiClassShutdownFlush(
77 IN PDEVICE_OBJECT DeviceObject
,
84 IN PDRIVER_OBJECT DriverObject
,
85 IN PUNICODE_STRING RegistryPath
89 // Class internal routines
96 PDEVICE_OBJECT DeviceObject
,
98 PSCSI_REQUEST_BLOCK Srb
,
105 IN PDEVICE_OBJECT DeviceObject
111 IN PDEVICE_OBJECT DeviceObject
,
118 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
126 IN PDRIVER_OBJECT DriverObject
,
127 IN PUNICODE_STRING RegistryPath
130 return STATUS_SUCCESS
;
133 /* The following hack to assign drive letters with a non-PnP storage stack */
135 typedef struct _CLASS_DEVICE_INFO
{
139 PDEVICE_OBJECT LowerDevice
;
140 } CLASS_DEVICE_INFO
, *PCLASS_DEVICE_INFO
;
142 typedef struct _CLASS_DRIVER_EXTENSION
{
144 CLASS_INIT_DATA InitializationData
;
145 } CLASS_DRIVER_EXTENSION
, *PCLASS_DRIVER_EXTENSION
;
149 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
152 UNICODE_STRING DriveLetterU
;
155 DriveLetterU
.Buffer
= Buffer1
;
156 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
158 /* Delete the symbolic link to PhysicalDriveX */
159 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DeviceInfo
->DriveNumber
) * sizeof(WCHAR
);
160 IoDeleteSymbolicLink(&DriveLetterU
);
162 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
164 for (Index
= 0; Index
< sizeof(ULONG
) * 8; Index
++)
166 if (DeviceInfo
->Partitions
& (1 << Index
))
168 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
169 IoDeleteSymbolicLink(&DriveLetterU
);
170 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
177 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
181 UNICODE_STRING DriveLetterU
, PartitionU
;
183 ULONG Index
, PartitionNumber
, DeviceNumber
, DriveNumber
;
184 OBJECT_ATTRIBUTES ObjectAttributes
;
185 IO_STATUS_BLOCK Iosb
;
186 HANDLE PartitionHandle
;
188 /* We assume this device does not current have a drive letter */
194 DriveLetterU
.Buffer
= Buffer1
;
195 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
196 PartitionU
.Buffer
= Buffer2
;
197 PartitionU
.MaximumLength
= sizeof(Buffer2
);
199 /* Determine the correct disk number */
202 /* Check that the disk exists */
203 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\HardDisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
204 InitializeObjectAttributes(&ObjectAttributes
,
206 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
209 Status
= ZwOpenFile(&PartitionHandle
,
210 FILE_READ_ATTRIBUTES
,
215 if (!NT_SUCCESS(Status
))
217 /* Return the last one that worked */
222 ZwClose(PartitionHandle
);
225 } while (Status
== STATUS_SUCCESS
);
227 /* Determine the correct drive number */
230 /* Check that the drive exists */
231 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
232 InitializeObjectAttributes(&ObjectAttributes
,
234 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
237 Status
= ZwOpenFile(&PartitionHandle
,
238 FILE_READ_ATTRIBUTES
,
243 if (NT_SUCCESS(Status
))
245 ZwClose(PartitionHandle
);
248 } while (Status
== STATUS_SUCCESS
);
250 /* Create the symbolic link to PhysicalDriveX */
251 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
252 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
254 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
255 if (!NT_SUCCESS(Status
))
257 /* Failed to create symbolic link */
261 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
265 /* Check that the disk exists */
266 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", DeviceNumber
, PartitionNumber
) * sizeof(WCHAR
);
267 InitializeObjectAttributes(&ObjectAttributes
,
269 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
272 Status
= ZwOpenFile(&PartitionHandle
,
273 FILE_READ_ATTRIBUTES
,
278 if (!NT_SUCCESS(Status
))
282 ZwClose(PartitionHandle
);
284 /* Assign it a drive letter */
287 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
289 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
292 } while (Status
!= STATUS_SUCCESS
);
294 DeviceInfo
->Partitions
|= (1 << (Index
- 1));
296 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
301 DeviceInfo
->DeviceNumber
= DeviceNumber
;
302 DeviceInfo
->DriveNumber
= DriveNumber
;
304 return STATUS_SUCCESS
;
310 IN PDEVICE_OBJECT DeviceObject
,
313 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
315 if (IrpSp
->MinorFunction
== IRP_MN_START_DEVICE
)
317 IoSkipCurrentIrpStackLocation(Irp
);
318 return STATUS_SUCCESS
;
320 else if (IrpSp
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
322 PCLASS_DEVICE_INFO DeviceInfo
= DeviceObject
->DeviceExtension
;
324 ScsiClassRemoveDriveLetter(DeviceInfo
);
326 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
327 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
329 IoDetachDevice(DeviceInfo
->LowerDevice
);
330 IoDeleteDevice(DeviceObject
);
331 return STATUS_SUCCESS
;
335 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
336 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
337 return STATUS_NOT_SUPPORTED
;
344 IN PDRIVER_OBJECT DriverObject
,
345 IN PDEVICE_OBJECT PhysicalDeviceObject
)
347 PCLASS_DRIVER_EXTENSION DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
348 PCLASS_DEVICE_INFO DeviceInfo
;
349 PDEVICE_OBJECT DeviceObject
;
352 if (DriverExtension
->InitializationData
.ClassFindDevices(DriverObject
, NULL
, &DriverExtension
->InitializationData
,
353 PhysicalDeviceObject
, DriverExtension
->PortNumber
))
355 /* Create a device object */
356 Status
= IoCreateDevice(DriverObject
,
357 sizeof(CLASS_DEVICE_INFO
),
363 if (!NT_SUCCESS(Status
))
368 DeviceInfo
= DeviceObject
->DeviceExtension
;
369 RtlZeroMemory(DeviceInfo
, sizeof(CLASS_DEVICE_INFO
));
371 /* Attach it to the PDO */
372 DeviceInfo
->LowerDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
374 /* Assign a drive letter */
375 ScsiClassAssignDriveLetter(DeviceInfo
);
379 /* Failed to find device */
380 DbgPrint("FAILED TO FIND DEVICE!\n");
383 return STATUS_SUCCESS
;
385 /* ---- End hack ---- */
394 IN PCLASS_INIT_DATA InitializationData
401 This routine is called by a class driver during its
402 DriverEntry routine to initialize the driver.
406 Argument1 - Driver Object.
407 Argument2 - Registry Path.
408 InitializationData - Device-specific driver's initialization data.
412 A valid return code for a DriverEntry routine.
419 PDRIVER_OBJECT DriverObject
= Argument1
;
420 PDEVICE_OBJECT portDeviceObject
;
422 STRING deviceNameString
;
423 UNICODE_STRING unicodeDeviceName
;
424 PFILE_OBJECT fileObject
;
425 CCHAR deviceNameBuffer
[256];
426 BOOLEAN deviceFound
= FALSE
;
427 PCLASS_DRIVER_EXTENSION DriverExtension
;
429 DebugPrint((3,"\n\nSCSI Class Driver\n"));
432 // Validate the length of this structure. This is effectively a
436 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
438 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
439 return (ULONG
) STATUS_REVISION_MISMATCH
;
443 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
444 // are not required entry points.
447 if ((!InitializationData
->ClassFindDevices
) ||
448 (!InitializationData
->ClassDeviceControl
) ||
449 (!((InitializationData
->ClassReadWriteVerification
) ||
450 (InitializationData
->ClassStartIo
)))) {
453 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
455 return (ULONG
) STATUS_REVISION_MISMATCH
;
458 status
= IoAllocateDriverObjectExtension(DriverObject
,
460 sizeof(CLASS_DRIVER_EXTENSION
),
461 (PVOID
*)&DriverExtension
);
462 if (!NT_SUCCESS(status
))
465 RtlCopyMemory(&DriverExtension
->InitializationData
, InitializationData
, sizeof(CLASS_INIT_DATA
));
466 DriverExtension
->PortNumber
= 0;
469 // Update driver object with entry points.
472 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
473 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
474 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
475 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
476 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ScsiClassPlugPlay
;
477 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
478 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
479 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
480 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
481 DriverObject
->DriverExtension
->AddDevice
= ScsiClassAddDevice
;
483 if (InitializationData
->ClassStartIo
) {
484 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
488 // Open port driver controller device objects by name.
493 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", DriverExtension
->PortNumber
);
495 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
497 RtlInitString(&deviceNameString
, deviceNameBuffer
);
499 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
503 if (!NT_SUCCESS(status
)){
507 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
508 FILE_READ_ATTRIBUTES
,
512 if (NT_SUCCESS(status
)) {
515 // Call the device-specific driver's FindDevice routine.
518 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
519 portDeviceObject
, DriverExtension
->PortNumber
)) {
526 // Check next SCSI adapter.
529 DriverExtension
->PortNumber
++;
531 } while(NT_SUCCESS(status
));
533 return deviceFound
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
539 ScsiClassCreateClose(
540 IN PDEVICE_OBJECT DeviceObject
,
548 SCSI class driver create and close routine. This is called by the I/O system
549 when the device is opened or closed.
553 DriverObject - Pointer to driver object created by system.
559 Device-specific drivers return value or STATUS_SUCCESS.
564 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
567 // Invoke the device-specific routine, if one exists. Otherwise complete
571 if (deviceExtension
->ClassCreateClose
) {
573 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
576 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
578 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
579 return(STATUS_SUCCESS
);
588 IN PDEVICE_OBJECT DeviceObject
,
596 This is the system entry point for read and write requests. The device-specific handler is invoked
597 to perform any validation necessary. The number of bytes in the request are
598 checked against the maximum byte counts that the adapter supports and requests are broken up into
599 smaller sizes if necessary.
613 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
614 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
616 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
617 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
620 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
621 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
624 // if DO_VERIFY_VOLUME bit is set
625 // in device object flags, fail request.
628 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
630 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
631 Irp
->IoStatus
.Information
= 0;
633 IoCompleteRequest(Irp
, 0);
634 return STATUS_VERIFY_REQUIRED
;
638 // Invoke the device specific routine to do whatever it needs to verify
642 ASSERT(deviceExtension
->ClassReadWriteVerification
);
644 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
646 if (!NT_SUCCESS(status
)) {
649 // It is up to the device specific driver to set the Irp status.
652 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
654 } else if (status
== STATUS_PENDING
) {
656 IoMarkIrpPending(Irp
);
657 return STATUS_PENDING
;
661 // Check for a zero length IO, as several macros will turn this into
662 // seemingly a 0xffffffff length request.
665 if (transferByteCount
== 0) {
666 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
667 Irp
->IoStatus
.Information
= 0;
668 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
669 return STATUS_SUCCESS
;
673 if (deviceExtension
->ClassStartIo
) {
675 IoMarkIrpPending(Irp
);
677 IoStartPacket(DeviceObject
,
682 return STATUS_PENDING
;
686 // Mark IRP with status pending.
689 IoMarkIrpPending(Irp
);
692 // Add partition byte offset to make starting byte relative to
693 // beginning of disk. In addition, add in skew for DM Driver, if any.
696 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
697 deviceExtension
->DMByteSkew
);
700 // Calculate number of pages in this transfer.
703 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
704 currentIrpStack
->Parameters
.Read
.Length
);
707 // Check if request length is greater than the maximum number of
708 // bytes that the hardware can transfer.
711 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
712 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
714 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
715 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
716 maximumTransferLength
));
717 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
718 currentIrpStack
->Parameters
.Read
.Length
));
721 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
723 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
724 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
728 // Check that maximum transfer size is not zero.
731 if (maximumTransferLength
== 0) {
732 maximumTransferLength
= PAGE_SIZE
;
736 // Mark IRP with status pending.
739 IoMarkIrpPending(Irp
);
742 // Request greater than port driver maximum.
743 // Break up into smaller routines.
746 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
749 return STATUS_PENDING
;
753 // Build SRB and CDB for this IRP.
756 ScsiClassBuildRequest(DeviceObject
, Irp
);
759 // Return the results of the call to the port driver.
762 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
764 } // end ScsiClassReadWrite()
769 ScsiClassGetCapabilities(
770 IN PDEVICE_OBJECT PortDeviceObject
,
771 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
778 This routine builds and sends a request to the port driver to
779 get a pointer to a structure that describes the adapter's
780 capabilities/limitations. This routine is sychronous.
784 PortDeviceObject - Port driver device object representing the HBA.
786 PortCapabilities - Location to store pointer to capabilities structure.
790 Nt status indicating the results of the operation.
794 This routine should only be called at initialization time.
800 IO_STATUS_BLOCK ioStatus
;
807 // Create notification event object to be used to signal the
808 // request completion.
811 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
814 // Build the synchronous request to be sent to the port driver
815 // to perform the request.
818 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
829 return STATUS_INSUFFICIENT_RESOURCES
;
833 // Pass request to port driver and wait for request to complete.
836 status
= IoCallDriver(PortDeviceObject
, irp
);
838 if (status
== STATUS_PENDING
) {
839 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
840 return(ioStatus
.Status
);
845 } // end ScsiClassGetCapabilities()
850 ScsiClassGetInquiryData(
851 IN PDEVICE_OBJECT PortDeviceObject
,
852 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
859 This routine sends a request to a port driver to return
860 configuration information. Space for the information is
861 allocated by this routine. The caller is responsible for
862 freeing the configuration information. This routine is
867 PortDeviceObject - Port driver device object representing the HBA.
869 ConfigInfo - Returns a pointer to the configuration information.
873 Nt status indicating the results of the operation.
877 This routine should be called only at initialization time.
883 IO_STATUS_BLOCK ioStatus
;
886 PSCSI_ADAPTER_BUS_INFO buffer
;
890 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
891 *ConfigInfo
= buffer
;
893 if (buffer
== NULL
) {
894 return(STATUS_INSUFFICIENT_RESOURCES
);
898 // Create notification event object to be used to signal the inquiry
899 // request completion.
902 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
905 // Build the synchronous request to be sent to the port driver
906 // to perform the inquiries.
909 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
920 return(STATUS_INSUFFICIENT_RESOURCES
);
924 // Pass request to port driver and wait for request to complete.
927 status
= IoCallDriver(PortDeviceObject
, irp
);
929 if (status
== STATUS_PENDING
) {
930 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
931 status
= ioStatus
.Status
;
934 if (!NT_SUCCESS(status
)) {
937 // Free the buffer on an error.
947 } // end ScsiClassGetInquiryData()
952 ScsiClassReadDriveCapacity(
953 IN PDEVICE_OBJECT DeviceObject
960 This routine sends a READ CAPACITY to the requested device, updates
961 the geometry information in the device object and returns
962 when it is complete. This routine is synchronous.
966 DeviceObject - Supplies a pointer to the device object that represents
967 the device whose capacity is to be read.
975 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
979 PREAD_CAPACITY_DATA readCapacityBuffer
;
980 SCSI_REQUEST_BLOCK srb
;
984 // Allocate read capacity buffer from nonpaged pool.
987 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
988 sizeof(READ_CAPACITY_DATA
));
990 if (!readCapacityBuffer
) {
991 return(STATUS_INSUFFICIENT_RESOURCES
);
994 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
997 // Build the read capacity CDB.
1001 cdb
= (PCDB
)srb
.Cdb
;
1004 // Set timeout value from device extension.
1007 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1009 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1013 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
1016 sizeof(READ_CAPACITY_DATA
),
1019 if (NT_SUCCESS(status
)) {
1022 // Copy sector size from read capacity buffer to device extension
1023 // in reverse byte order.
1026 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
1027 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
1029 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
1030 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
1032 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
1033 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
1035 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
1036 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
1039 // Copy last sector in reverse byte order.
1042 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
1043 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
1045 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
1046 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
1048 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
1049 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
1051 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
1052 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
1055 // Calculate sector to byte shift.
1058 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
1060 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
1061 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
1063 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
1067 // Calculate media capacity in bytes.
1070 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
1073 // Calculate number of cylinders.
1076 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
1078 deviceExtension
->PartitionLength
.QuadPart
=
1079 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
1081 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1084 // This device supports removable media.
1087 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1092 // Assume media type is fixed disk.
1095 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1099 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
1102 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
1105 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
1108 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
1111 if (status
== STATUS_VERIFY_REQUIRED
) {
1114 // Routine ScsiClassSendSrbSynchronous does not retry
1115 // requests returned with this status.
1116 // Read Capacities should be retried
1130 if (!NT_SUCCESS(status
)) {
1133 // If the read capacity fails, set the geometry to reasonable parameter
1134 // so things don't fail at unexpected places. Zero the geometry
1135 // except for the bytes per sector and sector shift.
1138 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
1139 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1140 deviceExtension
->SectorShift
= 9;
1141 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
1143 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1146 // This device supports removable media.
1149 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1154 // Assume media type is fixed disk.
1157 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1162 // Deallocate read capacity buffer.
1165 ExFreePool(readCapacityBuffer
);
1169 } // end ScsiClassReadDriveCapacity()
1174 ScsiClassReleaseQueue(
1175 IN PDEVICE_OBJECT DeviceObject
1180 Routine Description:
1182 This routine issues an internal device control command
1183 to the port driver to release a frozen queue. The call
1184 is issued asynchronously as ScsiClassReleaseQueue will be invoked
1185 from the IO completion DPC (and will have no context to
1186 wait for a synchronous call to complete).
1190 DeviceObject - The device object for the logical unit with
1199 PIO_STACK_LOCATION irpStack
;
1201 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1202 PCOMPLETION_CONTEXT context
;
1203 PSCSI_REQUEST_BLOCK srb
;
1207 // Allocate context from nonpaged pool.
1210 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1211 sizeof(COMPLETION_CONTEXT
));
1214 // Save the device object in the context for use by the completion
1218 context
->DeviceObject
= DeviceObject
;
1219 srb
= &context
->Srb
;
1225 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1228 // Write length to SRB.
1231 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1234 // Set up SCSI bus address.
1237 srb
->PathId
= deviceExtension
->PathId
;
1238 srb
->TargetId
= deviceExtension
->TargetId
;
1239 srb
->Lun
= deviceExtension
->Lun
;
1242 // If this device is removable then flush the queue. This will also
1246 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1248 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
1252 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
1257 // Build the asynchronous request to be sent to the port driver.
1260 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1265 // We have no better way of dealing with this at the moment
1268 KeBugCheck((ULONG
)0x0000002DL
);
1272 IoSetCompletionRoutine(irp
,
1273 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1279 irpStack
= IoGetNextIrpStackLocation(irp
);
1281 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1283 srb
->OriginalRequest
= irp
;
1286 // Store the SRB address in next stack for port driver.
1289 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1292 // Since this routine can cause outstanding requests to be completed, and
1293 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1294 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1295 // issuing the request
1298 currentIrql
= KeGetCurrentIrql();
1300 if(currentIrql
< DISPATCH_LEVEL
) {
1301 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1302 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1303 KeLowerIrql(currentIrql
);
1305 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1310 } // end ScsiClassReleaseQueue()
1316 IN PDEVICE_OBJECT DeviceObject
1321 Routine Description:
1323 Send command to SCSI unit to start or power up.
1324 Because this command is issued asynchronounsly, that is, without
1325 waiting on it to complete, the IMMEDIATE flag is not set. This
1326 means that the CDB will not return until the drive has powered up.
1327 This should keep subsequent requests from being submitted to the
1328 device before it has completely spun up.
1329 This routine is called from the InterpretSense routine, when a
1330 request sense returns data indicating that a drive must be
1335 DeviceObject - The device object for the logical unit with
1344 PIO_STACK_LOCATION irpStack
;
1346 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1347 PSCSI_REQUEST_BLOCK srb
;
1348 PCOMPLETION_CONTEXT context
;
1352 // Allocate Srb from nonpaged pool.
1355 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1356 sizeof(COMPLETION_CONTEXT
));
1359 // Save the device object in the context for use by the completion
1363 context
->DeviceObject
= DeviceObject
;
1364 srb
= &context
->Srb
;
1370 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1373 // Write length to SRB.
1376 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1379 // Set up SCSI bus address.
1382 srb
->PathId
= deviceExtension
->PathId
;
1383 srb
->TargetId
= deviceExtension
->TargetId
;
1384 srb
->Lun
= deviceExtension
->Lun
;
1386 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1389 // Set timeout value large enough for drive to spin up.
1392 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1395 // Set the transfer length.
1398 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1401 // Build the start unit CDB.
1405 cdb
= (PCDB
)srb
->Cdb
;
1407 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1408 cdb
->START_STOP
.Start
= 1;
1409 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1412 // Build the asynchronous request to be sent to the port driver.
1413 // Since this routine is called from a DPC the IRP should always be
1417 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1418 IoSetCompletionRoutine(irp
,
1419 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1425 irpStack
= IoGetNextIrpStackLocation(irp
);
1426 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1427 srb
->OriginalRequest
= irp
;
1430 // Store the SRB address in next stack for port driver.
1433 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1436 // Call the port driver with the IRP.
1439 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1443 } // end StartUnit()
1448 ScsiClassAsynchronousCompletion(
1449 PDEVICE_OBJECT DeviceObject
,
1455 Routine Description:
1457 This routine is called when an asynchronous I/O request
1458 which was issused by the class driver completes. Examples of such requests
1459 are release queue or START UNIT. This routine releases the queue if
1460 necessary. It then frees the context and the IRP.
1464 DeviceObject - The device object for the logical unit; however since this
1465 is the top stack location the value is NULL.
1467 Irp - Supplies a pointer to the Irp to be processed.
1469 Context - Supplies the context to be used to process this request.
1478 PCOMPLETION_CONTEXT context
= Context
;
1479 PSCSI_REQUEST_BLOCK srb
;
1481 srb
= &context
->Srb
;
1484 // If this is an execute srb, then check the return status and make sure.
1485 // the queue is not frozen.
1488 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1491 // Check for a frozen queue.
1494 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1497 // Unfreeze the queue getting the device object from the context.
1500 ScsiClassReleaseQueue(context
->DeviceObject
);
1505 // Free the context and the Irp.
1508 if (Irp
->MdlAddress
!= NULL
) {
1509 MmUnlockPages(Irp
->MdlAddress
);
1510 IoFreeMdl(Irp
->MdlAddress
);
1512 Irp
->MdlAddress
= NULL
;
1515 ExFreePool(context
);
1519 // Indicate the I/O system should stop processing the Irp completion.
1522 return STATUS_MORE_PROCESSING_REQUIRED
;
1524 } // ScsiClassAsynchronousCompletion()
1529 ScsiClassSplitRequest(
1530 IN PDEVICE_OBJECT DeviceObject
,
1532 IN ULONG MaximumBytes
1537 Routine Description:
1539 Break request into smaller requests. Each new request will be the
1540 maximum transfer size that the port driver can handle or if it
1541 is the final request, it may be the residual size.
1543 The number of IRPs required to process this request is written in the
1544 current stack of the original IRP. Then as each new IRP completes
1545 the count in the original IRP is decremented. When the count goes to
1546 zero, the original IRP is completed.
1550 DeviceObject - Pointer to the class device object to be addressed.
1552 Irp - Pointer to Irp the orginal request.
1561 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1562 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1563 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1564 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1565 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1566 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1567 ULONG dataLength
= MaximumBytes
;
1568 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1570 PSCSI_REQUEST_BLOCK srb
;
1572 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1573 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1576 // If all partial transfers complete successfully then the status and
1577 // bytes transferred are already set up. Failing a partial-transfer IRP
1578 // will set status to error and bytes transferred to 0 during
1579 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1580 // asynchronous partial transfers. This is an optimization for the
1584 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1585 Irp
->IoStatus
.Information
= transferByteCount
;
1588 // Save number of IRPs to complete count on current stack
1592 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1594 for (i
= 0; i
< irpCount
; i
++) {
1597 PIO_STACK_LOCATION newIrpStack
;
1600 // Allocate new IRP.
1603 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1605 if (newIrp
== NULL
) {
1607 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1610 // If an Irp can't be allocated then the orginal request cannot
1611 // be executed. If this is the first request then just fail the
1612 // orginal request; otherwise just return. When the pending
1613 // requests complete, they will complete the original request.
1614 // In either case set the IRP status to failure.
1617 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1618 Irp
->IoStatus
.Information
= 0;
1621 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1627 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1630 // Write MDL address to new IRP. In the port driver the SRB data
1631 // buffer field is used as an offset into the MDL, so the same MDL
1632 // can be used for each partial transfer. This saves having to build
1633 // a new MDL for each partial transfer.
1636 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1639 // At this point there is no current stack. IoSetNextIrpStackLocation
1640 // will make the first stack location the current stack so that the
1641 // SRB address can be written there.
1644 IoSetNextIrpStackLocation(newIrp
);
1645 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1647 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1648 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1649 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1650 newIrpStack
->DeviceObject
= DeviceObject
;
1653 // Build SRB and CDB.
1656 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1659 // Adjust SRB for this partial transfer.
1662 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1664 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1665 srb
->DataBuffer
= dataBuffer
;
1668 // Write original IRP address to new IRP.
1671 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1674 // Set the completion routine to ScsiClassIoCompleteAssociated.
1677 IoSetCompletionRoutine(newIrp
,
1678 ScsiClassIoCompleteAssociated
,
1685 // Call port driver with new request.
1688 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1691 // Set up for next request.
1694 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1696 transferByteCount
-= MaximumBytes
;
1698 if (transferByteCount
> MaximumBytes
) {
1700 dataLength
= MaximumBytes
;
1704 dataLength
= transferByteCount
;
1708 // Adjust disk byte offset.
1711 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1716 } // end ScsiClassSplitRequest()
1721 ScsiClassIoComplete(
1722 IN PDEVICE_OBJECT DeviceObject
,
1729 Routine Description:
1731 This routine executes when the port driver has completed a request.
1732 It looks at the SRB status in the completing SRB and if not success
1733 it checks for valid request sense buffer information. If valid, the
1734 info is used to update status with more precise message of type of
1735 error. This routine deallocates the SRB.
1739 DeviceObject - Supplies the device object which represents the logical
1742 Irp - Supplies the Irp which has completed.
1744 Context - Supplies a pointer to the SRB.
1753 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1754 PSCSI_REQUEST_BLOCK srb
= Context
;
1755 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1760 // Check SRB status for success of completing request.
1763 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1765 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1768 // Release the queue if it is frozen.
1771 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1772 ScsiClassReleaseQueue(DeviceObject
);
1775 retry
= ScsiClassInterpretSenseInfo(
1778 irpStack
->MajorFunction
,
1779 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1780 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1784 // If the status is verified required and the this request
1785 // should bypass verify required then retry the request.
1788 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1789 status
== STATUS_VERIFY_REQUIRED
) {
1791 status
= STATUS_IO_DEVICE_ERROR
;
1795 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1801 DebugPrint((1, "Retry request %lx\n", Irp
));
1802 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1803 return STATUS_MORE_PROCESSING_REQUIRED
;
1808 // Set status for successful request.
1811 status
= STATUS_SUCCESS
;
1813 } // end if (SRB_STATUS(srb->SrbStatus) ...
1816 // Return SRB to list.
1819 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1823 // Set status in completing IRP.
1826 Irp
->IoStatus
.Status
= status
;
1827 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1828 ASSERT(Irp
->IoStatus
.Information
);
1832 // Set the hard error if necessary.
1835 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1838 // Store DeviceObject for filesystem, and clear
1839 // in IoStatus.Information field.
1842 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1843 Irp
->IoStatus
.Information
= 0;
1847 // If pending has be returned for this irp then mark the current stack as
1851 if (Irp
->PendingReturned
) {
1852 IoMarkIrpPending(Irp
);
1855 if (deviceExtension
->ClassStartIo
) {
1856 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1857 IoStartNextPacket(DeviceObject
, FALSE
);
1863 } // end ScsiClassIoComplete()
1868 ScsiClassIoCompleteAssociated(
1869 IN PDEVICE_OBJECT DeviceObject
,
1876 Routine Description:
1878 This routine executes when the port driver has completed a request.
1879 It looks at the SRB status in the completing SRB and if not success
1880 it checks for valid request sense buffer information. If valid, the
1881 info is used to update status with more precise message of type of
1882 error. This routine deallocates the SRB. This routine is used for
1883 requests which were build by split request. After it has processed
1884 the request it decrements the Irp count in the master Irp. If the
1885 count goes to zero then the master Irp is completed.
1889 DeviceObject - Supplies the device object which represents the logical
1892 Irp - Supplies the Irp which has completed.
1894 Context - Supplies a pointer to the SRB.
1903 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1904 PSCSI_REQUEST_BLOCK srb
= Context
;
1905 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1906 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1912 // Check SRB status for success of completing request.
1915 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1917 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1920 // Release the queue if it is frozen.
1923 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1924 ScsiClassReleaseQueue(DeviceObject
);
1927 retry
= ScsiClassInterpretSenseInfo(
1930 irpStack
->MajorFunction
,
1931 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1932 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1936 // If the status is verified required and the this request
1937 // should bypass verify required then retry the request.
1940 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1941 status
== STATUS_VERIFY_REQUIRED
) {
1943 status
= STATUS_IO_DEVICE_ERROR
;
1947 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1950 // Retry request. If the class driver has supplied a StartIo,
1951 // call it directly for retries.
1954 DebugPrint((1, "Retry request %lx\n", Irp
));
1957 if (!deviceExtension->ClassStartIo) {
1958 RetryRequest(DeviceObject, Irp, srb, TRUE);
1960 deviceExtension->ClassStartIo(DeviceObject, Irp);
1964 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1966 return STATUS_MORE_PROCESSING_REQUIRED
;
1974 // Set status for successful request.
1977 status
= STATUS_SUCCESS
;
1979 } // end if (SRB_STATUS(srb->SrbStatus) ...
1982 // Return SRB to list.
1985 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1989 // Set status in completing IRP.
1992 Irp
->IoStatus
.Status
= status
;
1994 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
1997 // Get next stack location. This original request is unused
1998 // except to keep track of the completing partial IRPs so the
1999 // stack location is valid.
2002 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
2005 // Update status only if error so that if any partial transfer
2006 // completes with error, then the original IRP will return with
2007 // error. If any of the asynchronous partial transfer IRPs fail,
2008 // with an error then the original IRP will return 0 bytes transfered.
2009 // This is an optimization for successful transfers.
2012 if (!NT_SUCCESS(status
)) {
2014 originalIrp
->IoStatus
.Status
= status
;
2015 originalIrp
->IoStatus
.Information
= 0;
2018 // Set the hard error if necessary.
2021 if (IoIsErrorUserInduced(status
)) {
2024 // Store DeviceObject for filesystem.
2027 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
2032 // Decrement and get the count of remaining IRPs.
2035 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
2037 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
2041 // Old bug could cause irp count to negative
2044 ASSERT(irpCount
>= 0);
2046 if (irpCount
== 0) {
2049 // All partial IRPs have completed.
2053 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
2056 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
2059 // If the class driver has supplied a startio, start the
2063 if (deviceExtension
->ClassStartIo
) {
2064 IoStartNextPacket(DeviceObject
, FALSE
);
2069 // Deallocate IRP and indicate the I/O system should not attempt any more
2074 return STATUS_MORE_PROCESSING_REQUIRED
;
2076 } // end ScsiClassIoCompleteAssociated()
2081 ScsiClassSendSrbSynchronous(
2082 PDEVICE_OBJECT DeviceObject
,
2083 PSCSI_REQUEST_BLOCK Srb
,
2084 PVOID BufferAddress
,
2086 BOOLEAN WriteToDevice
2091 Routine Description:
2093 This routine is called by SCSI device controls to complete an
2094 SRB and send it to the port driver synchronously (ie wait for
2095 completion). The CDB is already completed along with the SRB CDB
2096 size and request timeout value.
2100 DeviceObject - Supplies the device object which represents the logical
2103 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2105 BufferAddress - Supplies the address of the buffer.
2107 BufferLength - Supplies the length in bytes of the buffer.
2109 WriteToDevice - Indicates the data should be transfer to the device.
2113 Nt status indicating the final results of the operation.
2118 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2119 IO_STATUS_BLOCK ioStatus
;
2120 ULONG controlType
, mjFunction
;
2122 PIO_STACK_LOCATION irpStack
;
2124 PUCHAR senseInfoBuffer
;
2125 ULONG retryCount
= MAXIMUM_RETRIES
;
2128 LARGE_INTEGER dummy
;
2135 // Write length to SRB.
2138 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2141 // Set SCSI bus address.
2144 Srb
->PathId
= deviceExtension
->PathId
;
2145 Srb
->TargetId
= deviceExtension
->TargetId
;
2146 Srb
->Lun
= deviceExtension
->Lun
;
2147 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2150 // NOTICE: The SCSI-II specification indicates that this field should be
2151 // zero; however, some target controllers ignore the logical unit number
2152 // in the INDENTIFY message and only look at the logical unit number field
2156 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
2159 // Enable auto request sense.
2162 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
2165 // Sense buffer is in aligned nonpaged pool.
2168 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
2170 if (senseInfoBuffer
== NULL
) {
2173 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
2174 return(STATUS_INSUFFICIENT_RESOURCES
);
2177 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
2178 Srb
->DataBuffer
= BufferAddress
;
2181 // Start retries here.
2187 // Set the event object to the unsignaled state.
2188 // It will be used to signal request completion.
2191 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
2194 // Set controlType and Srb direction flags.
2197 if (BufferAddress
!= NULL
) {
2199 if (WriteToDevice
) {
2201 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
2202 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
2203 mjFunction
= IRP_MJ_WRITE
;
2207 controlType
= IOCTL_SCSI_EXECUTE_IN
;
2208 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
2209 mjFunction
= IRP_MJ_READ
;
2215 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
2216 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
2217 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
2221 // Build device I/O control request with data transfer.
2223 irp
= IoBuildAsynchronousFsdRequest(
2225 deviceExtension
->DeviceObject
,
2227 (BufferAddress
) ? BufferLength
: 0,
2232 ExFreePool(senseInfoBuffer
);
2233 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2234 return(STATUS_INSUFFICIENT_RESOURCES
);
2238 irp
->UserEvent
= &event
;
2241 // Disable synchronous transfer for these requests.
2244 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2247 // Set the transfer length.
2250 Srb
->DataTransferLength
= BufferLength
;
2256 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
2259 // Set completion routine
2260 IoSetCompletionRoutine(
2262 ClassCompletionRoutine
,
2269 // Get next stack location.
2272 irpStack
= IoGetNextIrpStackLocation(irp
);
2274 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2275 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2278 // Set up SRB for execute scsi request. Save SRB address in next stack
2279 // for the port driver.
2282 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2285 // Set up IRP Address.
2288 Srb
->OriginalRequest
= irp
;
2291 // Call the port driver with the request and wait for it to complete.
2294 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2296 if (status
== STATUS_PENDING
) {
2297 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2301 // Check that request completed without error.
2304 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2307 // Release the queue if it is frozen.
2310 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2311 ScsiClassReleaseQueue(DeviceObject
);
2315 // Update status and determine if request should be retried.
2318 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2322 MAXIMUM_RETRIES
- retryCount
,
2327 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2328 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2329 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2331 LARGE_INTEGER delay
;
2334 // Delay for 2 seconds.
2337 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2340 // Stall for a while to let the controller spinup.
2343 KeDelayExecutionThread(KernelMode
,
2350 // If retries are not exhausted then retry this operation.
2360 status
= STATUS_SUCCESS
;
2363 ExFreePool(senseInfoBuffer
);
2366 } // end ScsiClassSendSrbSynchronous()
2371 ScsiClassInterpretSenseInfo(
2372 IN PDEVICE_OBJECT DeviceObject
,
2373 IN PSCSI_REQUEST_BLOCK Srb
,
2374 IN UCHAR MajorFunctionCode
,
2375 IN ULONG IoDeviceCode
,
2376 IN ULONG RetryCount
,
2377 OUT NTSTATUS
*Status
2382 Routine Description:
2384 This routine interprets the data returned from the SCSI
2385 request sense. It determines the status to return in the
2386 IRP and whether this request can be retried.
2390 DeviceObject - Supplies the device object associated with this request.
2392 Srb - Supplies the scsi request block which failed.
2394 MajorFunctionCode - Supplies the function code to be used for logging.
2396 IoDeviceCode - Supplies the device code to be used for logging.
2398 Status - Returns the status for the request.
2402 BOOLEAN TRUE: Drivers should retry this request.
2403 FALSE: Drivers should not retry this request.
2408 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2409 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2410 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2411 BOOLEAN retry
= TRUE
;
2412 BOOLEAN logError
= FALSE
;
2413 ULONG badSector
= 0;
2418 PIO_ERROR_LOG_PACKET errorLogEntry
;
2425 // Check that request sense buffer is valid.
2429 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2430 for (i
= 1; i
< 12; i
++) {
2431 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2433 DebugPrint((3,"\n"));
2436 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2437 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2439 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2440 senseBuffer
->ErrorCode
));
2441 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2442 senseBuffer
->SenseKey
));
2443 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2444 senseBuffer
->AdditionalSenseCode
));
2445 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2446 senseBuffer
->AdditionalSenseCodeQualifier
));
2449 // Zero the additional sense code and additional sense code qualifier
2450 // if they were not returned by the device.
2453 readSector
= senseBuffer
->AdditionalSenseLength
+
2454 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2456 if (readSector
> Srb
->SenseInfoBufferLength
) {
2457 readSector
= Srb
->SenseInfoBufferLength
;
2460 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2461 senseBuffer
->AdditionalSenseCode
= 0;
2464 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2465 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2468 switch (senseBuffer
->SenseKey
& 0xf) {
2470 case SCSI_SENSE_NOT_READY
:
2472 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2473 *Status
= STATUS_DEVICE_NOT_READY
;
2475 switch (senseBuffer
->AdditionalSenseCode
) {
2477 case SCSI_ADSENSE_LUN_NOT_READY
:
2479 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2481 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2483 case SCSI_SENSEQ_BECOMING_READY
:
2485 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2486 " In process of becoming ready\n"));
2489 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2491 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2492 " Manual intervention required\n"));
2493 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2497 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2499 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2503 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2507 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2508 " Initializing command required\n"));
2511 // This sense code/additional sense code
2512 // combination may indicate that the device
2513 // needs to be started. Send an start unit if this
2514 // is a disk device.
2517 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2518 StartUnit(DeviceObject
);
2523 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2527 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2530 "ScsiClassInterpretSenseInfo:"
2531 " No Media in device.\n"));
2532 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2536 // signal autorun that there isn't any media in the device
2539 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2540 (!deviceExtension
->MediaChangeNoMedia
)) {
2541 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2544 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2545 "Detected No Media In Device "
2546 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2547 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2551 } // end switch (senseBuffer->AdditionalSenseCode)
2555 case SCSI_SENSE_DATA_PROTECT
:
2557 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2558 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2562 case SCSI_SENSE_MEDIUM_ERROR
:
2564 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2565 *Status
= STATUS_DEVICE_DATA_ERROR
;
2570 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2573 case SCSI_SENSE_HARDWARE_ERROR
:
2575 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2576 *Status
= STATUS_IO_DEVICE_ERROR
;
2580 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2584 case SCSI_SENSE_ILLEGAL_REQUEST
:
2586 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2587 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2589 switch (senseBuffer
->AdditionalSenseCode
) {
2591 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2592 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2596 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2597 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2598 *Status
= STATUS_NONEXISTENT_SECTOR
;
2602 case SCSI_ADSENSE_INVALID_LUN
:
2603 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2604 *Status
= STATUS_NO_SUCH_DEVICE
;
2608 case SCSI_ADSENSE_MUSIC_AREA
:
2609 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2613 case SCSI_ADSENSE_DATA_AREA
:
2614 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2618 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2619 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2623 case SCSI_ADSENSE_INVALID_CDB
:
2624 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2627 // Check if write cache enabled.
2630 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2633 // Assume FUA is not supported.
2636 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2645 } // end switch (senseBuffer->AdditionalSenseCode)
2649 case SCSI_SENSE_UNIT_ATTENTION
:
2651 switch (senseBuffer
->AdditionalSenseCode
) {
2652 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2653 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2655 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2657 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2660 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2661 "New Media Found - Setting MediaChanged event"
2662 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2663 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2668 case SCSI_ADSENSE_BUS_RESET
:
2669 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2673 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2676 } // end switch (senseBuffer->AdditionalSenseCode)
2678 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2679 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2682 // Set bit to indicate that media may have changed
2683 // and volume needs verification.
2686 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2688 *Status
= STATUS_VERIFY_REQUIRED
;
2693 *Status
= STATUS_IO_DEVICE_ERROR
;
2698 // A media change may have occured so increment the change
2699 // count for the physical device
2702 physicalExtension
->MediaChangeCount
++;
2704 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2705 "count for device %d is %d\n",
2706 physicalExtension
->DeviceNumber
,
2707 physicalExtension
->MediaChangeCount
));
2711 case SCSI_SENSE_ABORTED_COMMAND
:
2713 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2714 *Status
= STATUS_IO_DEVICE_ERROR
;
2717 case SCSI_SENSE_RECOVERED_ERROR
:
2719 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2720 *Status
= STATUS_SUCCESS
;
2725 switch(senseBuffer
->AdditionalSenseCode
) {
2726 case SCSI_ADSENSE_SEEK_ERROR
:
2727 case SCSI_ADSENSE_TRACK_ERROR
:
2728 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2731 case SCSI_ADSENSE_REC_DATA_NOECC
:
2732 case SCSI_ADSENSE_REC_DATA_ECC
:
2733 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2737 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2740 } // end switch(senseBuffer->AdditionalSenseCode)
2742 if (senseBuffer
->IncorrectLength
) {
2744 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2745 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2750 case SCSI_SENSE_NO_SENSE
:
2753 // Check other indicators.
2756 if (senseBuffer
->IncorrectLength
) {
2758 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2759 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2764 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2765 *Status
= STATUS_IO_DEVICE_ERROR
;
2773 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2774 *Status
= STATUS_IO_DEVICE_ERROR
;
2777 } // end switch (senseBuffer->SenseKey & 0xf)
2780 // Try to determine the bad sector from the inquiry data.
2783 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2784 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2785 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2787 for (index
= 0; index
< 4; index
++) {
2788 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2792 for (index
= 0; index
< 4; index
++) {
2793 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2796 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2797 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2800 // Make sure the bad sector is within the read sectors.
2803 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2804 badSector
= readSector
;
2811 // Request sense buffer not valid. No sense information
2812 // to pinpoint the error. Return general request fail.
2815 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2816 SRB_STATUS(Srb
->SrbStatus
)));
2819 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2820 case SRB_STATUS_INVALID_LUN
:
2821 case SRB_STATUS_INVALID_TARGET_ID
:
2822 case SRB_STATUS_NO_DEVICE
:
2823 case SRB_STATUS_NO_HBA
:
2824 case SRB_STATUS_INVALID_PATH_ID
:
2825 *Status
= STATUS_NO_SUCH_DEVICE
;
2829 case SRB_STATUS_COMMAND_TIMEOUT
:
2830 case SRB_STATUS_ABORTED
:
2831 case SRB_STATUS_TIMEOUT
:
2834 // Update the error count for the device.
2837 deviceExtension
->ErrorCount
++;
2838 *Status
= STATUS_IO_TIMEOUT
;
2841 case SRB_STATUS_SELECTION_TIMEOUT
:
2843 logStatus
= 0;//IO_ERR_NOT_READY;
2845 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2849 case SRB_STATUS_DATA_OVERRUN
:
2850 *Status
= STATUS_DATA_OVERRUN
;
2854 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2857 // Update the error count for the device.
2860 deviceExtension
->ErrorCount
++;
2861 *Status
= STATUS_IO_DEVICE_ERROR
;
2864 // If there was phase sequence error then limit the number of
2868 if (RetryCount
> 1 ) {
2874 case SRB_STATUS_REQUEST_FLUSHED
:
2877 // If the status needs verification bit is set. Then set
2878 // the status to need verification and no retry; otherwise,
2879 // just retry the request.
2882 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2884 *Status
= STATUS_VERIFY_REQUIRED
;
2887 *Status
= STATUS_IO_DEVICE_ERROR
;
2892 case SRB_STATUS_INVALID_REQUEST
:
2895 // An invalid request was attempted.
2898 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2902 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2903 case SRB_STATUS_PARITY_ERROR
:
2906 // Update the error count for the device.
2909 deviceExtension
->ErrorCount
++;
2912 // Fall through to below.
2915 case SRB_STATUS_BUS_RESET
:
2916 *Status
= STATUS_IO_DEVICE_ERROR
;
2919 case SRB_STATUS_ERROR
:
2921 *Status
= STATUS_IO_DEVICE_ERROR
;
2922 if (Srb
->ScsiStatus
== 0) {
2925 // This is some strange return code. Update the error
2926 // count for the device.
2929 deviceExtension
->ErrorCount
++;
2931 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2933 *Status
= STATUS_DEVICE_NOT_READY
;
2935 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2937 *Status
= STATUS_DEVICE_BUSY
;
2946 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2948 *Status
= STATUS_IO_DEVICE_ERROR
;
2954 // If the error count has exceeded the error limit, then disable
2955 // any tagged queuing, multiple requests per lu queueing
2956 // and sychronous data transfers.
2959 if (deviceExtension
->ErrorCount
== 4) {
2962 // Clearing the no queue freeze flag prevents the port driver
2963 // from sending multiple requests per logical unit.
2966 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2967 SRB_FLAGS_NO_QUEUE_FREEZE
);
2969 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2970 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2972 } else if (deviceExtension
->ErrorCount
== 8) {
2975 // If a second threshold is reached, disable disconnects.
2978 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
2979 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2984 // If there is a class specific error handler call it.
2987 if (deviceExtension
->ClassError
!= NULL
) {
2989 deviceExtension
->ClassError(DeviceObject
,
2996 // Log an error if necessary.
3001 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3003 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
3005 if (errorLogEntry
== NULL
) {
3008 // Return if no packet could be allocated.
3015 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
3016 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3018 errorLogEntry
->FinalStatus
= *Status
;
3022 // Calculate the device offset if there is a geometry.
3025 if (deviceExtension
->DiskGeometry
!= NULL
) {
3027 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
3028 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
3029 errorLogEntry
->DeviceOffset
,
3030 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
3033 errorLogEntry
->ErrorCode
= logStatus
;
3034 errorLogEntry
->SequenceNumber
= 0;
3035 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
3036 errorLogEntry
->IoControlCode
= IoDeviceCode
;
3037 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
3038 errorLogEntry
->UniqueErrorValue
= uniqueId
;
3039 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
3040 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
3041 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
3042 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
3043 errorLogEntry
->DumpData
[3] = 0;
3044 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
3046 if (senseBuffer
!= NULL
) {
3047 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
3048 senseBuffer
->AdditionalSenseCode
<< 8 |
3049 senseBuffer
->AdditionalSenseCodeQualifier
;
3054 // Write the error log packet.
3057 IoWriteErrorLogEntry(errorLogEntry
);
3062 } // end ScsiClassInterpretSenseInfo()
3068 PDEVICE_OBJECT DeviceObject
,
3070 PSCSI_REQUEST_BLOCK Srb
,
3076 Routine Description:
3078 This routine reinitalizes the necessary fields, and sends the request
3083 DeviceObject - Supplies the device object associated with this request.
3085 Irp - Supplies the request to be retried.
3087 Srb - Supplies a Pointer to the SCSI request block to be retied.
3089 Assocaiated - Indicates this is an assocatied Irp created by split request.
3098 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3099 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3100 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3101 ULONG transferByteCount
;
3104 // Determine the transfer count of the request. If this is a read or a
3105 // write then the transfer count is in the Irp stack. Otherwise assume
3106 // the MDL contains the correct length. If there is no MDL then the
3107 // transfer length must be zero.
3110 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
3111 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
3113 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3115 } else if (Irp
->MdlAddress
!= NULL
) {
3118 // Note this assumes that only read and write requests are spilt and
3119 // other request do not need to be. If the data buffer address in
3120 // the MDL and the SRB don't match then transfer length is most
3121 // likely incorrect.
3124 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3125 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
3129 transferByteCount
= 0;
3133 // Reset byte count of transfer in SRB Extension.
3136 Srb
->DataTransferLength
= transferByteCount
;
3139 // Zero SRB statuses.
3142 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
3145 // Set the no disconnect flag, disable synchronous data transfers and
3146 // disable tagged queuing. This fixes some errors.
3149 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
3150 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3152 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
3153 Srb
->QueueTag
= SP_UNTAGGED
;
3156 // Set up major SCSI function.
3159 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3162 // Save SRB address in next stack for port driver.
3165 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
3168 // Set up IoCompletion routine address.
3173 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
3177 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3181 // Pass the request to the port driver.
3184 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3186 } // end RetryRequest()
3190 ScsiClassBuildRequest(
3191 PDEVICE_OBJECT DeviceObject
,
3197 Routine Description:
3199 This routine allocates and builds an Srb for a read or write request.
3200 The block address and length are supplied by the Irp. The retry count
3201 is stored in the current stack for use by ScsiClassIoComplete which
3202 processes these requests when they complete. The Irp is ready to be
3203 passed to the port driver when this routine returns.
3207 DeviceObject - Supplies the device object associated with this request.
3209 Irp - Supplies the request to be retried.
3213 If the IRP is for a disk transfer, the byteoffset field
3214 will already have been adjusted to make it relative to
3215 the beginning of the disk.
3225 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3226 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3227 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3228 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3229 PSCSI_REQUEST_BLOCK srb
;
3231 ULONG logicalBlockAddress
;
3232 USHORT transferBlocks
;
3235 // Calculate relative sector address.
3238 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
3244 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
3249 // Write length to SRB.
3252 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3255 // Set up IRP Address.
3258 srb
->OriginalRequest
= Irp
;
3261 // Set up target ID and logical unit number.
3264 srb
->PathId
= deviceExtension
->PathId
;
3265 srb
->TargetId
= deviceExtension
->TargetId
;
3266 srb
->Lun
= deviceExtension
->Lun
;
3267 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3268 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3271 // Save byte count of transfer in SRB Extension.
3274 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3277 // Initialize the queue actions field.
3280 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3283 // Queue sort key is Relative Block Address.
3286 srb
->QueueSortKey
= logicalBlockAddress
;
3289 // Indicate auto request sense by specifying buffer and size.
3292 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3293 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3296 // Set timeout value of one unit per 64k bytes of data.
3299 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3300 deviceExtension
->TimeOutValue
;
3306 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3310 // Indicate that 10-byte CDB's will be used.
3313 srb
->CdbLength
= 10;
3316 // Fill in CDB fields.
3319 cdb
= (PCDB
)srb
->Cdb
;
3322 // Zero 12 bytes for Atapi Packets
3325 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3327 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3328 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3331 // Move little endian values into CDB in big endian format.
3334 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3335 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3336 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3337 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3339 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3340 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3343 // Set transfer direction flag and Cdb command.
3346 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3348 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3350 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3351 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3355 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3357 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3358 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3362 // If this is not a write-through request, then allow caching.
3365 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3367 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3372 // If write caching is enable then force media access in the
3376 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3377 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3382 // Or in the default flags from the device object.
3385 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3388 // Set up major SCSI function.
3391 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3394 // Save SRB address in next stack for port driver.
3397 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3400 // Save retry count in current IRP stack.
3403 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3406 // Set up IoCompletion routine address.
3409 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3413 } // end ScsiClassBuildRequest()
3418 IN PDEVICE_OBJECT DeviceObject
,
3419 IN PCHAR ModeSenseBuffer
,
3426 Routine Description:
3428 This routine sends a mode sense command to a target ID and returns
3429 when it is complete.
3433 DeviceObject - Supplies the device object associated with this request.
3435 ModeSenseBuffer - Supplies a buffer to store the sense data.
3437 Length - Supplies the length in bytes of the mode sense buffer.
3439 PageMode - Supplies the page or pages of mode sense data to be retrived.
3443 Length of the transferred data is returned.
3447 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3449 SCSI_REQUEST_BLOCK srb
;
3453 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3456 // Build the MODE SENSE CDB.
3460 cdb
= (PCDB
)srb
.Cdb
;
3463 // Set timeout value from device extension.
3466 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3468 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3469 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3470 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3474 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3481 if (status
== STATUS_VERIFY_REQUIRED
) {
3484 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3485 // this status. MODE SENSE commands should be retried anyway.
3497 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3498 status
= STATUS_SUCCESS
;
3501 if (NT_SUCCESS(status
)) {
3502 return(srb
.DataTransferLength
);
3507 } // end ScsiClassModeSense()
3512 ScsiClassFindModePage(
3513 IN PCHAR ModeSenseBuffer
,
3521 Routine Description:
3523 This routine scans through the mode sense data and finds the requested
3524 mode sense page code.
3527 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3529 Length - Indicates the length of valid data.
3531 PageMode - Supplies the page mode to be searched for.
3533 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3537 A pointer to the the requested mode page. If the mode page was not found
3538 then NULL is return.
3543 ULONG parameterHeaderLength
;
3545 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3546 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3550 // Skip the mode select header and block descriptors.
3553 if (Length
< parameterHeaderLength
) {
3559 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3560 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3563 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3564 // requested page until the limit is reached.
3568 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3570 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3571 return(ModeSenseBuffer
);
3575 // Advance to the next page.
3578 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3586 ScsiClassSendSrbAsynchronous(
3587 PDEVICE_OBJECT DeviceObject
,
3588 PSCSI_REQUEST_BLOCK Srb
,
3590 PVOID BufferAddress
,
3592 BOOLEAN WriteToDevice
3596 Routine Description:
3598 This routine takes a partially built Srb and an Irp and sends it down to
3602 DeviceObject - Supplies the device object for the orginal request.
3604 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3605 CDB and the SRB timeout value must be filled in. The SRB must not be
3606 allocated from zone.
3608 Irp - Supplies the requesting Irp.
3610 BufferAddress - Supplies a pointer to the buffer to be transfered.
3612 BufferLength - Supplies the length of data transfer.
3614 WriteToDevice - Indicates the data transfer will be from system memory to
3619 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3624 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3625 PIO_STACK_LOCATION irpStack
;
3630 // Write length to SRB.
3633 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3636 // Set SCSI bus address.
3639 Srb
->PathId
= deviceExtension
->PathId
;
3640 Srb
->TargetId
= deviceExtension
->TargetId
;
3641 Srb
->Lun
= deviceExtension
->Lun
;
3643 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3646 // This is a violation of the SCSI spec but it is required for
3650 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3653 // Indicate auto request sense by specifying buffer and size.
3656 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3657 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3658 Srb
->DataBuffer
= BufferAddress
;
3660 if (BufferAddress
!= NULL
) {
3663 // Build Mdl if necessary.
3666 if (Irp
->MdlAddress
== NULL
) {
3668 if (IoAllocateMdl(BufferAddress
,
3674 return(STATUS_INSUFFICIENT_RESOURCES
);
3677 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3682 // Make sure the buffer requested matches the MDL.
3685 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3692 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3700 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3704 // Disable synchronous transfer for these requests.
3707 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3710 // Set the transfer length.
3713 Srb
->DataTransferLength
= BufferLength
;
3719 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3724 // Save a few parameters in the current stack location.
3727 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3730 // Save retry count in current Irp stack.
3733 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3736 // Set up IoCompletion routine address.
3739 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3742 // Get next stack location and
3743 // set major function code.
3746 irpStack
= IoGetNextIrpStackLocation(Irp
);
3748 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3751 // Save SRB address in next stack for port driver.
3754 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3757 // Set up Irp Address.
3760 Srb
->OriginalRequest
= Irp
;
3763 // Call the port driver to process the request.
3766 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3773 ScsiClassDeviceControlDispatch(
3774 PDEVICE_OBJECT DeviceObject
,
3780 Routine Description:
3782 The routine is the common class driver device control dispatch entry point.
3783 This routine is invokes the device-specific drivers DeviceControl routine,
3784 (which may call the Class driver's common DeviceControl routine).
3788 DeviceObject - Supplies a pointer to the device object for this request.
3790 Irp - Supplies the Irp making the request.
3794 Returns the status returned from the device-specific driver.
3800 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3804 // Call the class specific driver DeviceControl routine.
3805 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3808 ASSERT(deviceExtension
->ClassDeviceControl
);
3810 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3816 ScsiClassDeviceControl(
3817 PDEVICE_OBJECT DeviceObject
,
3822 Routine Description:
3824 The routine is the common class driver device control dispatch function.
3825 This routine is called by a class driver when it get an unrecognized
3826 device control request. This routine will perform the correct action for
3827 common requests such as lock media. If the device request is unknown it
3828 passed down to the next level.
3832 DeviceObject - Supplies a pointer to the device object for this request.
3834 Irp - Supplies the Irp making the request.
3838 Returns back a STATUS_PENDING or a completion status.
3843 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3844 PIO_STACK_LOCATION nextStack
;
3845 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3846 PSCSI_REQUEST_BLOCK srb
;
3849 ULONG modifiedIoControlCode
;
3851 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3852 IOCTL_STORAGE_RESET_DEVICE
) {
3854 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3855 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3856 status
= STATUS_UNSUCCESSFUL
;
3857 goto SetStatusAndReturn
;
3861 // If this is a pass through I/O control, set the minor function code
3862 // and device address and pass it to the port driver.
3865 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3866 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3868 PSCSI_PASS_THROUGH scsiPass
;
3870 nextStack
= IoGetNextIrpStackLocation(Irp
);
3873 // Validiate the user buffer.
3876 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3878 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3879 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3880 status
= STATUS_INVALID_PARAMETER
;
3881 goto SetStatusAndReturn
;
3885 // Force the SCSI address to the correct value.
3888 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3889 scsiPass
->PathId
= deviceExtension
->PathId
;
3890 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3891 scsiPass
->Lun
= deviceExtension
->Lun
;
3894 // NOTICE: The SCSI-II specificaiton indicates that this field
3895 // should be zero; however, some target controllers ignore the logical
3896 // unit number in the INDENTIFY message and only look at the logical
3897 // unit number field in the CDB.
3900 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3902 nextStack
->Parameters
= irpStack
->Parameters
;
3903 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3904 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3906 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3907 goto SetStatusAndReturn
;
3910 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3912 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3914 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3915 sizeof(SCSI_ADDRESS
)) {
3918 // Indicate unsuccessful status and no data transferred.
3921 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3922 Irp
->IoStatus
.Information
= 0;
3923 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3924 status
= STATUS_BUFFER_TOO_SMALL
;
3925 goto SetStatusAndReturn
;
3929 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3930 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3931 scsiAddress
->PathId
= deviceExtension
->PathId
;
3932 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3933 scsiAddress
->Lun
= deviceExtension
->Lun
;
3934 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3935 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3936 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3937 status
= STATUS_SUCCESS
;
3938 goto SetStatusAndReturn
;
3941 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3945 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3946 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3947 status
= STATUS_INSUFFICIENT_RESOURCES
;
3948 goto SetStatusAndReturn
;
3952 // Write zeros to Srb.
3955 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3957 cdb
= (PCDB
)srb
->Cdb
;
3960 // Change the device type to disk for the switch statement.
3963 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3964 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3966 switch (modifiedIoControlCode
) {
3968 case IOCTL_DISK_CHECK_VERIFY
: {
3971 PIO_STACK_LOCATION newStack
;
3973 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3976 // If a buffer for a media change count was provided, make sure it's
3977 // big enough to hold the result
3980 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
3983 // If the buffer is too small to hold the media change count
3984 // then return an error to the caller
3987 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3990 DebugPrint((3,"ScsiDeviceIoControl: media count "
3991 "buffer too small\n"));
3993 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3994 Irp
->IoStatus
.Information
= 0;
3996 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3997 status
= STATUS_BUFFER_TOO_SMALL
;
3998 goto SetStatusAndReturn
;
4003 // The caller has provided a valid buffer. Allocate an additional
4004 // irp and stick the CheckVerify completion routine on it. We will
4005 // then send this down to the port driver instead of the irp the
4009 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
4013 // Allocate a new irp to send the TestUnitReady to the port driver
4016 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
4019 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4020 Irp
->IoStatus
.Information
= 0;
4022 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4023 status
= STATUS_INSUFFICIENT_RESOURCES
;
4024 goto SetStatusAndReturn
;
4029 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
4030 IoSetNextIrpStackLocation(irp2
);
4033 // Set the top stack location and shove the master Irp into the
4037 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4038 newStack
->Parameters
.Others
.Argument1
= Irp
;
4039 newStack
->DeviceObject
= DeviceObject
;
4042 // Stick the check verify completion routine onto the stack
4043 // and prepare the irp for the port driver
4046 IoSetCompletionRoutine(irp2
,
4047 ScsiClassCheckVerifyComplete
,
4053 IoSetNextIrpStackLocation(irp2
);
4054 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4055 newStack
->DeviceObject
= DeviceObject
;
4058 // Mark the master irp as pending - whether the lower level
4059 // driver completes it immediately or not this should allow it
4060 // to go all the way back up.
4063 IoMarkIrpPending(Irp
);
4074 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
4077 // Set timeout value.
4080 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4083 // Since this routine will always hand the request to the
4084 // port driver if there isn't a data transfer to be done
4085 // we don't have to worry about completing the request here
4089 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4099 case IOCTL_DISK_MEDIA_REMOVAL
: {
4101 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
4104 // Prevent/Allow media removal.
4107 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4109 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4110 sizeof(PREVENT_MEDIA_REMOVAL
)) {
4113 // Indicate unsuccessful status and no data transferred.
4116 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4117 Irp
->IoStatus
.Information
= 0;
4119 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4120 status
= STATUS_BUFFER_TOO_SMALL
;
4121 goto SetStatusAndReturn
;
4125 // Get physical device extension. This is where the
4126 // lock count is stored.
4129 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
4132 // If command succeeded then increment or decrement lock counter.
4135 if (MediaRemoval
->PreventMediaRemoval
) {
4138 // This is a lock command. Reissue the command in case bus or device
4139 // was reset and lock cleared.
4142 InterlockedIncrement(&deviceExtension
->LockCount
);
4145 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4146 deviceExtension
->LockCount
,
4147 deviceExtension
->DeviceNumber
));
4152 // This is an unlock command.
4155 if (!deviceExtension
->LockCount
||
4156 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
4159 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4160 deviceExtension
->LockCount
,
4161 deviceExtension
->DeviceNumber
));
4164 // Don't unlock because someone still wants it locked.
4167 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4169 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4170 status
= STATUS_SUCCESS
;
4171 goto SetStatusAndReturn
;
4175 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4176 deviceExtension
->LockCount
,
4177 deviceExtension
->DeviceNumber
));
4182 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
4185 // TRUE - prevent media removal.
4186 // FALSE - allow media removal.
4189 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
4192 // Set timeout value.
4195 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4196 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4204 // Some devices will not support lock/unlock.
4205 // Pretend that it worked.
4211 case IOCTL_DISK_RESERVE
: {
4214 // Reserve logical unit.
4219 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
4222 // Set timeout value.
4225 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4227 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4237 case IOCTL_DISK_RELEASE
: {
4240 // Release logical unit.
4245 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
4248 // Set timeout value.
4251 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4253 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4263 case IOCTL_DISK_EJECT_MEDIA
: {
4271 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4272 cdb
->START_STOP
.LoadEject
= 1;
4273 cdb
->START_STOP
.Start
= 0;
4276 // Set timeout value.
4279 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4280 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4289 case IOCTL_DISK_LOAD_MEDIA
: {
4295 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4299 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4300 cdb
->START_STOP
.LoadEject
= 1;
4301 cdb
->START_STOP
.Start
= 1;
4304 // Set timeout value.
4307 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4308 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4318 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4321 // Search for devices that have been powered on since the last
4322 // device search or system initialization.
4325 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4326 status
= DriverEntry(DeviceObject
->DriverObject
,
4329 Irp
->IoStatus
.Status
= status
;
4331 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4338 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4341 // Pass the device control to the next driver.
4347 // Copy the Irp stack parameters to the next stack location.
4350 nextStack
= IoGetNextIrpStackLocation(Irp
);
4351 nextStack
->Parameters
= irpStack
->Parameters
;
4352 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4353 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4355 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4359 } // end switch( ...
4369 ScsiClassShutdownFlush(
4370 IN PDEVICE_OBJECT DeviceObject
,
4376 Routine Description:
4378 This routine is called for a shutdown and flush IRPs. These are sent by the
4379 system before it actually shuts down or when the file system does a flush.
4380 If it exists, the device-specific driver's routine will be invoked. If there
4381 wasn't one specified, the Irp will be completed with an Invalid device request.
4385 DriverObject - Pointer to device object to being shutdown by system.
4396 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4398 if (deviceExtension
->ClassShutdownFlush
) {
4401 // Call the device-specific driver's routine.
4404 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4408 // Device-specific driver doesn't support this.
4411 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4412 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4414 return STATUS_INVALID_DEVICE_REQUEST
;
4420 ScsiClassFindUnclaimedDevices(
4421 IN PCLASS_INIT_DATA InitializationData
,
4422 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4426 ULONG scsiBus
,deviceCount
= 0;
4427 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4428 PSCSI_INQUIRY_DATA lunInfo
;
4429 PINQUIRYDATA inquiryData
;
4431 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4434 // Get the SCSI bus scan data for this bus.
4437 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4440 // Search list for unclaimed disk devices.
4443 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4445 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4447 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4449 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4454 if (lunInfo
->NextInquiryDataOffset
== 0) {
4458 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4468 ScsiClassCreateDeviceObject(
4469 IN PDRIVER_OBJECT DriverObject
,
4470 IN PCCHAR ObjectNameBuffer
,
4471 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4472 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4473 IN PCLASS_INIT_DATA InitializationData
4478 Routine Description:
4480 This routine creates an object for the physical device specified and
4481 sets up the deviceExtension's function pointers for each entry point
4482 in the device-specific driver.
4486 DriverObject - Pointer to driver object created by system.
4488 ObjectNameBuffer - Dir. name of the object to create.
4490 PhysicalDeviceObject - Pointer to the physical (class) device object for
4491 this logical unit or NULL if this is it.
4493 DeviceObject - Pointer to the device object pointer we will return.
4495 InitializationData - Pointer to the init data created by the device-specific driver.
4504 STRING ntNameString
;
4505 UNICODE_STRING ntUnicodeString
;
4507 PDEVICE_OBJECT deviceObject
= NULL
;
4509 *DeviceObject
= NULL
;
4512 "ScsiClassCreateDeviceObject: Create device object %s\n",
4515 RtlInitString(&ntNameString
,
4518 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4522 if (!NT_SUCCESS(status
)) {
4525 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4528 ntUnicodeString
.Buffer
= NULL
;
4532 status
= IoCreateDevice(DriverObject
,
4533 InitializationData
->DeviceExtensionSize
,
4535 InitializationData
->DeviceType
,
4536 InitializationData
->DeviceCharacteristics
,
4541 if (!NT_SUCCESS(status
)) {
4544 "CreateDiskDeviceObjects: Can not create device object %s\n",
4549 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4552 // Fill in entry points
4555 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4556 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4557 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4558 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4559 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4560 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4561 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4563 deviceExtension
->MediaChangeCount
= 0;
4566 // If a pointer to the physical device object was passed in then use
4567 // that. If the value was NULL, then this is the physical device so
4568 // use the pointer to the device we just created.
4571 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4572 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4574 deviceExtension
->PhysicalDevice
= deviceObject
;
4578 *DeviceObject
= deviceObject
;
4580 RtlFreeUnicodeString(&ntUnicodeString
);
4583 // Indicate the ntUnicodeString is free.
4586 ntUnicodeString
.Buffer
= NULL
;
4594 ScsiClassClaimDevice(
4595 IN PDEVICE_OBJECT PortDeviceObject
,
4596 IN PSCSI_INQUIRY_DATA LunInfo
,
4598 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4602 Routine Description:
4604 This function claims a device in the port driver. The port driver object
4605 is updated with the correct driver object if the device is successfully
4610 PortDeviceObject - Supplies the base port device object.
4612 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4614 Release - Indicates the logical unit should be released rather than claimed.
4616 NewPortDeviceObject - Returns the updated port device object to be used
4617 for all future accesses.
4621 Returns a status indicating success or failure of the operation.
4626 IO_STATUS_BLOCK ioStatus
;
4628 PIO_STACK_LOCATION irpStack
;
4631 SCSI_REQUEST_BLOCK srb
;
4635 if (NewPortDeviceObject
!= NULL
) {
4636 *NewPortDeviceObject
= NULL
;
4640 // Clear the SRB fields.
4643 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4646 // Write length to SRB.
4649 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4652 // Set SCSI bus address.
4655 srb
.PathId
= LunInfo
->PathId
;
4656 srb
.TargetId
= LunInfo
->TargetId
;
4657 srb
.Lun
= LunInfo
->Lun
;
4659 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4660 SRB_FUNCTION_CLAIM_DEVICE
;
4663 // Set the event object to the unsignaled state.
4664 // It will be used to signal request completion.
4667 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4670 // Build synchronous request with no transfer.
4673 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4685 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4686 return STATUS_INSUFFICIENT_RESOURCES
;
4689 irpStack
= IoGetNextIrpStackLocation(irp
);
4692 // Save SRB address in next stack for port driver.
4695 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4698 // Set up IRP Address.
4701 srb
.OriginalRequest
= irp
;
4704 // Call the port driver with the request and wait for it to complete.
4707 status
= IoCallDriver(PortDeviceObject
, irp
);
4708 if (status
== STATUS_PENDING
) {
4710 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4711 status
= ioStatus
.Status
;
4715 // If this is a release request, then just decrement the reference count
4716 // and return. The status does not matter.
4721 ObDereferenceObject(PortDeviceObject
);
4722 return STATUS_SUCCESS
;
4725 if (!NT_SUCCESS(status
)) {
4729 ASSERT(srb
.DataBuffer
!= NULL
);
4732 // Reference the new port driver object so that it will not go away while
4733 // it is being used.
4736 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4741 if (!NT_SUCCESS(status
)) {
4747 // Return the new port device object pointer.
4750 if (NewPortDeviceObject
!= NULL
) {
4751 *NewPortDeviceObject
= srb
.DataBuffer
;
4760 ScsiClassInternalIoControl (
4761 IN PDEVICE_OBJECT DeviceObject
,
4767 Routine Description:
4769 This routine passes internal device controls to the port driver.
4770 Internal device controls are used by higher level class drivers to
4771 send scsi requests to a device that are not normally sent by a generic
4774 The path ID, target ID and logical unit ID are set in the srb so the
4775 higher level driver does not have to figure out what values are actually
4780 DeviceObject - Supplies a pointer to the device object for this request.
4782 Irp - Supplies the Irp making the request.
4786 Returns back a STATUS_PENDING or a completion status.
4790 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4791 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4792 PSCSI_REQUEST_BLOCK srb
;
4795 // Get a pointer to the SRB.
4798 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4801 // Set SCSI bus address.
4804 srb
->PathId
= deviceExtension
->PathId
;
4805 srb
->TargetId
= deviceExtension
->TargetId
;
4806 srb
->Lun
= deviceExtension
->Lun
;
4809 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4810 // zero; however, some target controllers ignore the logical unit number
4811 // in the INDENTIFY message and only look at the logical unit number field
4815 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4818 // Set the parameters in the next stack location.
4821 irpStack
= IoGetNextIrpStackLocation(Irp
);
4823 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4824 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4825 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4827 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4828 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4834 IN PDEVICE_OBJECT DeviceObject
,
4841 Routine Description:
4843 This routine is called when an internal device control I/O request
4844 has completed. It marks the IRP pending if necessary and returns the
4845 status of the request.
4849 DeviceObject - Target device object.
4851 Irp - Completed request.
4857 Returns the status of the completed request.
4862 UNREFERENCED_PARAMETER(Context
);
4863 UNREFERENCED_PARAMETER(DeviceObject
);
4866 // If pending is returned for this Irp then mark current stack
4870 if (Irp
->PendingReturned
) {
4872 IoMarkIrpPending( Irp
);
4875 return Irp
->IoStatus
.Status
;
4881 ScsiClassInitializeSrbLookasideList(
4882 IN PDEVICE_EXTENSION DeviceExtension
,
4883 IN ULONG NumberElements
4888 Routine Description:
4890 This routine sets up a lookaside listhead for srbs.
4894 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4896 NumberElements - Supplies the maximum depth of the lookaside list.
4906 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4909 NonPagedPoolMustSucceed
,
4910 SCSI_REQUEST_BLOCK_SIZE
,
4912 (USHORT
)NumberElements
);
4919 ScsiClassQueryTimeOutRegistryValue(
4920 IN PUNICODE_STRING RegistryPath
4925 Routine Description:
4927 This routine determines whether a reg key for a user-specified timeout value exists.
4931 RegistryPath - Pointer to the hardware reg. entry describing the key.
4935 New default timeout for a class of devices.
4941 // Find the appropriate reg. key
4944 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4951 if (!RegistryPath
) {
4955 parameters
= ExAllocatePool(NonPagedPool
,
4956 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4962 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4963 path
= ExAllocatePool(NonPagedPool
, size
);
4966 ExFreePool(parameters
);
4970 RtlZeroMemory(path
,size
);
4971 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
4975 // Check for the Timeout value.
4978 RtlZeroMemory(parameters
,
4979 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
4981 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
4982 parameters
[0].Name
= L
"TimeOutValue";
4983 parameters
[0].EntryContext
= &timeOut
;
4984 parameters
[0].DefaultType
= REG_DWORD
;
4985 parameters
[0].DefaultData
= &zero
;
4986 parameters
[0].DefaultLength
= sizeof(ULONG
);
4988 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
4994 if (!(NT_SUCCESS(status
))) {
4998 ExFreePool(parameters
);
5002 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
5012 ScsiClassCheckVerifyComplete(
5013 IN PDEVICE_OBJECT DeviceObject
,
5020 Routine Description:
5022 This routine executes when the port driver has completed a check verify
5023 ioctl. It will set the status of the master Irp, copy the media change
5024 count and complete the request.
5028 DeviceObject - Supplies the device object which represents the logical
5031 Irp - Supplies the Irp which has completed.
5042 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5043 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5044 PDEVICE_EXTENSION physicalExtension
=
5045 deviceExtension
->PhysicalDevice
->DeviceExtension
;
5048 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
5051 // Copy the media change count and status
5054 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
5055 physicalExtension
->MediaChangeCount
;
5057 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
5058 "device %d is %d\n",
5059 physicalExtension
->DeviceNumber
,
5060 physicalExtension
->MediaChangeCount
));
5062 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
5063 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
5065 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
5069 return STATUS_MORE_PROCESSING_REQUIRED
;
5074 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
5078 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
5079 PKEVENT Event
= Irp
->UserEvent
;
5082 *IoStatusBlock
= Irp
->IoStatus
;
5083 Irp
->UserIosb
= NULL
;
5084 Irp
->UserEvent
= NULL
;
5088 Mdl
= Irp
->MdlAddress
;
5090 // if necessary - unlock pages
5091 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
5092 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
5101 // free irp and set event to unsignaled state
5103 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
5105 return STATUS_MORE_PROCESSING_REQUIRED
;