2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/class2/class2.c
5 * PURPOSE: SCSI Class driver routines
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
12 #include <include/class2.h>
15 /* Part of the drive letter hack */
23 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
24 #pragma alloc_text(PAGE, ScsiClassInitialize)
25 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
26 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
27 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
28 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
32 #define INQUIRY_DATA_SIZE 2048
33 #define START_UNIT_TIMEOUT 30
35 /* Disk layout used by Windows NT4 and earlier versions. */
36 //#define DEFAULT_SECTORS_PER_TRACK 32
37 //#define DEFAULT_TRACKS_PER_CYLINDER 64
39 /* Disk layout used by Windows 2000 and later versions. */
40 #define DEFAULT_SECTORS_PER_TRACK 63
41 #define DEFAULT_TRACKS_PER_CYLINDER 255
46 IN PDEVICE_OBJECT DeviceObject
,
53 IN PDEVICE_OBJECT DeviceObject
,
59 ScsiClassDeviceControlDispatch(
60 PDEVICE_OBJECT DeviceObject
,
66 ScsiClassDeviceControl(
67 PDEVICE_OBJECT DeviceObject
,
73 ScsiClassInternalIoControl (
74 IN PDEVICE_OBJECT DeviceObject
,
80 ScsiClassShutdownFlush(
81 IN PDEVICE_OBJECT DeviceObject
,
88 IN PDRIVER_OBJECT DriverObject
,
89 IN PUNICODE_STRING RegistryPath
93 // Class internal routines
100 PDEVICE_OBJECT DeviceObject
,
102 PSCSI_REQUEST_BLOCK Srb
,
109 IN PDEVICE_OBJECT DeviceObject
115 IN PDEVICE_OBJECT DeviceObject
,
122 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
130 IN PDRIVER_OBJECT DriverObject
,
131 IN PUNICODE_STRING RegistryPath
134 return STATUS_SUCCESS
;
137 /* The following hack to assign drive letters with a non-PnP storage stack */
139 typedef struct _CLASS_DEVICE_INFO
{
143 PDEVICE_OBJECT LowerDevice
;
144 } CLASS_DEVICE_INFO
, *PCLASS_DEVICE_INFO
;
146 typedef struct _CLASS_DRIVER_EXTENSION
{
148 CLASS_INIT_DATA InitializationData
;
149 } CLASS_DRIVER_EXTENSION
, *PCLASS_DRIVER_EXTENSION
;
153 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
156 UNICODE_STRING DriveLetterU
;
159 DriveLetterU
.Buffer
= Buffer1
;
160 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
162 /* Delete the symbolic link to PhysicalDriveX */
163 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DeviceInfo
->DriveNumber
) * sizeof(WCHAR
);
164 IoDeleteSymbolicLink(&DriveLetterU
);
166 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
168 for (Index
= 0; Index
< sizeof(ULONG
) * 8; Index
++)
170 if (DeviceInfo
->Partitions
& (1 << Index
))
172 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
173 IoDeleteSymbolicLink(&DriveLetterU
);
174 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
181 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
185 UNICODE_STRING DriveLetterU
, PartitionU
;
187 ULONG Index
, PartitionNumber
, DeviceNumber
, DriveNumber
;
188 OBJECT_ATTRIBUTES ObjectAttributes
;
189 IO_STATUS_BLOCK Iosb
;
190 HANDLE PartitionHandle
;
192 /* We assume this device does not current have a drive letter */
198 DriveLetterU
.Buffer
= Buffer1
;
199 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
200 PartitionU
.Buffer
= Buffer2
;
201 PartitionU
.MaximumLength
= sizeof(Buffer2
);
203 /* Determine the correct disk number */
206 /* Check that the disk exists */
207 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\HardDisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
208 InitializeObjectAttributes(&ObjectAttributes
,
210 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
213 Status
= ZwOpenFile(&PartitionHandle
,
214 FILE_READ_ATTRIBUTES
,
219 if (!NT_SUCCESS(Status
))
221 /* Return the last one that worked */
226 ZwClose(PartitionHandle
);
229 } while (Status
== STATUS_SUCCESS
);
231 /* Determine the correct drive number */
234 /* Check that the drive exists */
235 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
236 InitializeObjectAttributes(&ObjectAttributes
,
238 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
241 Status
= ZwOpenFile(&PartitionHandle
,
242 FILE_READ_ATTRIBUTES
,
247 if (NT_SUCCESS(Status
))
249 ZwClose(PartitionHandle
);
252 } while (Status
== STATUS_SUCCESS
);
254 /* Create the symbolic link to PhysicalDriveX */
255 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
256 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
258 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
259 if (!NT_SUCCESS(Status
))
261 /* Failed to create symbolic link */
265 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
269 /* Check that the disk exists */
270 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", DeviceNumber
, PartitionNumber
) * sizeof(WCHAR
);
271 InitializeObjectAttributes(&ObjectAttributes
,
273 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
276 Status
= ZwOpenFile(&PartitionHandle
,
277 FILE_READ_ATTRIBUTES
,
282 if (!NT_SUCCESS(Status
))
286 ZwClose(PartitionHandle
);
288 /* Assign it a drive letter */
291 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
293 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
296 } while (Status
!= STATUS_SUCCESS
);
298 DeviceInfo
->Partitions
|= (1 << (Index
- 1));
300 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
305 DeviceInfo
->DeviceNumber
= DeviceNumber
;
306 DeviceInfo
->DriveNumber
= DriveNumber
;
308 return STATUS_SUCCESS
;
314 IN PDEVICE_OBJECT DeviceObject
,
317 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
319 if (IrpSp
->MinorFunction
== IRP_MN_START_DEVICE
)
321 IoSkipCurrentIrpStackLocation(Irp
);
322 return STATUS_SUCCESS
;
324 else if (IrpSp
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
326 PCLASS_DEVICE_INFO DeviceInfo
= DeviceObject
->DeviceExtension
;
328 ScsiClassRemoveDriveLetter(DeviceInfo
);
330 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
331 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
333 IoDetachDevice(DeviceInfo
->LowerDevice
);
334 IoDeleteDevice(DeviceObject
);
335 return STATUS_SUCCESS
;
339 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
340 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
341 return STATUS_NOT_SUPPORTED
;
348 IN PDRIVER_OBJECT DriverObject
,
349 IN PDEVICE_OBJECT PhysicalDeviceObject
)
351 PCLASS_DRIVER_EXTENSION DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
352 PCLASS_DEVICE_INFO DeviceInfo
;
353 PDEVICE_OBJECT DeviceObject
;
356 if (DriverExtension
->InitializationData
.ClassFindDevices(DriverObject
, NULL
, &DriverExtension
->InitializationData
,
357 PhysicalDeviceObject
, DriverExtension
->PortNumber
))
359 /* Create a device object */
360 Status
= IoCreateDevice(DriverObject
,
361 sizeof(CLASS_DEVICE_INFO
),
367 if (!NT_SUCCESS(Status
))
372 DeviceInfo
= DeviceObject
->DeviceExtension
;
373 RtlZeroMemory(DeviceInfo
, sizeof(CLASS_DEVICE_INFO
));
375 /* Attach it to the PDO */
376 DeviceInfo
->LowerDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
378 /* Check that the kernel has already assigned drive letters */
379 if (KeLoaderBlock
== NULL
)
381 /* Assign a drive letter */
382 ScsiClassAssignDriveLetter(DeviceInfo
);
386 /* The kernel will handle it */
389 /* Move to the next port number */
390 DriverExtension
->PortNumber
++;
394 /* Failed to find device */
395 DbgPrint("FAILED TO FIND DEVICE!\n");
398 return STATUS_SUCCESS
;
400 /* ---- End hack ---- */
409 IN PCLASS_INIT_DATA InitializationData
416 This routine is called by a class driver during its
417 DriverEntry routine to initialize the driver.
421 Argument1 - Driver Object.
422 Argument2 - Registry Path.
423 InitializationData - Device-specific driver's initialization data.
427 A valid return code for a DriverEntry routine.
434 PDRIVER_OBJECT DriverObject
= Argument1
;
435 PDEVICE_OBJECT portDeviceObject
;
437 STRING deviceNameString
;
438 UNICODE_STRING unicodeDeviceName
;
439 PFILE_OBJECT fileObject
;
440 CCHAR deviceNameBuffer
[256];
441 BOOLEAN deviceFound
= FALSE
;
442 PCLASS_DRIVER_EXTENSION DriverExtension
;
444 DebugPrint((3,"\n\nSCSI Class Driver\n"));
447 // Validate the length of this structure. This is effectively a
451 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
453 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
454 return (ULONG
) STATUS_REVISION_MISMATCH
;
458 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
459 // are not required entry points.
462 if ((!InitializationData
->ClassFindDevices
) ||
463 (!InitializationData
->ClassDeviceControl
) ||
464 (!((InitializationData
->ClassReadWriteVerification
) ||
465 (InitializationData
->ClassStartIo
)))) {
468 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
470 return (ULONG
) STATUS_REVISION_MISMATCH
;
473 status
= IoAllocateDriverObjectExtension(DriverObject
,
475 sizeof(CLASS_DRIVER_EXTENSION
),
476 (PVOID
*)&DriverExtension
);
477 if (!NT_SUCCESS(status
))
480 RtlCopyMemory(&DriverExtension
->InitializationData
, InitializationData
, sizeof(CLASS_INIT_DATA
));
481 DriverExtension
->PortNumber
= 0;
484 // Update driver object with entry points.
487 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
488 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
489 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
490 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
491 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ScsiClassPlugPlay
;
492 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
493 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
494 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
495 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
496 DriverObject
->DriverExtension
->AddDevice
= ScsiClassAddDevice
;
498 if (InitializationData
->ClassStartIo
) {
499 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
503 // Open port driver controller device objects by name.
508 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", DriverExtension
->PortNumber
);
510 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
512 RtlInitString(&deviceNameString
, deviceNameBuffer
);
514 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
518 if (!NT_SUCCESS(status
)){
522 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
523 FILE_READ_ATTRIBUTES
,
527 if (NT_SUCCESS(status
)) {
530 // Call the device-specific driver's FindDevice routine.
533 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
534 portDeviceObject
, DriverExtension
->PortNumber
)) {
541 // Check next SCSI adapter.
544 DriverExtension
->PortNumber
++;
546 } while(NT_SUCCESS(status
));
548 /* We don't want to fail init just because we don't have devices right now */
549 return STATUS_SUCCESS
; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
555 ScsiClassCreateClose(
556 IN PDEVICE_OBJECT DeviceObject
,
564 SCSI class driver create and close routine. This is called by the I/O system
565 when the device is opened or closed.
569 DriverObject - Pointer to driver object created by system.
575 Device-specific drivers return value or STATUS_SUCCESS.
580 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
583 // Invoke the device-specific routine, if one exists. Otherwise complete
587 if (deviceExtension
->ClassCreateClose
) {
589 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
592 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
594 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
595 return(STATUS_SUCCESS
);
604 IN PDEVICE_OBJECT DeviceObject
,
612 This is the system entry point for read and write requests. The device-specific handler is invoked
613 to perform any validation necessary. The number of bytes in the request are
614 checked against the maximum byte counts that the adapter supports and requests are broken up into
615 smaller sizes if necessary.
629 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
630 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
632 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
633 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
636 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
637 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
640 // if DO_VERIFY_VOLUME bit is set
641 // in device object flags, fail request.
644 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
646 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
647 Irp
->IoStatus
.Information
= 0;
649 IoCompleteRequest(Irp
, 0);
650 return STATUS_VERIFY_REQUIRED
;
654 // Invoke the device specific routine to do whatever it needs to verify
658 ASSERT(deviceExtension
->ClassReadWriteVerification
);
660 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
662 if (!NT_SUCCESS(status
)) {
665 // It is up to the device specific driver to set the Irp status.
668 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
670 } else if (status
== STATUS_PENDING
) {
672 IoMarkIrpPending(Irp
);
673 return STATUS_PENDING
;
677 // Check for a zero length IO, as several macros will turn this into
678 // seemingly a 0xffffffff length request.
681 if (transferByteCount
== 0) {
682 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
683 Irp
->IoStatus
.Information
= 0;
684 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
685 return STATUS_SUCCESS
;
689 if (deviceExtension
->ClassStartIo
) {
691 IoMarkIrpPending(Irp
);
693 IoStartPacket(DeviceObject
,
698 return STATUS_PENDING
;
702 // Mark IRP with status pending.
705 IoMarkIrpPending(Irp
);
708 // Add partition byte offset to make starting byte relative to
709 // beginning of disk. In addition, add in skew for DM Driver, if any.
712 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
713 deviceExtension
->DMByteSkew
);
716 // Calculate number of pages in this transfer.
719 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
720 currentIrpStack
->Parameters
.Read
.Length
);
723 // Check if request length is greater than the maximum number of
724 // bytes that the hardware can transfer.
727 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
728 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
730 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
731 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
732 maximumTransferLength
));
733 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
734 currentIrpStack
->Parameters
.Read
.Length
));
737 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
739 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
740 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
744 // Check that maximum transfer size is not zero.
747 if (maximumTransferLength
== 0) {
748 maximumTransferLength
= PAGE_SIZE
;
752 // Mark IRP with status pending.
755 IoMarkIrpPending(Irp
);
758 // Request greater than port driver maximum.
759 // Break up into smaller routines.
762 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
765 return STATUS_PENDING
;
769 // Build SRB and CDB for this IRP.
772 ScsiClassBuildRequest(DeviceObject
, Irp
);
775 // Return the results of the call to the port driver.
778 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
780 } // end ScsiClassReadWrite()
785 ScsiClassGetCapabilities(
786 IN PDEVICE_OBJECT PortDeviceObject
,
787 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
794 This routine builds and sends a request to the port driver to
795 get a pointer to a structure that describes the adapter's
796 capabilities/limitations. This routine is sychronous.
800 PortDeviceObject - Port driver device object representing the HBA.
802 PortCapabilities - Location to store pointer to capabilities structure.
806 Nt status indicating the results of the operation.
810 This routine should only be called at initialization time.
816 IO_STATUS_BLOCK ioStatus
;
823 // Create notification event object to be used to signal the
824 // request completion.
827 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
830 // Build the synchronous request to be sent to the port driver
831 // to perform the request.
834 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
845 return STATUS_INSUFFICIENT_RESOURCES
;
849 // Pass request to port driver and wait for request to complete.
852 status
= IoCallDriver(PortDeviceObject
, irp
);
854 if (status
== STATUS_PENDING
) {
855 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
856 return(ioStatus
.Status
);
861 } // end ScsiClassGetCapabilities()
866 ScsiClassGetInquiryData(
867 IN PDEVICE_OBJECT PortDeviceObject
,
868 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
875 This routine sends a request to a port driver to return
876 configuration information. Space for the information is
877 allocated by this routine. The caller is responsible for
878 freeing the configuration information. This routine is
883 PortDeviceObject - Port driver device object representing the HBA.
885 ConfigInfo - Returns a pointer to the configuration information.
889 Nt status indicating the results of the operation.
893 This routine should be called only at initialization time.
899 IO_STATUS_BLOCK ioStatus
;
902 PSCSI_ADAPTER_BUS_INFO buffer
;
906 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
907 *ConfigInfo
= buffer
;
909 if (buffer
== NULL
) {
910 return(STATUS_INSUFFICIENT_RESOURCES
);
914 // Create notification event object to be used to signal the inquiry
915 // request completion.
918 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
921 // Build the synchronous request to be sent to the port driver
922 // to perform the inquiries.
925 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
936 return(STATUS_INSUFFICIENT_RESOURCES
);
940 // Pass request to port driver and wait for request to complete.
943 status
= IoCallDriver(PortDeviceObject
, irp
);
945 if (status
== STATUS_PENDING
) {
946 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
947 status
= ioStatus
.Status
;
950 if (!NT_SUCCESS(status
)) {
953 // Free the buffer on an error.
963 } // end ScsiClassGetInquiryData()
968 ScsiClassReadDriveCapacity(
969 IN PDEVICE_OBJECT DeviceObject
976 This routine sends a READ CAPACITY to the requested device, updates
977 the geometry information in the device object and returns
978 when it is complete. This routine is synchronous.
982 DeviceObject - Supplies a pointer to the device object that represents
983 the device whose capacity is to be read.
991 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
995 PREAD_CAPACITY_DATA readCapacityBuffer
;
996 SCSI_REQUEST_BLOCK srb
;
1000 // Allocate read capacity buffer from nonpaged pool.
1003 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
1004 sizeof(READ_CAPACITY_DATA
));
1006 if (!readCapacityBuffer
) {
1007 return(STATUS_INSUFFICIENT_RESOURCES
);
1010 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1013 // Build the read capacity CDB.
1017 cdb
= (PCDB
)srb
.Cdb
;
1020 // Set timeout value from device extension.
1023 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1025 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1029 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
1032 sizeof(READ_CAPACITY_DATA
),
1035 if (NT_SUCCESS(status
)) {
1038 // Copy sector size from read capacity buffer to device extension
1039 // in reverse byte order.
1042 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
1043 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
1045 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
1046 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
1048 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
1049 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
1051 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
1052 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
1055 // Copy last sector in reverse byte order.
1058 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
1059 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
1061 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
1062 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
1064 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
1065 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
1067 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
1068 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
1071 // Calculate sector to byte shift.
1074 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
1076 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
1077 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
1079 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
1083 // Calculate media capacity in bytes.
1086 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
1089 // Calculate number of cylinders.
1092 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
1094 deviceExtension
->PartitionLength
.QuadPart
=
1095 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
1097 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1100 // This device supports removable media.
1103 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1108 // Assume media type is fixed disk.
1111 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1115 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
1118 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
1121 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
1124 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
1127 if (status
== STATUS_VERIFY_REQUIRED
) {
1130 // Routine ScsiClassSendSrbSynchronous does not retry
1131 // requests returned with this status.
1132 // Read Capacities should be retried
1146 if (!NT_SUCCESS(status
)) {
1149 // If the read capacity fails, set the geometry to reasonable parameter
1150 // so things don't fail at unexpected places. Zero the geometry
1151 // except for the bytes per sector and sector shift.
1154 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
1155 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1156 deviceExtension
->SectorShift
= 9;
1157 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
1159 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1162 // This device supports removable media.
1165 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1170 // Assume media type is fixed disk.
1173 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1178 // Deallocate read capacity buffer.
1181 ExFreePool(readCapacityBuffer
);
1185 } // end ScsiClassReadDriveCapacity()
1190 ScsiClassReleaseQueue(
1191 IN PDEVICE_OBJECT DeviceObject
1196 Routine Description:
1198 This routine issues an internal device control command
1199 to the port driver to release a frozen queue. The call
1200 is issued asynchronously as ScsiClassReleaseQueue will be invoked
1201 from the IO completion DPC (and will have no context to
1202 wait for a synchronous call to complete).
1206 DeviceObject - The device object for the logical unit with
1215 PIO_STACK_LOCATION irpStack
;
1217 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1218 PCOMPLETION_CONTEXT context
;
1219 PSCSI_REQUEST_BLOCK srb
;
1223 // Allocate context from nonpaged pool.
1226 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1227 sizeof(COMPLETION_CONTEXT
));
1230 // Save the device object in the context for use by the completion
1234 context
->DeviceObject
= DeviceObject
;
1235 srb
= &context
->Srb
;
1241 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1244 // Write length to SRB.
1247 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1250 // Set up SCSI bus address.
1253 srb
->PathId
= deviceExtension
->PathId
;
1254 srb
->TargetId
= deviceExtension
->TargetId
;
1255 srb
->Lun
= deviceExtension
->Lun
;
1258 // If this device is removable then flush the queue. This will also
1262 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1264 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
1268 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
1273 // Build the asynchronous request to be sent to the port driver.
1276 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1281 // We have no better way of dealing with this at the moment
1284 KeBugCheck((ULONG
)0x0000002DL
);
1288 IoSetCompletionRoutine(irp
,
1289 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1295 irpStack
= IoGetNextIrpStackLocation(irp
);
1297 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1299 srb
->OriginalRequest
= irp
;
1302 // Store the SRB address in next stack for port driver.
1305 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1308 // Since this routine can cause outstanding requests to be completed, and
1309 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1310 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1311 // issuing the request
1314 currentIrql
= KeGetCurrentIrql();
1316 if(currentIrql
< DISPATCH_LEVEL
) {
1317 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1318 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1319 KeLowerIrql(currentIrql
);
1321 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1326 } // end ScsiClassReleaseQueue()
1332 IN PDEVICE_OBJECT DeviceObject
1337 Routine Description:
1339 Send command to SCSI unit to start or power up.
1340 Because this command is issued asynchronounsly, that is, without
1341 waiting on it to complete, the IMMEDIATE flag is not set. This
1342 means that the CDB will not return until the drive has powered up.
1343 This should keep subsequent requests from being submitted to the
1344 device before it has completely spun up.
1345 This routine is called from the InterpretSense routine, when a
1346 request sense returns data indicating that a drive must be
1351 DeviceObject - The device object for the logical unit with
1360 PIO_STACK_LOCATION irpStack
;
1362 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1363 PSCSI_REQUEST_BLOCK srb
;
1364 PCOMPLETION_CONTEXT context
;
1368 // Allocate Srb from nonpaged pool.
1371 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1372 sizeof(COMPLETION_CONTEXT
));
1375 // Save the device object in the context for use by the completion
1379 context
->DeviceObject
= DeviceObject
;
1380 srb
= &context
->Srb
;
1386 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1389 // Write length to SRB.
1392 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1395 // Set up SCSI bus address.
1398 srb
->PathId
= deviceExtension
->PathId
;
1399 srb
->TargetId
= deviceExtension
->TargetId
;
1400 srb
->Lun
= deviceExtension
->Lun
;
1402 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1405 // Set timeout value large enough for drive to spin up.
1408 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1411 // Set the transfer length.
1414 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1417 // Build the start unit CDB.
1421 cdb
= (PCDB
)srb
->Cdb
;
1423 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1424 cdb
->START_STOP
.Start
= 1;
1425 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1428 // Build the asynchronous request to be sent to the port driver.
1429 // Since this routine is called from a DPC the IRP should always be
1433 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1434 IoSetCompletionRoutine(irp
,
1435 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1441 irpStack
= IoGetNextIrpStackLocation(irp
);
1442 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1443 srb
->OriginalRequest
= irp
;
1446 // Store the SRB address in next stack for port driver.
1449 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1452 // Call the port driver with the IRP.
1455 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1459 } // end StartUnit()
1464 ScsiClassAsynchronousCompletion(
1465 PDEVICE_OBJECT DeviceObject
,
1471 Routine Description:
1473 This routine is called when an asynchronous I/O request
1474 which was issused by the class driver completes. Examples of such requests
1475 are release queue or START UNIT. This routine releases the queue if
1476 necessary. It then frees the context and the IRP.
1480 DeviceObject - The device object for the logical unit; however since this
1481 is the top stack location the value is NULL.
1483 Irp - Supplies a pointer to the Irp to be processed.
1485 Context - Supplies the context to be used to process this request.
1494 PCOMPLETION_CONTEXT context
= Context
;
1495 PSCSI_REQUEST_BLOCK srb
;
1497 srb
= &context
->Srb
;
1500 // If this is an execute srb, then check the return status and make sure.
1501 // the queue is not frozen.
1504 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1507 // Check for a frozen queue.
1510 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1513 // Unfreeze the queue getting the device object from the context.
1516 ScsiClassReleaseQueue(context
->DeviceObject
);
1521 // Free the context and the Irp.
1524 if (Irp
->MdlAddress
!= NULL
) {
1525 MmUnlockPages(Irp
->MdlAddress
);
1526 IoFreeMdl(Irp
->MdlAddress
);
1528 Irp
->MdlAddress
= NULL
;
1531 ExFreePool(context
);
1535 // Indicate the I/O system should stop processing the Irp completion.
1538 return STATUS_MORE_PROCESSING_REQUIRED
;
1540 } // ScsiClassAsynchronousCompletion()
1545 ScsiClassSplitRequest(
1546 IN PDEVICE_OBJECT DeviceObject
,
1548 IN ULONG MaximumBytes
1553 Routine Description:
1555 Break request into smaller requests. Each new request will be the
1556 maximum transfer size that the port driver can handle or if it
1557 is the final request, it may be the residual size.
1559 The number of IRPs required to process this request is written in the
1560 current stack of the original IRP. Then as each new IRP completes
1561 the count in the original IRP is decremented. When the count goes to
1562 zero, the original IRP is completed.
1566 DeviceObject - Pointer to the class device object to be addressed.
1568 Irp - Pointer to Irp the orginal request.
1577 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1578 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1579 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1580 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1581 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1582 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1583 ULONG dataLength
= MaximumBytes
;
1584 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1586 PSCSI_REQUEST_BLOCK srb
;
1588 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1589 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1592 // If all partial transfers complete successfully then the status and
1593 // bytes transferred are already set up. Failing a partial-transfer IRP
1594 // will set status to error and bytes transferred to 0 during
1595 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1596 // asynchronous partial transfers. This is an optimization for the
1600 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1601 Irp
->IoStatus
.Information
= transferByteCount
;
1604 // Save number of IRPs to complete count on current stack
1608 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1610 for (i
= 0; i
< irpCount
; i
++) {
1613 PIO_STACK_LOCATION newIrpStack
;
1616 // Allocate new IRP.
1619 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1621 if (newIrp
== NULL
) {
1623 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1626 // If an Irp can't be allocated then the orginal request cannot
1627 // be executed. If this is the first request then just fail the
1628 // orginal request; otherwise just return. When the pending
1629 // requests complete, they will complete the original request.
1630 // In either case set the IRP status to failure.
1633 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1634 Irp
->IoStatus
.Information
= 0;
1637 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1643 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1646 // Write MDL address to new IRP. In the port driver the SRB data
1647 // buffer field is used as an offset into the MDL, so the same MDL
1648 // can be used for each partial transfer. This saves having to build
1649 // a new MDL for each partial transfer.
1652 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1655 // At this point there is no current stack. IoSetNextIrpStackLocation
1656 // will make the first stack location the current stack so that the
1657 // SRB address can be written there.
1660 IoSetNextIrpStackLocation(newIrp
);
1661 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1663 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1664 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1665 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1666 newIrpStack
->DeviceObject
= DeviceObject
;
1669 // Build SRB and CDB.
1672 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1675 // Adjust SRB for this partial transfer.
1678 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1680 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1681 srb
->DataBuffer
= dataBuffer
;
1684 // Write original IRP address to new IRP.
1687 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1690 // Set the completion routine to ScsiClassIoCompleteAssociated.
1693 IoSetCompletionRoutine(newIrp
,
1694 ScsiClassIoCompleteAssociated
,
1701 // Call port driver with new request.
1704 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1707 // Set up for next request.
1710 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1712 transferByteCount
-= MaximumBytes
;
1714 if (transferByteCount
> MaximumBytes
) {
1716 dataLength
= MaximumBytes
;
1720 dataLength
= transferByteCount
;
1724 // Adjust disk byte offset.
1727 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1732 } // end ScsiClassSplitRequest()
1737 ScsiClassIoComplete(
1738 IN PDEVICE_OBJECT DeviceObject
,
1745 Routine Description:
1747 This routine executes when the port driver has completed a request.
1748 It looks at the SRB status in the completing SRB and if not success
1749 it checks for valid request sense buffer information. If valid, the
1750 info is used to update status with more precise message of type of
1751 error. This routine deallocates the SRB.
1755 DeviceObject - Supplies the device object which represents the logical
1758 Irp - Supplies the Irp which has completed.
1760 Context - Supplies a pointer to the SRB.
1769 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1770 PSCSI_REQUEST_BLOCK srb
= Context
;
1771 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1776 // Check SRB status for success of completing request.
1779 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1781 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1784 // Release the queue if it is frozen.
1787 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1788 ScsiClassReleaseQueue(DeviceObject
);
1791 retry
= ScsiClassInterpretSenseInfo(
1794 irpStack
->MajorFunction
,
1795 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1796 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1800 // If the status is verified required and the this request
1801 // should bypass verify required then retry the request.
1804 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1805 status
== STATUS_VERIFY_REQUIRED
) {
1807 status
= STATUS_IO_DEVICE_ERROR
;
1811 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1817 DebugPrint((1, "Retry request %lx\n", Irp
));
1818 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1819 return STATUS_MORE_PROCESSING_REQUIRED
;
1824 // Set status for successful request.
1827 status
= STATUS_SUCCESS
;
1829 } // end if (SRB_STATUS(srb->SrbStatus) ...
1832 // Return SRB to list.
1835 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1839 // Set status in completing IRP.
1842 Irp
->IoStatus
.Status
= status
;
1843 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1844 ASSERT(Irp
->IoStatus
.Information
);
1848 // Set the hard error if necessary.
1851 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1854 // Store DeviceObject for filesystem, and clear
1855 // in IoStatus.Information field.
1858 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1859 Irp
->IoStatus
.Information
= 0;
1863 // If pending has be returned for this irp then mark the current stack as
1867 if (Irp
->PendingReturned
) {
1868 IoMarkIrpPending(Irp
);
1871 if (deviceExtension
->ClassStartIo
) {
1872 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1873 IoStartNextPacket(DeviceObject
, FALSE
);
1879 } // end ScsiClassIoComplete()
1884 ScsiClassIoCompleteAssociated(
1885 IN PDEVICE_OBJECT DeviceObject
,
1892 Routine Description:
1894 This routine executes when the port driver has completed a request.
1895 It looks at the SRB status in the completing SRB and if not success
1896 it checks for valid request sense buffer information. If valid, the
1897 info is used to update status with more precise message of type of
1898 error. This routine deallocates the SRB. This routine is used for
1899 requests which were build by split request. After it has processed
1900 the request it decrements the Irp count in the master Irp. If the
1901 count goes to zero then the master Irp is completed.
1905 DeviceObject - Supplies the device object which represents the logical
1908 Irp - Supplies the Irp which has completed.
1910 Context - Supplies a pointer to the SRB.
1919 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1920 PSCSI_REQUEST_BLOCK srb
= Context
;
1921 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1922 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1928 // Check SRB status for success of completing request.
1931 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1933 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1936 // Release the queue if it is frozen.
1939 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1940 ScsiClassReleaseQueue(DeviceObject
);
1943 retry
= ScsiClassInterpretSenseInfo(
1946 irpStack
->MajorFunction
,
1947 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1948 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1952 // If the status is verified required and the this request
1953 // should bypass verify required then retry the request.
1956 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1957 status
== STATUS_VERIFY_REQUIRED
) {
1959 status
= STATUS_IO_DEVICE_ERROR
;
1963 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1966 // Retry request. If the class driver has supplied a StartIo,
1967 // call it directly for retries.
1970 DebugPrint((1, "Retry request %lx\n", Irp
));
1973 if (!deviceExtension->ClassStartIo) {
1974 RetryRequest(DeviceObject, Irp, srb, TRUE);
1976 deviceExtension->ClassStartIo(DeviceObject, Irp);
1980 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1982 return STATUS_MORE_PROCESSING_REQUIRED
;
1990 // Set status for successful request.
1993 status
= STATUS_SUCCESS
;
1995 } // end if (SRB_STATUS(srb->SrbStatus) ...
1998 // Return SRB to list.
2001 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
2005 // Set status in completing IRP.
2008 Irp
->IoStatus
.Status
= status
;
2010 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
2013 // Get next stack location. This original request is unused
2014 // except to keep track of the completing partial IRPs so the
2015 // stack location is valid.
2018 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
2021 // Update status only if error so that if any partial transfer
2022 // completes with error, then the original IRP will return with
2023 // error. If any of the asynchronous partial transfer IRPs fail,
2024 // with an error then the original IRP will return 0 bytes transfered.
2025 // This is an optimization for successful transfers.
2028 if (!NT_SUCCESS(status
)) {
2030 originalIrp
->IoStatus
.Status
= status
;
2031 originalIrp
->IoStatus
.Information
= 0;
2034 // Set the hard error if necessary.
2037 if (IoIsErrorUserInduced(status
)) {
2040 // Store DeviceObject for filesystem.
2043 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
2048 // Decrement and get the count of remaining IRPs.
2051 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
2053 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
2057 // Old bug could cause irp count to negative
2060 ASSERT(irpCount
>= 0);
2062 if (irpCount
== 0) {
2065 // All partial IRPs have completed.
2069 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
2072 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
2075 // If the class driver has supplied a startio, start the
2079 if (deviceExtension
->ClassStartIo
) {
2080 IoStartNextPacket(DeviceObject
, FALSE
);
2085 // Deallocate IRP and indicate the I/O system should not attempt any more
2090 return STATUS_MORE_PROCESSING_REQUIRED
;
2092 } // end ScsiClassIoCompleteAssociated()
2097 ScsiClassSendSrbSynchronous(
2098 PDEVICE_OBJECT DeviceObject
,
2099 PSCSI_REQUEST_BLOCK Srb
,
2100 PVOID BufferAddress
,
2102 BOOLEAN WriteToDevice
2107 Routine Description:
2109 This routine is called by SCSI device controls to complete an
2110 SRB and send it to the port driver synchronously (ie wait for
2111 completion). The CDB is already completed along with the SRB CDB
2112 size and request timeout value.
2116 DeviceObject - Supplies the device object which represents the logical
2119 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2121 BufferAddress - Supplies the address of the buffer.
2123 BufferLength - Supplies the length in bytes of the buffer.
2125 WriteToDevice - Indicates the data should be transfer to the device.
2129 Nt status indicating the final results of the operation.
2134 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2135 IO_STATUS_BLOCK ioStatus
;
2136 ULONG controlType
, mjFunction
;
2138 PIO_STACK_LOCATION irpStack
;
2140 PUCHAR senseInfoBuffer
;
2141 ULONG retryCount
= MAXIMUM_RETRIES
;
2144 LARGE_INTEGER dummy
;
2151 // Write length to SRB.
2154 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2157 // Set SCSI bus address.
2160 Srb
->PathId
= deviceExtension
->PathId
;
2161 Srb
->TargetId
= deviceExtension
->TargetId
;
2162 Srb
->Lun
= deviceExtension
->Lun
;
2163 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2166 // NOTICE: The SCSI-II specification indicates that this field should be
2167 // zero; however, some target controllers ignore the logical unit number
2168 // in the INDENTIFY message and only look at the logical unit number field
2172 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
2175 // Enable auto request sense.
2178 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
2181 // Sense buffer is in aligned nonpaged pool.
2184 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
2186 if (senseInfoBuffer
== NULL
) {
2189 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
2190 return(STATUS_INSUFFICIENT_RESOURCES
);
2193 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
2194 Srb
->DataBuffer
= BufferAddress
;
2197 // Start retries here.
2203 // Set the event object to the unsignaled state.
2204 // It will be used to signal request completion.
2207 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
2210 // Set controlType and Srb direction flags.
2213 if (BufferAddress
!= NULL
) {
2215 if (WriteToDevice
) {
2217 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
2218 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
2219 mjFunction
= IRP_MJ_WRITE
;
2223 controlType
= IOCTL_SCSI_EXECUTE_IN
;
2224 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
2225 mjFunction
= IRP_MJ_READ
;
2231 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
2232 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
2233 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
2237 // Build device I/O control request with data transfer.
2239 irp
= IoBuildAsynchronousFsdRequest(
2241 deviceExtension
->DeviceObject
,
2243 (BufferAddress
) ? BufferLength
: 0,
2248 ExFreePool(senseInfoBuffer
);
2249 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2250 return(STATUS_INSUFFICIENT_RESOURCES
);
2254 irp
->UserEvent
= &event
;
2257 // Disable synchronous transfer for these requests.
2260 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2263 // Set the transfer length.
2266 Srb
->DataTransferLength
= BufferLength
;
2272 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
2275 // Set completion routine
2276 IoSetCompletionRoutine(
2278 ClassCompletionRoutine
,
2285 // Get next stack location.
2288 irpStack
= IoGetNextIrpStackLocation(irp
);
2290 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2291 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2294 // Set up SRB for execute scsi request. Save SRB address in next stack
2295 // for the port driver.
2298 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2301 // Set up IRP Address.
2304 Srb
->OriginalRequest
= irp
;
2307 // Call the port driver with the request and wait for it to complete.
2310 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2312 if (status
== STATUS_PENDING
) {
2313 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2317 // Check that request completed without error.
2320 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2323 // Release the queue if it is frozen.
2326 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2327 ScsiClassReleaseQueue(DeviceObject
);
2331 // Update status and determine if request should be retried.
2334 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2338 MAXIMUM_RETRIES
- retryCount
,
2343 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2344 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2345 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2347 LARGE_INTEGER delay
;
2350 // Delay for 2 seconds.
2353 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2356 // Stall for a while to let the controller spinup.
2359 KeDelayExecutionThread(KernelMode
,
2366 // If retries are not exhausted then retry this operation.
2376 status
= STATUS_SUCCESS
;
2379 ExFreePool(senseInfoBuffer
);
2382 } // end ScsiClassSendSrbSynchronous()
2387 ScsiClassInterpretSenseInfo(
2388 IN PDEVICE_OBJECT DeviceObject
,
2389 IN PSCSI_REQUEST_BLOCK Srb
,
2390 IN UCHAR MajorFunctionCode
,
2391 IN ULONG IoDeviceCode
,
2392 IN ULONG RetryCount
,
2393 OUT NTSTATUS
*Status
2398 Routine Description:
2400 This routine interprets the data returned from the SCSI
2401 request sense. It determines the status to return in the
2402 IRP and whether this request can be retried.
2406 DeviceObject - Supplies the device object associated with this request.
2408 Srb - Supplies the scsi request block which failed.
2410 MajorFunctionCode - Supplies the function code to be used for logging.
2412 IoDeviceCode - Supplies the device code to be used for logging.
2414 Status - Returns the status for the request.
2418 BOOLEAN TRUE: Drivers should retry this request.
2419 FALSE: Drivers should not retry this request.
2424 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2425 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2426 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2427 BOOLEAN retry
= TRUE
;
2428 BOOLEAN logError
= FALSE
;
2429 ULONG badSector
= 0;
2434 PIO_ERROR_LOG_PACKET errorLogEntry
;
2441 // Check that request sense buffer is valid.
2445 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2446 for (i
= 1; i
< 12; i
++) {
2447 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2449 DebugPrint((3,"\n"));
2452 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2453 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2455 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2456 senseBuffer
->ErrorCode
));
2457 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2458 senseBuffer
->SenseKey
));
2459 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2460 senseBuffer
->AdditionalSenseCode
));
2461 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2462 senseBuffer
->AdditionalSenseCodeQualifier
));
2465 // Zero the additional sense code and additional sense code qualifier
2466 // if they were not returned by the device.
2469 readSector
= senseBuffer
->AdditionalSenseLength
+
2470 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2472 if (readSector
> Srb
->SenseInfoBufferLength
) {
2473 readSector
= Srb
->SenseInfoBufferLength
;
2476 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2477 senseBuffer
->AdditionalSenseCode
= 0;
2480 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2481 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2484 switch (senseBuffer
->SenseKey
& 0xf) {
2486 case SCSI_SENSE_NOT_READY
:
2488 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2489 *Status
= STATUS_DEVICE_NOT_READY
;
2491 switch (senseBuffer
->AdditionalSenseCode
) {
2493 case SCSI_ADSENSE_LUN_NOT_READY
:
2495 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2497 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2499 case SCSI_SENSEQ_BECOMING_READY
:
2501 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2502 " In process of becoming ready\n"));
2505 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2507 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2508 " Manual intervention required\n"));
2509 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2513 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2515 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2519 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2523 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2524 " Initializing command required\n"));
2527 // This sense code/additional sense code
2528 // combination may indicate that the device
2529 // needs to be started. Send an start unit if this
2530 // is a disk device.
2533 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2534 StartUnit(DeviceObject
);
2539 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2543 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2546 "ScsiClassInterpretSenseInfo:"
2547 " No Media in device.\n"));
2548 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2552 // signal autorun that there isn't any media in the device
2555 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2556 (!deviceExtension
->MediaChangeNoMedia
)) {
2557 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2560 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2561 "Detected No Media In Device "
2562 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2563 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2567 } // end switch (senseBuffer->AdditionalSenseCode)
2571 case SCSI_SENSE_DATA_PROTECT
:
2573 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2574 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2578 case SCSI_SENSE_MEDIUM_ERROR
:
2580 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2581 *Status
= STATUS_DEVICE_DATA_ERROR
;
2586 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2589 case SCSI_SENSE_HARDWARE_ERROR
:
2591 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2592 *Status
= STATUS_IO_DEVICE_ERROR
;
2596 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2600 case SCSI_SENSE_ILLEGAL_REQUEST
:
2602 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2603 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2605 switch (senseBuffer
->AdditionalSenseCode
) {
2607 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2608 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2612 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2613 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2614 *Status
= STATUS_NONEXISTENT_SECTOR
;
2618 case SCSI_ADSENSE_INVALID_LUN
:
2619 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2620 *Status
= STATUS_NO_SUCH_DEVICE
;
2624 case SCSI_ADSENSE_MUSIC_AREA
:
2625 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2629 case SCSI_ADSENSE_DATA_AREA
:
2630 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2634 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2635 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2639 case SCSI_ADSENSE_INVALID_CDB
:
2640 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2643 // Check if write cache enabled.
2646 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2649 // Assume FUA is not supported.
2652 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2661 } // end switch (senseBuffer->AdditionalSenseCode)
2665 case SCSI_SENSE_UNIT_ATTENTION
:
2667 switch (senseBuffer
->AdditionalSenseCode
) {
2668 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2669 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2671 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2673 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2676 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2677 "New Media Found - Setting MediaChanged event"
2678 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2679 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2684 case SCSI_ADSENSE_BUS_RESET
:
2685 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2689 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2692 } // end switch (senseBuffer->AdditionalSenseCode)
2694 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2695 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2698 // Set bit to indicate that media may have changed
2699 // and volume needs verification.
2702 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2704 *Status
= STATUS_VERIFY_REQUIRED
;
2709 *Status
= STATUS_IO_DEVICE_ERROR
;
2714 // A media change may have occured so increment the change
2715 // count for the physical device
2718 physicalExtension
->MediaChangeCount
++;
2720 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2721 "count for device %d is %d\n",
2722 physicalExtension
->DeviceNumber
,
2723 physicalExtension
->MediaChangeCount
));
2727 case SCSI_SENSE_ABORTED_COMMAND
:
2729 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2730 *Status
= STATUS_IO_DEVICE_ERROR
;
2733 case SCSI_SENSE_RECOVERED_ERROR
:
2735 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2736 *Status
= STATUS_SUCCESS
;
2741 switch(senseBuffer
->AdditionalSenseCode
) {
2742 case SCSI_ADSENSE_SEEK_ERROR
:
2743 case SCSI_ADSENSE_TRACK_ERROR
:
2744 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2747 case SCSI_ADSENSE_REC_DATA_NOECC
:
2748 case SCSI_ADSENSE_REC_DATA_ECC
:
2749 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2753 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2756 } // end switch(senseBuffer->AdditionalSenseCode)
2758 if (senseBuffer
->IncorrectLength
) {
2760 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2761 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2766 case SCSI_SENSE_NO_SENSE
:
2769 // Check other indicators.
2772 if (senseBuffer
->IncorrectLength
) {
2774 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2775 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2780 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2781 *Status
= STATUS_IO_DEVICE_ERROR
;
2789 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2790 *Status
= STATUS_IO_DEVICE_ERROR
;
2793 } // end switch (senseBuffer->SenseKey & 0xf)
2796 // Try to determine the bad sector from the inquiry data.
2799 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2800 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2801 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2803 for (index
= 0; index
< 4; index
++) {
2804 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2808 for (index
= 0; index
< 4; index
++) {
2809 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2812 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2813 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2816 // Make sure the bad sector is within the read sectors.
2819 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2820 badSector
= readSector
;
2827 // Request sense buffer not valid. No sense information
2828 // to pinpoint the error. Return general request fail.
2831 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2832 SRB_STATUS(Srb
->SrbStatus
)));
2835 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2836 case SRB_STATUS_INVALID_LUN
:
2837 case SRB_STATUS_INVALID_TARGET_ID
:
2838 case SRB_STATUS_NO_DEVICE
:
2839 case SRB_STATUS_NO_HBA
:
2840 case SRB_STATUS_INVALID_PATH_ID
:
2841 *Status
= STATUS_NO_SUCH_DEVICE
;
2845 case SRB_STATUS_COMMAND_TIMEOUT
:
2846 case SRB_STATUS_ABORTED
:
2847 case SRB_STATUS_TIMEOUT
:
2850 // Update the error count for the device.
2853 deviceExtension
->ErrorCount
++;
2854 *Status
= STATUS_IO_TIMEOUT
;
2857 case SRB_STATUS_SELECTION_TIMEOUT
:
2859 logStatus
= 0;//IO_ERR_NOT_READY;
2861 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2865 case SRB_STATUS_DATA_OVERRUN
:
2866 *Status
= STATUS_DATA_OVERRUN
;
2870 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2873 // Update the error count for the device.
2876 deviceExtension
->ErrorCount
++;
2877 *Status
= STATUS_IO_DEVICE_ERROR
;
2880 // If there was phase sequence error then limit the number of
2884 if (RetryCount
> 1 ) {
2890 case SRB_STATUS_REQUEST_FLUSHED
:
2893 // If the status needs verification bit is set. Then set
2894 // the status to need verification and no retry; otherwise,
2895 // just retry the request.
2898 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2900 *Status
= STATUS_VERIFY_REQUIRED
;
2903 *Status
= STATUS_IO_DEVICE_ERROR
;
2908 case SRB_STATUS_INVALID_REQUEST
:
2911 // An invalid request was attempted.
2914 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2918 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2919 case SRB_STATUS_PARITY_ERROR
:
2922 // Update the error count for the device.
2925 deviceExtension
->ErrorCount
++;
2928 // Fall through to below.
2931 case SRB_STATUS_BUS_RESET
:
2932 *Status
= STATUS_IO_DEVICE_ERROR
;
2935 case SRB_STATUS_ERROR
:
2937 *Status
= STATUS_IO_DEVICE_ERROR
;
2938 if (Srb
->ScsiStatus
== 0) {
2941 // This is some strange return code. Update the error
2942 // count for the device.
2945 deviceExtension
->ErrorCount
++;
2947 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2949 *Status
= STATUS_DEVICE_NOT_READY
;
2951 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2953 *Status
= STATUS_DEVICE_BUSY
;
2962 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2964 *Status
= STATUS_IO_DEVICE_ERROR
;
2970 // If the error count has exceeded the error limit, then disable
2971 // any tagged queuing, multiple requests per lu queueing
2972 // and sychronous data transfers.
2975 if (deviceExtension
->ErrorCount
== 4) {
2978 // Clearing the no queue freeze flag prevents the port driver
2979 // from sending multiple requests per logical unit.
2982 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2983 SRB_FLAGS_NO_QUEUE_FREEZE
);
2985 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2986 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2988 } else if (deviceExtension
->ErrorCount
== 8) {
2991 // If a second threshold is reached, disable disconnects.
2994 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
2995 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
3000 // If there is a class specific error handler call it.
3003 if (deviceExtension
->ClassError
!= NULL
) {
3005 deviceExtension
->ClassError(DeviceObject
,
3012 // Log an error if necessary.
3017 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3019 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
3021 if (errorLogEntry
== NULL
) {
3024 // Return if no packet could be allocated.
3031 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
3032 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3034 errorLogEntry
->FinalStatus
= *Status
;
3038 // Calculate the device offset if there is a geometry.
3041 if (deviceExtension
->DiskGeometry
!= NULL
) {
3043 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
3044 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
3045 errorLogEntry
->DeviceOffset
,
3046 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
3049 errorLogEntry
->ErrorCode
= logStatus
;
3050 errorLogEntry
->SequenceNumber
= 0;
3051 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
3052 errorLogEntry
->IoControlCode
= IoDeviceCode
;
3053 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
3054 errorLogEntry
->UniqueErrorValue
= uniqueId
;
3055 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
3056 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
3057 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
3058 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
3059 errorLogEntry
->DumpData
[3] = 0;
3060 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
3062 if (senseBuffer
!= NULL
) {
3063 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
3064 senseBuffer
->AdditionalSenseCode
<< 8 |
3065 senseBuffer
->AdditionalSenseCodeQualifier
;
3070 // Write the error log packet.
3073 IoWriteErrorLogEntry(errorLogEntry
);
3078 } // end ScsiClassInterpretSenseInfo()
3084 PDEVICE_OBJECT DeviceObject
,
3086 PSCSI_REQUEST_BLOCK Srb
,
3092 Routine Description:
3094 This routine reinitalizes the necessary fields, and sends the request
3099 DeviceObject - Supplies the device object associated with this request.
3101 Irp - Supplies the request to be retried.
3103 Srb - Supplies a Pointer to the SCSI request block to be retied.
3105 Assocaiated - Indicates this is an assocatied Irp created by split request.
3114 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3115 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3116 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3117 ULONG transferByteCount
;
3120 // Determine the transfer count of the request. If this is a read or a
3121 // write then the transfer count is in the Irp stack. Otherwise assume
3122 // the MDL contains the correct length. If there is no MDL then the
3123 // transfer length must be zero.
3126 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
3127 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
3129 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3131 } else if (Irp
->MdlAddress
!= NULL
) {
3134 // Note this assumes that only read and write requests are spilt and
3135 // other request do not need to be. If the data buffer address in
3136 // the MDL and the SRB don't match then transfer length is most
3137 // likely incorrect.
3140 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3141 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
3145 transferByteCount
= 0;
3149 // Reset byte count of transfer in SRB Extension.
3152 Srb
->DataTransferLength
= transferByteCount
;
3155 // Zero SRB statuses.
3158 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
3161 // Set the no disconnect flag, disable synchronous data transfers and
3162 // disable tagged queuing. This fixes some errors.
3165 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
3166 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3168 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
3169 Srb
->QueueTag
= SP_UNTAGGED
;
3172 // Set up major SCSI function.
3175 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3178 // Save SRB address in next stack for port driver.
3181 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
3184 // Set up IoCompletion routine address.
3189 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
3193 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3197 // Pass the request to the port driver.
3200 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3202 } // end RetryRequest()
3206 ScsiClassBuildRequest(
3207 PDEVICE_OBJECT DeviceObject
,
3213 Routine Description:
3215 This routine allocates and builds an Srb for a read or write request.
3216 The block address and length are supplied by the Irp. The retry count
3217 is stored in the current stack for use by ScsiClassIoComplete which
3218 processes these requests when they complete. The Irp is ready to be
3219 passed to the port driver when this routine returns.
3223 DeviceObject - Supplies the device object associated with this request.
3225 Irp - Supplies the request to be retried.
3229 If the IRP is for a disk transfer, the byteoffset field
3230 will already have been adjusted to make it relative to
3231 the beginning of the disk.
3241 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3242 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3243 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3244 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3245 PSCSI_REQUEST_BLOCK srb
;
3247 ULONG logicalBlockAddress
;
3248 USHORT transferBlocks
;
3251 // Calculate relative sector address.
3254 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
3260 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
3265 // Write length to SRB.
3268 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3271 // Set up IRP Address.
3274 srb
->OriginalRequest
= Irp
;
3277 // Set up target ID and logical unit number.
3280 srb
->PathId
= deviceExtension
->PathId
;
3281 srb
->TargetId
= deviceExtension
->TargetId
;
3282 srb
->Lun
= deviceExtension
->Lun
;
3283 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3284 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3287 // Save byte count of transfer in SRB Extension.
3290 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3293 // Initialize the queue actions field.
3296 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3299 // Queue sort key is Relative Block Address.
3302 srb
->QueueSortKey
= logicalBlockAddress
;
3305 // Indicate auto request sense by specifying buffer and size.
3308 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3309 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3312 // Set timeout value of one unit per 64k bytes of data.
3315 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3316 deviceExtension
->TimeOutValue
;
3322 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3326 // Indicate that 10-byte CDB's will be used.
3329 srb
->CdbLength
= 10;
3332 // Fill in CDB fields.
3335 cdb
= (PCDB
)srb
->Cdb
;
3338 // Zero 12 bytes for Atapi Packets
3341 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3343 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3344 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3347 // Move little endian values into CDB in big endian format.
3350 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3351 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3352 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3353 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3355 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3356 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3359 // Set transfer direction flag and Cdb command.
3362 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3364 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3366 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3367 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3371 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3373 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3374 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3378 // If this is not a write-through request, then allow caching.
3381 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3383 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3388 // If write caching is enable then force media access in the
3392 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3393 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3398 // Or in the default flags from the device object.
3401 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3404 // Set up major SCSI function.
3407 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3410 // Save SRB address in next stack for port driver.
3413 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3416 // Save retry count in current IRP stack.
3419 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3422 // Set up IoCompletion routine address.
3425 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3429 } // end ScsiClassBuildRequest()
3434 IN PDEVICE_OBJECT DeviceObject
,
3435 IN PCHAR ModeSenseBuffer
,
3442 Routine Description:
3444 This routine sends a mode sense command to a target ID and returns
3445 when it is complete.
3449 DeviceObject - Supplies the device object associated with this request.
3451 ModeSenseBuffer - Supplies a buffer to store the sense data.
3453 Length - Supplies the length in bytes of the mode sense buffer.
3455 PageMode - Supplies the page or pages of mode sense data to be retrived.
3459 Length of the transferred data is returned.
3463 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3465 SCSI_REQUEST_BLOCK srb
;
3469 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3472 // Build the MODE SENSE CDB.
3476 cdb
= (PCDB
)srb
.Cdb
;
3479 // Set timeout value from device extension.
3482 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3484 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3485 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3486 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3490 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3497 if (status
== STATUS_VERIFY_REQUIRED
) {
3500 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3501 // this status. MODE SENSE commands should be retried anyway.
3513 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3514 status
= STATUS_SUCCESS
;
3517 if (NT_SUCCESS(status
)) {
3518 return(srb
.DataTransferLength
);
3523 } // end ScsiClassModeSense()
3528 ScsiClassFindModePage(
3529 IN PCHAR ModeSenseBuffer
,
3537 Routine Description:
3539 This routine scans through the mode sense data and finds the requested
3540 mode sense page code.
3543 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3545 Length - Indicates the length of valid data.
3547 PageMode - Supplies the page mode to be searched for.
3549 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3553 A pointer to the the requested mode page. If the mode page was not found
3554 then NULL is return.
3559 ULONG parameterHeaderLength
;
3561 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3562 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3566 // Skip the mode select header and block descriptors.
3569 if (Length
< parameterHeaderLength
) {
3575 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3576 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3579 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3580 // requested page until the limit is reached.
3584 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3586 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3587 return(ModeSenseBuffer
);
3591 // Advance to the next page.
3594 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3602 ScsiClassSendSrbAsynchronous(
3603 PDEVICE_OBJECT DeviceObject
,
3604 PSCSI_REQUEST_BLOCK Srb
,
3606 PVOID BufferAddress
,
3608 BOOLEAN WriteToDevice
3612 Routine Description:
3614 This routine takes a partially built Srb and an Irp and sends it down to
3618 DeviceObject - Supplies the device object for the orginal request.
3620 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3621 CDB and the SRB timeout value must be filled in. The SRB must not be
3622 allocated from zone.
3624 Irp - Supplies the requesting Irp.
3626 BufferAddress - Supplies a pointer to the buffer to be transfered.
3628 BufferLength - Supplies the length of data transfer.
3630 WriteToDevice - Indicates the data transfer will be from system memory to
3635 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3640 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3641 PIO_STACK_LOCATION irpStack
;
3646 // Write length to SRB.
3649 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3652 // Set SCSI bus address.
3655 Srb
->PathId
= deviceExtension
->PathId
;
3656 Srb
->TargetId
= deviceExtension
->TargetId
;
3657 Srb
->Lun
= deviceExtension
->Lun
;
3659 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3662 // This is a violation of the SCSI spec but it is required for
3666 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3669 // Indicate auto request sense by specifying buffer and size.
3672 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3673 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3674 Srb
->DataBuffer
= BufferAddress
;
3676 if (BufferAddress
!= NULL
) {
3679 // Build Mdl if necessary.
3682 if (Irp
->MdlAddress
== NULL
) {
3684 if (IoAllocateMdl(BufferAddress
,
3690 return(STATUS_INSUFFICIENT_RESOURCES
);
3693 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3698 // Make sure the buffer requested matches the MDL.
3701 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3708 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3716 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3720 // Disable synchronous transfer for these requests.
3723 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3726 // Set the transfer length.
3729 Srb
->DataTransferLength
= BufferLength
;
3735 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3740 // Save a few parameters in the current stack location.
3743 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3746 // Save retry count in current Irp stack.
3749 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3752 // Set up IoCompletion routine address.
3755 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3758 // Get next stack location and
3759 // set major function code.
3762 irpStack
= IoGetNextIrpStackLocation(Irp
);
3764 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3767 // Save SRB address in next stack for port driver.
3770 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3773 // Set up Irp Address.
3776 Srb
->OriginalRequest
= Irp
;
3779 // Call the port driver to process the request.
3782 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3789 ScsiClassDeviceControlDispatch(
3790 PDEVICE_OBJECT DeviceObject
,
3796 Routine Description:
3798 The routine is the common class driver device control dispatch entry point.
3799 This routine is invokes the device-specific drivers DeviceControl routine,
3800 (which may call the Class driver's common DeviceControl routine).
3804 DeviceObject - Supplies a pointer to the device object for this request.
3806 Irp - Supplies the Irp making the request.
3810 Returns the status returned from the device-specific driver.
3816 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3820 // Call the class specific driver DeviceControl routine.
3821 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3824 ASSERT(deviceExtension
->ClassDeviceControl
);
3826 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3832 ScsiClassDeviceControl(
3833 PDEVICE_OBJECT DeviceObject
,
3838 Routine Description:
3840 The routine is the common class driver device control dispatch function.
3841 This routine is called by a class driver when it get an unrecognized
3842 device control request. This routine will perform the correct action for
3843 common requests such as lock media. If the device request is unknown it
3844 passed down to the next level.
3848 DeviceObject - Supplies a pointer to the device object for this request.
3850 Irp - Supplies the Irp making the request.
3854 Returns back a STATUS_PENDING or a completion status.
3859 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3860 PIO_STACK_LOCATION nextStack
;
3861 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3862 PSCSI_REQUEST_BLOCK srb
;
3865 ULONG modifiedIoControlCode
;
3867 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3868 IOCTL_STORAGE_RESET_DEVICE
) {
3870 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3871 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3872 status
= STATUS_UNSUCCESSFUL
;
3873 goto SetStatusAndReturn
;
3877 // If this is a pass through I/O control, set the minor function code
3878 // and device address and pass it to the port driver.
3881 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3882 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3884 PSCSI_PASS_THROUGH scsiPass
;
3886 nextStack
= IoGetNextIrpStackLocation(Irp
);
3889 // Validiate the user buffer.
3892 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3894 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3895 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3896 status
= STATUS_INVALID_PARAMETER
;
3897 goto SetStatusAndReturn
;
3901 // Force the SCSI address to the correct value.
3904 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3905 scsiPass
->PathId
= deviceExtension
->PathId
;
3906 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3907 scsiPass
->Lun
= deviceExtension
->Lun
;
3910 // NOTICE: The SCSI-II specificaiton indicates that this field
3911 // should be zero; however, some target controllers ignore the logical
3912 // unit number in the INDENTIFY message and only look at the logical
3913 // unit number field in the CDB.
3916 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3918 nextStack
->Parameters
= irpStack
->Parameters
;
3919 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3920 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3922 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3923 goto SetStatusAndReturn
;
3926 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3928 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3930 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3931 sizeof(SCSI_ADDRESS
)) {
3934 // Indicate unsuccessful status and no data transferred.
3937 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3938 Irp
->IoStatus
.Information
= 0;
3939 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3940 status
= STATUS_BUFFER_TOO_SMALL
;
3941 goto SetStatusAndReturn
;
3945 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3946 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3947 scsiAddress
->PathId
= deviceExtension
->PathId
;
3948 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3949 scsiAddress
->Lun
= deviceExtension
->Lun
;
3950 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3951 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3952 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3953 status
= STATUS_SUCCESS
;
3954 goto SetStatusAndReturn
;
3957 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3961 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3962 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3963 status
= STATUS_INSUFFICIENT_RESOURCES
;
3964 goto SetStatusAndReturn
;
3968 // Write zeros to Srb.
3971 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3973 cdb
= (PCDB
)srb
->Cdb
;
3976 // Change the device type to disk for the switch statement.
3979 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3980 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3982 switch (modifiedIoControlCode
) {
3984 case IOCTL_DISK_CHECK_VERIFY
: {
3987 PIO_STACK_LOCATION newStack
;
3989 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3992 // If a buffer for a media change count was provided, make sure it's
3993 // big enough to hold the result
3996 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
3999 // If the buffer is too small to hold the media change count
4000 // then return an error to the caller
4003 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4006 DebugPrint((3,"ScsiDeviceIoControl: media count "
4007 "buffer too small\n"));
4009 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4010 Irp
->IoStatus
.Information
= 0;
4012 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4013 status
= STATUS_BUFFER_TOO_SMALL
;
4014 goto SetStatusAndReturn
;
4019 // The caller has provided a valid buffer. Allocate an additional
4020 // irp and stick the CheckVerify completion routine on it. We will
4021 // then send this down to the port driver instead of the irp the
4025 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
4029 // Allocate a new irp to send the TestUnitReady to the port driver
4032 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
4035 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4036 Irp
->IoStatus
.Information
= 0;
4038 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4039 status
= STATUS_INSUFFICIENT_RESOURCES
;
4040 goto SetStatusAndReturn
;
4045 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
4046 IoSetNextIrpStackLocation(irp2
);
4049 // Set the top stack location and shove the master Irp into the
4053 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4054 newStack
->Parameters
.Others
.Argument1
= Irp
;
4055 newStack
->DeviceObject
= DeviceObject
;
4058 // Stick the check verify completion routine onto the stack
4059 // and prepare the irp for the port driver
4062 IoSetCompletionRoutine(irp2
,
4063 ScsiClassCheckVerifyComplete
,
4069 IoSetNextIrpStackLocation(irp2
);
4070 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4071 newStack
->DeviceObject
= DeviceObject
;
4074 // Mark the master irp as pending - whether the lower level
4075 // driver completes it immediately or not this should allow it
4076 // to go all the way back up.
4079 IoMarkIrpPending(Irp
);
4090 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
4093 // Set timeout value.
4096 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4099 // Since this routine will always hand the request to the
4100 // port driver if there isn't a data transfer to be done
4101 // we don't have to worry about completing the request here
4105 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4115 case IOCTL_DISK_MEDIA_REMOVAL
: {
4117 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
4120 // Prevent/Allow media removal.
4123 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4125 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4126 sizeof(PREVENT_MEDIA_REMOVAL
)) {
4129 // Indicate unsuccessful status and no data transferred.
4132 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4133 Irp
->IoStatus
.Information
= 0;
4135 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4136 status
= STATUS_BUFFER_TOO_SMALL
;
4137 goto SetStatusAndReturn
;
4141 // Get physical device extension. This is where the
4142 // lock count is stored.
4145 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
4148 // If command succeeded then increment or decrement lock counter.
4151 if (MediaRemoval
->PreventMediaRemoval
) {
4154 // This is a lock command. Reissue the command in case bus or device
4155 // was reset and lock cleared.
4158 InterlockedIncrement(&deviceExtension
->LockCount
);
4161 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4162 deviceExtension
->LockCount
,
4163 deviceExtension
->DeviceNumber
));
4168 // This is an unlock command.
4171 if (!deviceExtension
->LockCount
||
4172 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
4175 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4176 deviceExtension
->LockCount
,
4177 deviceExtension
->DeviceNumber
));
4180 // Don't unlock because someone still wants it locked.
4183 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4185 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4186 status
= STATUS_SUCCESS
;
4187 goto SetStatusAndReturn
;
4191 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4192 deviceExtension
->LockCount
,
4193 deviceExtension
->DeviceNumber
));
4198 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
4201 // TRUE - prevent media removal.
4202 // FALSE - allow media removal.
4205 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
4208 // Set timeout value.
4211 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4212 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4220 // Some devices will not support lock/unlock.
4221 // Pretend that it worked.
4227 case IOCTL_DISK_RESERVE
: {
4230 // Reserve logical unit.
4235 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
4238 // Set timeout value.
4241 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4243 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4253 case IOCTL_DISK_RELEASE
: {
4256 // Release logical unit.
4261 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
4264 // Set timeout value.
4267 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4269 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4279 case IOCTL_DISK_EJECT_MEDIA
: {
4287 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4288 cdb
->START_STOP
.LoadEject
= 1;
4289 cdb
->START_STOP
.Start
= 0;
4292 // Set timeout value.
4295 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4296 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4305 case IOCTL_DISK_LOAD_MEDIA
: {
4311 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4315 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4316 cdb
->START_STOP
.LoadEject
= 1;
4317 cdb
->START_STOP
.Start
= 1;
4320 // Set timeout value.
4323 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4324 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4334 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4337 // Search for devices that have been powered on since the last
4338 // device search or system initialization.
4341 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4342 status
= DriverEntry(DeviceObject
->DriverObject
,
4345 Irp
->IoStatus
.Status
= status
;
4347 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4354 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4357 // Pass the device control to the next driver.
4363 // Copy the Irp stack parameters to the next stack location.
4366 nextStack
= IoGetNextIrpStackLocation(Irp
);
4367 nextStack
->Parameters
= irpStack
->Parameters
;
4368 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4369 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4371 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4375 } // end switch( ...
4385 ScsiClassShutdownFlush(
4386 IN PDEVICE_OBJECT DeviceObject
,
4392 Routine Description:
4394 This routine is called for a shutdown and flush IRPs. These are sent by the
4395 system before it actually shuts down or when the file system does a flush.
4396 If it exists, the device-specific driver's routine will be invoked. If there
4397 wasn't one specified, the Irp will be completed with an Invalid device request.
4401 DriverObject - Pointer to device object to being shutdown by system.
4412 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4414 if (deviceExtension
->ClassShutdownFlush
) {
4417 // Call the device-specific driver's routine.
4420 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4424 // Device-specific driver doesn't support this.
4427 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4428 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4430 return STATUS_INVALID_DEVICE_REQUEST
;
4436 ScsiClassFindUnclaimedDevices(
4437 IN PCLASS_INIT_DATA InitializationData
,
4438 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4442 ULONG scsiBus
,deviceCount
= 0;
4443 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4444 PSCSI_INQUIRY_DATA lunInfo
;
4445 PINQUIRYDATA inquiryData
;
4447 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4450 // Get the SCSI bus scan data for this bus.
4453 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4456 // Search list for unclaimed disk devices.
4459 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4461 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4463 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4465 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4470 if (lunInfo
->NextInquiryDataOffset
== 0) {
4474 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4484 ScsiClassCreateDeviceObject(
4485 IN PDRIVER_OBJECT DriverObject
,
4486 IN PCCHAR ObjectNameBuffer
,
4487 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4488 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4489 IN PCLASS_INIT_DATA InitializationData
4494 Routine Description:
4496 This routine creates an object for the physical device specified and
4497 sets up the deviceExtension's function pointers for each entry point
4498 in the device-specific driver.
4502 DriverObject - Pointer to driver object created by system.
4504 ObjectNameBuffer - Dir. name of the object to create.
4506 PhysicalDeviceObject - Pointer to the physical (class) device object for
4507 this logical unit or NULL if this is it.
4509 DeviceObject - Pointer to the device object pointer we will return.
4511 InitializationData - Pointer to the init data created by the device-specific driver.
4520 STRING ntNameString
;
4521 UNICODE_STRING ntUnicodeString
;
4523 PDEVICE_OBJECT deviceObject
= NULL
;
4525 *DeviceObject
= NULL
;
4528 "ScsiClassCreateDeviceObject: Create device object %s\n",
4531 RtlInitString(&ntNameString
,
4534 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4538 if (!NT_SUCCESS(status
)) {
4541 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4544 ntUnicodeString
.Buffer
= NULL
;
4548 status
= IoCreateDevice(DriverObject
,
4549 InitializationData
->DeviceExtensionSize
,
4551 InitializationData
->DeviceType
,
4552 InitializationData
->DeviceCharacteristics
,
4557 if (!NT_SUCCESS(status
)) {
4560 "CreateDiskDeviceObjects: Can not create device object %s\n",
4565 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4568 // Fill in entry points
4571 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4572 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4573 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4574 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4575 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4576 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4577 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4579 deviceExtension
->MediaChangeCount
= 0;
4582 // If a pointer to the physical device object was passed in then use
4583 // that. If the value was NULL, then this is the physical device so
4584 // use the pointer to the device we just created.
4587 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4588 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4590 deviceExtension
->PhysicalDevice
= deviceObject
;
4594 *DeviceObject
= deviceObject
;
4596 RtlFreeUnicodeString(&ntUnicodeString
);
4599 // Indicate the ntUnicodeString is free.
4602 ntUnicodeString
.Buffer
= NULL
;
4610 ScsiClassClaimDevice(
4611 IN PDEVICE_OBJECT PortDeviceObject
,
4612 IN PSCSI_INQUIRY_DATA LunInfo
,
4614 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4618 Routine Description:
4620 This function claims a device in the port driver. The port driver object
4621 is updated with the correct driver object if the device is successfully
4626 PortDeviceObject - Supplies the base port device object.
4628 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4630 Release - Indicates the logical unit should be released rather than claimed.
4632 NewPortDeviceObject - Returns the updated port device object to be used
4633 for all future accesses.
4637 Returns a status indicating success or failure of the operation.
4642 IO_STATUS_BLOCK ioStatus
;
4644 PIO_STACK_LOCATION irpStack
;
4647 SCSI_REQUEST_BLOCK srb
;
4651 if (NewPortDeviceObject
!= NULL
) {
4652 *NewPortDeviceObject
= NULL
;
4656 // Clear the SRB fields.
4659 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4662 // Write length to SRB.
4665 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4668 // Set SCSI bus address.
4671 srb
.PathId
= LunInfo
->PathId
;
4672 srb
.TargetId
= LunInfo
->TargetId
;
4673 srb
.Lun
= LunInfo
->Lun
;
4675 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4676 SRB_FUNCTION_CLAIM_DEVICE
;
4679 // Set the event object to the unsignaled state.
4680 // It will be used to signal request completion.
4683 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4686 // Build synchronous request with no transfer.
4689 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4701 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4702 return STATUS_INSUFFICIENT_RESOURCES
;
4705 irpStack
= IoGetNextIrpStackLocation(irp
);
4708 // Save SRB address in next stack for port driver.
4711 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4714 // Set up IRP Address.
4717 srb
.OriginalRequest
= irp
;
4720 // Call the port driver with the request and wait for it to complete.
4723 status
= IoCallDriver(PortDeviceObject
, irp
);
4724 if (status
== STATUS_PENDING
) {
4726 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4727 status
= ioStatus
.Status
;
4731 // If this is a release request, then just decrement the reference count
4732 // and return. The status does not matter.
4737 ObDereferenceObject(PortDeviceObject
);
4738 return STATUS_SUCCESS
;
4741 if (!NT_SUCCESS(status
)) {
4745 ASSERT(srb
.DataBuffer
!= NULL
);
4748 // Reference the new port driver object so that it will not go away while
4749 // it is being used.
4752 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4757 if (!NT_SUCCESS(status
)) {
4763 // Return the new port device object pointer.
4766 if (NewPortDeviceObject
!= NULL
) {
4767 *NewPortDeviceObject
= srb
.DataBuffer
;
4776 ScsiClassInternalIoControl (
4777 IN PDEVICE_OBJECT DeviceObject
,
4783 Routine Description:
4785 This routine passes internal device controls to the port driver.
4786 Internal device controls are used by higher level class drivers to
4787 send scsi requests to a device that are not normally sent by a generic
4790 The path ID, target ID and logical unit ID are set in the srb so the
4791 higher level driver does not have to figure out what values are actually
4796 DeviceObject - Supplies a pointer to the device object for this request.
4798 Irp - Supplies the Irp making the request.
4802 Returns back a STATUS_PENDING or a completion status.
4806 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4807 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4808 PSCSI_REQUEST_BLOCK srb
;
4811 // Get a pointer to the SRB.
4814 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4817 // Set SCSI bus address.
4820 srb
->PathId
= deviceExtension
->PathId
;
4821 srb
->TargetId
= deviceExtension
->TargetId
;
4822 srb
->Lun
= deviceExtension
->Lun
;
4825 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4826 // zero; however, some target controllers ignore the logical unit number
4827 // in the INDENTIFY message and only look at the logical unit number field
4831 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4834 // Set the parameters in the next stack location.
4837 irpStack
= IoGetNextIrpStackLocation(Irp
);
4839 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4840 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4841 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4843 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4844 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4850 IN PDEVICE_OBJECT DeviceObject
,
4857 Routine Description:
4859 This routine is called when an internal device control I/O request
4860 has completed. It marks the IRP pending if necessary and returns the
4861 status of the request.
4865 DeviceObject - Target device object.
4867 Irp - Completed request.
4873 Returns the status of the completed request.
4878 UNREFERENCED_PARAMETER(Context
);
4879 UNREFERENCED_PARAMETER(DeviceObject
);
4882 // If pending is returned for this Irp then mark current stack
4886 if (Irp
->PendingReturned
) {
4888 IoMarkIrpPending( Irp
);
4891 return Irp
->IoStatus
.Status
;
4897 ScsiClassInitializeSrbLookasideList(
4898 IN PDEVICE_EXTENSION DeviceExtension
,
4899 IN ULONG NumberElements
4904 Routine Description:
4906 This routine sets up a lookaside listhead for srbs.
4910 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4912 NumberElements - Supplies the maximum depth of the lookaside list.
4922 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4925 NonPagedPoolMustSucceed
,
4926 SCSI_REQUEST_BLOCK_SIZE
,
4928 (USHORT
)NumberElements
);
4935 ScsiClassQueryTimeOutRegistryValue(
4936 IN PUNICODE_STRING RegistryPath
4941 Routine Description:
4943 This routine determines whether a reg key for a user-specified timeout value exists.
4947 RegistryPath - Pointer to the hardware reg. entry describing the key.
4951 New default timeout for a class of devices.
4957 // Find the appropriate reg. key
4960 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4967 if (!RegistryPath
) {
4971 parameters
= ExAllocatePool(NonPagedPool
,
4972 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4978 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4979 path
= ExAllocatePool(NonPagedPool
, size
);
4982 ExFreePool(parameters
);
4986 RtlZeroMemory(path
,size
);
4987 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
4991 // Check for the Timeout value.
4994 RtlZeroMemory(parameters
,
4995 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
4997 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
4998 parameters
[0].Name
= L
"TimeOutValue";
4999 parameters
[0].EntryContext
= &timeOut
;
5000 parameters
[0].DefaultType
= REG_DWORD
;
5001 parameters
[0].DefaultData
= &zero
;
5002 parameters
[0].DefaultLength
= sizeof(ULONG
);
5004 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
5010 if (!(NT_SUCCESS(status
))) {
5014 ExFreePool(parameters
);
5018 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
5028 ScsiClassCheckVerifyComplete(
5029 IN PDEVICE_OBJECT DeviceObject
,
5036 Routine Description:
5038 This routine executes when the port driver has completed a check verify
5039 ioctl. It will set the status of the master Irp, copy the media change
5040 count and complete the request.
5044 DeviceObject - Supplies the device object which represents the logical
5047 Irp - Supplies the Irp which has completed.
5058 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5059 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5060 PDEVICE_EXTENSION physicalExtension
=
5061 deviceExtension
->PhysicalDevice
->DeviceExtension
;
5064 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
5067 // Copy the media change count and status
5070 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
5071 physicalExtension
->MediaChangeCount
;
5073 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
5074 "device %d is %d\n",
5075 physicalExtension
->DeviceNumber
,
5076 physicalExtension
->MediaChangeCount
));
5078 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
5079 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
5081 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
5085 return STATUS_MORE_PROCESSING_REQUIRED
;
5090 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
5094 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
5095 PKEVENT Event
= Irp
->UserEvent
;
5098 *IoStatusBlock
= Irp
->IoStatus
;
5099 Irp
->UserIosb
= NULL
;
5100 Irp
->UserEvent
= NULL
;
5104 Mdl
= Irp
->MdlAddress
;
5106 // if necessary - unlock pages
5107 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
5108 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
5117 // free irp and set event to unsignaled state
5119 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
5121 return STATUS_MORE_PROCESSING_REQUIRED
;