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
{
144 PDEVICE_OBJECT LowerDevice
;
145 } CLASS_DEVICE_INFO
, *PCLASS_DEVICE_INFO
;
147 typedef struct _CLASS_DRIVER_EXTENSION
{
149 UNICODE_STRING RegistryPath
;
150 CLASS_INIT_DATA InitializationData
;
151 } CLASS_DRIVER_EXTENSION
, *PCLASS_DRIVER_EXTENSION
;
155 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
158 UNICODE_STRING DriveLetterU
;
161 DriveLetterU
.Buffer
= Buffer1
;
162 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
164 /* Delete the symbolic link to PhysicalDriveX */
165 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DeviceInfo
->DriveNumber
) * sizeof(WCHAR
);
166 IoDeleteSymbolicLink(&DriveLetterU
);
168 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
170 for (Index
= 0; Index
< sizeof(ULONG
) * 8; Index
++)
172 if (DeviceInfo
->Partitions
& (1 << Index
))
174 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
175 IoDeleteSymbolicLink(&DriveLetterU
);
176 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
183 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
187 UNICODE_STRING DriveLetterU
, PartitionU
;
189 ULONG Index
, PartitionNumber
, DeviceNumber
, DriveNumber
;
190 OBJECT_ATTRIBUTES ObjectAttributes
;
191 IO_STATUS_BLOCK Iosb
;
192 HANDLE PartitionHandle
;
194 /* We assume this device does not current have a drive letter */
200 DriveLetterU
.Buffer
= Buffer1
;
201 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
202 PartitionU
.Buffer
= Buffer2
;
203 PartitionU
.MaximumLength
= sizeof(Buffer2
);
205 /* Determine the correct disk number */
208 /* Check that the disk exists */
209 if (DeviceInfo
->DeviceType
== FILE_DEVICE_DISK
)
211 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\HardDisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
213 else if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
215 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\CdRom%d", DeviceNumber
) * sizeof(WCHAR
);
218 InitializeObjectAttributes(&ObjectAttributes
,
220 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
223 Status
= ZwOpenFile(&PartitionHandle
,
224 FILE_READ_ATTRIBUTES
,
229 if (!NT_SUCCESS(Status
))
231 /* Return the last one that worked */
236 ZwClose(PartitionHandle
);
239 } while (Status
== STATUS_SUCCESS
);
241 /* Determine the correct drive number */
244 /* Check that the drive exists */
245 if (DeviceInfo
->DeviceType
== FILE_DEVICE_DISK
)
247 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
249 else if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
251 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\%C:", ('C' + DriveNumber
)) * sizeof(WCHAR
);
253 InitializeObjectAttributes(&ObjectAttributes
,
255 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
258 Status
= ZwOpenFile(&PartitionHandle
,
259 FILE_READ_ATTRIBUTES
,
264 if (NT_SUCCESS(Status
))
266 ZwClose(PartitionHandle
);
269 } while (Status
== STATUS_SUCCESS
);
271 if (DeviceInfo
->DeviceType
== FILE_DEVICE_DISK
)
273 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
274 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
276 else if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
278 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\CdRom%d", DeviceNumber
) * sizeof(WCHAR
);
279 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + DriveNumber
)) * sizeof(WCHAR
);
282 /* Create the symbolic link to PhysicalDriveX */
283 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
284 if (!NT_SUCCESS(Status
))
286 /* Failed to create symbolic link */
287 DbgPrint("Failed to create symbolic link %wZ -> %wZ with %lx\n", &PartitionU
, &DriveLetterU
, Status
);
291 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
293 DeviceInfo
->DeviceNumber
= DeviceNumber
;
294 DeviceInfo
->DriveNumber
= DriveNumber
;
296 if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
298 /* done for cdroms */
299 return STATUS_SUCCESS
;
304 /* Check that the disk exists */
305 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", DeviceNumber
, PartitionNumber
) * sizeof(WCHAR
);
306 InitializeObjectAttributes(&ObjectAttributes
,
308 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
311 Status
= ZwOpenFile(&PartitionHandle
,
312 FILE_READ_ATTRIBUTES
,
317 if (!NT_SUCCESS(Status
))
321 ZwClose(PartitionHandle
);
323 /* Assign it a drive letter */
326 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
328 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
331 } while (Status
!= STATUS_SUCCESS
);
333 DeviceInfo
->Partitions
|= (1 << (Index
- 1));
335 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
340 return STATUS_SUCCESS
;
346 IN PDEVICE_OBJECT DeviceObject
,
349 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
351 if (IrpSp
->MinorFunction
== IRP_MN_START_DEVICE
)
353 IoSkipCurrentIrpStackLocation(Irp
);
354 return STATUS_SUCCESS
;
356 else if (IrpSp
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
358 PCLASS_DEVICE_INFO DeviceInfo
= DeviceObject
->DeviceExtension
;
360 ScsiClassRemoveDriveLetter(DeviceInfo
);
362 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
363 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
365 IoDetachDevice(DeviceInfo
->LowerDevice
);
366 IoDeleteDevice(DeviceObject
);
367 return STATUS_SUCCESS
;
371 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
372 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
373 return STATUS_NOT_SUPPORTED
;
380 IN PDRIVER_OBJECT DriverObject
,
381 IN PDEVICE_OBJECT PhysicalDeviceObject
)
383 PCLASS_DRIVER_EXTENSION DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
384 PCLASS_DEVICE_INFO DeviceInfo
;
385 PDEVICE_OBJECT DeviceObject
;
388 if (DriverExtension
->InitializationData
.ClassFindDevices(DriverObject
, &DriverExtension
->RegistryPath
, &DriverExtension
->InitializationData
,
389 PhysicalDeviceObject
, DriverExtension
->PortNumber
))
391 /* Create a device object */
392 Status
= IoCreateDevice(DriverObject
,
393 sizeof(CLASS_DEVICE_INFO
),
395 DriverExtension
->InitializationData
.DeviceType
,
399 if (!NT_SUCCESS(Status
))
404 DeviceInfo
= DeviceObject
->DeviceExtension
;
405 RtlZeroMemory(DeviceInfo
, sizeof(CLASS_DEVICE_INFO
));
407 /* Attach it to the PDO */
408 DeviceInfo
->LowerDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
409 DeviceInfo
->DeviceType
= DriverExtension
->InitializationData
.DeviceType
;
411 /* Check that the kernel has already assigned drive letters */
412 if (KeLoaderBlock
== NULL
)
414 /* Assign a drive letter */
415 ScsiClassAssignDriveLetter(DeviceInfo
);
419 /* The kernel will handle it */
422 /* Move to the next port number */
423 DriverExtension
->PortNumber
++;
427 /* Failed to find device */
428 DbgPrint("FAILED TO FIND DEVICE!\n");
431 return STATUS_SUCCESS
;
433 /* ---- End hack ---- */
442 IN PCLASS_INIT_DATA InitializationData
449 This routine is called by a class driver during its
450 DriverEntry routine to initialize the driver.
454 Argument1 - Driver Object.
455 Argument2 - Registry Path.
456 InitializationData - Device-specific driver's initialization data.
460 A valid return code for a DriverEntry routine.
467 PDRIVER_OBJECT DriverObject
= Argument1
;
468 PDEVICE_OBJECT portDeviceObject
;
470 STRING deviceNameString
;
471 UNICODE_STRING unicodeDeviceName
;
472 PFILE_OBJECT fileObject
;
473 CCHAR deviceNameBuffer
[256];
474 /* BOOLEAN deviceFound = FALSE; See note at the end */
475 PCLASS_DRIVER_EXTENSION DriverExtension
;
476 PUNICODE_STRING RegistryPath
= Argument2
;
478 DebugPrint((3,"\n\nSCSI Class Driver\n"));
481 // Validate the length of this structure. This is effectively a
485 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
487 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
488 return (ULONG
) STATUS_REVISION_MISMATCH
;
492 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
493 // are not required entry points.
496 if ((!InitializationData
->ClassFindDevices
) ||
497 (!InitializationData
->ClassDeviceControl
) ||
498 (!((InitializationData
->ClassReadWriteVerification
) ||
499 (InitializationData
->ClassStartIo
)))) {
502 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
504 return (ULONG
) STATUS_REVISION_MISMATCH
;
507 status
= IoAllocateDriverObjectExtension(DriverObject
,
509 sizeof(CLASS_DRIVER_EXTENSION
),
510 (PVOID
*)&DriverExtension
);
511 if (!NT_SUCCESS(status
))
514 RtlCopyMemory(&DriverExtension
->InitializationData
, InitializationData
, sizeof(CLASS_INIT_DATA
));
515 DriverExtension
->PortNumber
= 0;
517 DriverExtension
->RegistryPath
.Buffer
= ExAllocatePool(PagedPool
, RegistryPath
->MaximumLength
);
518 if (!DriverExtension
->RegistryPath
.Buffer
)
519 return STATUS_NO_MEMORY
;
521 DriverExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
522 DriverExtension
->RegistryPath
.MaximumLength
= RegistryPath
->MaximumLength
;
524 RtlCopyMemory(DriverExtension
->RegistryPath
.Buffer
,
525 RegistryPath
->Buffer
,
526 RegistryPath
->Length
);
529 // Update driver object with entry points.
532 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
533 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
534 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
535 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
536 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ScsiClassPlugPlay
;
537 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
538 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
539 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
540 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
541 DriverObject
->DriverExtension
->AddDevice
= ScsiClassAddDevice
;
543 if (InitializationData
->ClassStartIo
) {
544 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
548 // Open port driver controller device objects by name.
553 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", DriverExtension
->PortNumber
);
555 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
557 RtlInitString(&deviceNameString
, deviceNameBuffer
);
559 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
563 if (!NT_SUCCESS(status
)){
567 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
568 FILE_READ_ATTRIBUTES
,
572 if (NT_SUCCESS(status
)) {
575 // Call the device-specific driver's FindDevice routine.
578 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
579 portDeviceObject
, DriverExtension
->PortNumber
)) {
581 /* deviceFound = TRUE; See note at the end */
586 // Check next SCSI adapter.
589 DriverExtension
->PortNumber
++;
591 } while(NT_SUCCESS(status
));
593 /* We don't want to fail init just because we don't have devices right now */
594 return STATUS_SUCCESS
; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
600 ScsiClassCreateClose(
601 IN PDEVICE_OBJECT DeviceObject
,
609 SCSI class driver create and close routine. This is called by the I/O system
610 when the device is opened or closed.
614 DriverObject - Pointer to driver object created by system.
620 Device-specific drivers return value or STATUS_SUCCESS.
625 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
628 // Invoke the device-specific routine, if one exists. Otherwise complete
632 if (deviceExtension
->ClassCreateClose
) {
634 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
637 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
639 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
640 return(STATUS_SUCCESS
);
649 IN PDEVICE_OBJECT DeviceObject
,
657 This is the system entry point for read and write requests. The device-specific handler is invoked
658 to perform any validation necessary. The number of bytes in the request are
659 checked against the maximum byte counts that the adapter supports and requests are broken up into
660 smaller sizes if necessary.
674 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
675 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
677 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
678 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
681 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
682 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
685 // if DO_VERIFY_VOLUME bit is set
686 // in device object flags, fail request.
689 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
691 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
692 Irp
->IoStatus
.Information
= 0;
694 IoCompleteRequest(Irp
, 0);
695 return STATUS_VERIFY_REQUIRED
;
699 // Invoke the device specific routine to do whatever it needs to verify
703 ASSERT(deviceExtension
->ClassReadWriteVerification
);
705 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
707 if (!NT_SUCCESS(status
)) {
710 // It is up to the device specific driver to set the Irp status.
713 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
715 } else if (status
== STATUS_PENDING
) {
717 IoMarkIrpPending(Irp
);
718 return STATUS_PENDING
;
722 // Check for a zero length IO, as several macros will turn this into
723 // seemingly a 0xffffffff length request.
726 if (transferByteCount
== 0) {
727 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
728 Irp
->IoStatus
.Information
= 0;
729 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
730 return STATUS_SUCCESS
;
734 if (deviceExtension
->ClassStartIo
) {
736 IoMarkIrpPending(Irp
);
738 IoStartPacket(DeviceObject
,
743 return STATUS_PENDING
;
747 // Mark IRP with status pending.
750 IoMarkIrpPending(Irp
);
753 // Add partition byte offset to make starting byte relative to
754 // beginning of disk. In addition, add in skew for DM Driver, if any.
757 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
758 deviceExtension
->DMByteSkew
);
761 // Calculate number of pages in this transfer.
764 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
765 currentIrpStack
->Parameters
.Read
.Length
);
768 // Check if request length is greater than the maximum number of
769 // bytes that the hardware can transfer.
772 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
773 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
775 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
776 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
777 maximumTransferLength
));
778 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
779 currentIrpStack
->Parameters
.Read
.Length
));
782 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
784 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
785 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
789 // Check that maximum transfer size is not zero.
792 if (maximumTransferLength
== 0) {
793 maximumTransferLength
= PAGE_SIZE
;
797 // Mark IRP with status pending.
800 IoMarkIrpPending(Irp
);
803 // Request greater than port driver maximum.
804 // Break up into smaller routines.
807 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
810 return STATUS_PENDING
;
814 // Build SRB and CDB for this IRP.
817 ScsiClassBuildRequest(DeviceObject
, Irp
);
820 // Return the results of the call to the port driver.
823 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
825 } // end ScsiClassReadWrite()
830 ScsiClassGetCapabilities(
831 IN PDEVICE_OBJECT PortDeviceObject
,
832 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
839 This routine builds and sends a request to the port driver to
840 get a pointer to a structure that describes the adapter's
841 capabilities/limitations. This routine is sychronous.
845 PortDeviceObject - Port driver device object representing the HBA.
847 PortCapabilities - Location to store pointer to capabilities structure.
851 Nt status indicating the results of the operation.
855 This routine should only be called at initialization time.
861 IO_STATUS_BLOCK ioStatus
;
868 // Create notification event object to be used to signal the
869 // request completion.
872 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
875 // Build the synchronous request to be sent to the port driver
876 // to perform the request.
879 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
890 return STATUS_INSUFFICIENT_RESOURCES
;
894 // Pass request to port driver and wait for request to complete.
897 status
= IoCallDriver(PortDeviceObject
, irp
);
899 if (status
== STATUS_PENDING
) {
900 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
901 return(ioStatus
.Status
);
906 } // end ScsiClassGetCapabilities()
911 ScsiClassGetInquiryData(
912 IN PDEVICE_OBJECT PortDeviceObject
,
913 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
920 This routine sends a request to a port driver to return
921 configuration information. Space for the information is
922 allocated by this routine. The caller is responsible for
923 freeing the configuration information. This routine is
928 PortDeviceObject - Port driver device object representing the HBA.
930 ConfigInfo - Returns a pointer to the configuration information.
934 Nt status indicating the results of the operation.
938 This routine should be called only at initialization time.
944 IO_STATUS_BLOCK ioStatus
;
947 PSCSI_ADAPTER_BUS_INFO buffer
;
951 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
952 *ConfigInfo
= buffer
;
954 if (buffer
== NULL
) {
955 return(STATUS_INSUFFICIENT_RESOURCES
);
959 // Create notification event object to be used to signal the inquiry
960 // request completion.
963 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
966 // Build the synchronous request to be sent to the port driver
967 // to perform the inquiries.
970 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
981 return(STATUS_INSUFFICIENT_RESOURCES
);
985 // Pass request to port driver and wait for request to complete.
988 status
= IoCallDriver(PortDeviceObject
, irp
);
990 if (status
== STATUS_PENDING
) {
991 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
992 status
= ioStatus
.Status
;
995 if (!NT_SUCCESS(status
)) {
998 // Free the buffer on an error.
1008 } // end ScsiClassGetInquiryData()
1013 ScsiClassReadDriveCapacity(
1014 IN PDEVICE_OBJECT DeviceObject
1019 Routine Description:
1021 This routine sends a READ CAPACITY to the requested device, updates
1022 the geometry information in the device object and returns
1023 when it is complete. This routine is synchronous.
1027 DeviceObject - Supplies a pointer to the device object that represents
1028 the device whose capacity is to be read.
1036 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1040 PREAD_CAPACITY_DATA readCapacityBuffer
;
1041 SCSI_REQUEST_BLOCK srb
;
1045 // Allocate read capacity buffer from nonpaged pool.
1048 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
1049 sizeof(READ_CAPACITY_DATA
));
1051 if (!readCapacityBuffer
) {
1052 return(STATUS_INSUFFICIENT_RESOURCES
);
1055 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1058 // Build the read capacity CDB.
1062 cdb
= (PCDB
)srb
.Cdb
;
1065 // Set timeout value from device extension.
1068 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1070 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1074 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
1077 sizeof(READ_CAPACITY_DATA
),
1080 if (NT_SUCCESS(status
)) {
1083 // Copy sector size from read capacity buffer to device extension
1084 // in reverse byte order.
1087 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
1088 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
1090 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
1091 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
1093 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
1094 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
1096 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
1097 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
1100 // Copy last sector in reverse byte order.
1103 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
1104 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
1106 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
1107 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
1109 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
1110 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
1112 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
1113 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
1116 // Calculate sector to byte shift.
1119 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
1121 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
1122 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
1124 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
1128 // Calculate media capacity in bytes.
1131 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
1134 // Calculate number of cylinders.
1137 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
1139 deviceExtension
->PartitionLength
.QuadPart
=
1140 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
1142 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1145 // This device supports removable media.
1148 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1153 // Assume media type is fixed disk.
1156 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1160 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
1163 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
1166 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
1169 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
1172 if (status
== STATUS_VERIFY_REQUIRED
) {
1175 // Routine ScsiClassSendSrbSynchronous does not retry
1176 // requests returned with this status.
1177 // Read Capacities should be retried
1191 if (!NT_SUCCESS(status
)) {
1194 // If the read capacity fails, set the geometry to reasonable parameter
1195 // so things don't fail at unexpected places. Zero the geometry
1196 // except for the bytes per sector and sector shift.
1199 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
1200 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1201 deviceExtension
->SectorShift
= 9;
1202 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
1204 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1207 // This device supports removable media.
1210 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1215 // Assume media type is fixed disk.
1218 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1223 // Deallocate read capacity buffer.
1226 ExFreePool(readCapacityBuffer
);
1230 } // end ScsiClassReadDriveCapacity()
1235 ScsiClassReleaseQueue(
1236 IN PDEVICE_OBJECT DeviceObject
1241 Routine Description:
1243 This routine issues an internal device control command
1244 to the port driver to release a frozen queue. The call
1245 is issued asynchronously as ScsiClassReleaseQueue will be invoked
1246 from the IO completion DPC (and will have no context to
1247 wait for a synchronous call to complete).
1251 DeviceObject - The device object for the logical unit with
1260 PIO_STACK_LOCATION irpStack
;
1262 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1263 PCOMPLETION_CONTEXT context
;
1264 PSCSI_REQUEST_BLOCK srb
;
1268 // Allocate context from nonpaged pool.
1271 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1272 sizeof(COMPLETION_CONTEXT
));
1275 // Save the device object in the context for use by the completion
1279 context
->DeviceObject
= DeviceObject
;
1280 srb
= &context
->Srb
;
1286 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1289 // Write length to SRB.
1292 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1295 // Set up SCSI bus address.
1298 srb
->PathId
= deviceExtension
->PathId
;
1299 srb
->TargetId
= deviceExtension
->TargetId
;
1300 srb
->Lun
= deviceExtension
->Lun
;
1303 // If this device is removable then flush the queue. This will also
1307 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1309 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
1313 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
1318 // Build the asynchronous request to be sent to the port driver.
1321 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1326 // We have no better way of dealing with this at the moment
1329 KeBugCheck((ULONG
)0x0000002DL
);
1333 IoSetCompletionRoutine(irp
,
1334 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1340 irpStack
= IoGetNextIrpStackLocation(irp
);
1342 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1344 srb
->OriginalRequest
= irp
;
1347 // Store the SRB address in next stack for port driver.
1350 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1353 // Since this routine can cause outstanding requests to be completed, and
1354 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1355 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1356 // issuing the request
1359 currentIrql
= KeGetCurrentIrql();
1361 if(currentIrql
< DISPATCH_LEVEL
) {
1362 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1363 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1364 KeLowerIrql(currentIrql
);
1366 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1371 } // end ScsiClassReleaseQueue()
1377 IN PDEVICE_OBJECT DeviceObject
1382 Routine Description:
1384 Send command to SCSI unit to start or power up.
1385 Because this command is issued asynchronounsly, that is, without
1386 waiting on it to complete, the IMMEDIATE flag is not set. This
1387 means that the CDB will not return until the drive has powered up.
1388 This should keep subsequent requests from being submitted to the
1389 device before it has completely spun up.
1390 This routine is called from the InterpretSense routine, when a
1391 request sense returns data indicating that a drive must be
1396 DeviceObject - The device object for the logical unit with
1405 PIO_STACK_LOCATION irpStack
;
1407 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1408 PSCSI_REQUEST_BLOCK srb
;
1409 PCOMPLETION_CONTEXT context
;
1413 // Allocate Srb from nonpaged pool.
1416 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1417 sizeof(COMPLETION_CONTEXT
));
1420 // Save the device object in the context for use by the completion
1424 context
->DeviceObject
= DeviceObject
;
1425 srb
= &context
->Srb
;
1431 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1434 // Write length to SRB.
1437 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1440 // Set up SCSI bus address.
1443 srb
->PathId
= deviceExtension
->PathId
;
1444 srb
->TargetId
= deviceExtension
->TargetId
;
1445 srb
->Lun
= deviceExtension
->Lun
;
1447 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1450 // Set timeout value large enough for drive to spin up.
1453 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1456 // Set the transfer length.
1459 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1462 // Build the start unit CDB.
1466 cdb
= (PCDB
)srb
->Cdb
;
1468 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1469 cdb
->START_STOP
.Start
= 1;
1470 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1473 // Build the asynchronous request to be sent to the port driver.
1474 // Since this routine is called from a DPC the IRP should always be
1478 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1479 IoSetCompletionRoutine(irp
,
1480 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1486 irpStack
= IoGetNextIrpStackLocation(irp
);
1487 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1488 srb
->OriginalRequest
= irp
;
1491 // Store the SRB address in next stack for port driver.
1494 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1497 // Call the port driver with the IRP.
1500 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1504 } // end StartUnit()
1509 ScsiClassAsynchronousCompletion(
1510 PDEVICE_OBJECT DeviceObject
,
1516 Routine Description:
1518 This routine is called when an asynchronous I/O request
1519 which was issused by the class driver completes. Examples of such requests
1520 are release queue or START UNIT. This routine releases the queue if
1521 necessary. It then frees the context and the IRP.
1525 DeviceObject - The device object for the logical unit; however since this
1526 is the top stack location the value is NULL.
1528 Irp - Supplies a pointer to the Irp to be processed.
1530 Context - Supplies the context to be used to process this request.
1539 PCOMPLETION_CONTEXT context
= Context
;
1540 PSCSI_REQUEST_BLOCK srb
;
1542 srb
= &context
->Srb
;
1545 // If this is an execute srb, then check the return status and make sure.
1546 // the queue is not frozen.
1549 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1552 // Check for a frozen queue.
1555 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1558 // Unfreeze the queue getting the device object from the context.
1561 ScsiClassReleaseQueue(context
->DeviceObject
);
1566 // Free the context and the Irp.
1569 if (Irp
->MdlAddress
!= NULL
) {
1570 MmUnlockPages(Irp
->MdlAddress
);
1571 IoFreeMdl(Irp
->MdlAddress
);
1573 Irp
->MdlAddress
= NULL
;
1576 ExFreePool(context
);
1580 // Indicate the I/O system should stop processing the Irp completion.
1583 return STATUS_MORE_PROCESSING_REQUIRED
;
1585 } // ScsiClassAsynchronousCompletion()
1590 ScsiClassSplitRequest(
1591 IN PDEVICE_OBJECT DeviceObject
,
1593 IN ULONG MaximumBytes
1598 Routine Description:
1600 Break request into smaller requests. Each new request will be the
1601 maximum transfer size that the port driver can handle or if it
1602 is the final request, it may be the residual size.
1604 The number of IRPs required to process this request is written in the
1605 current stack of the original IRP. Then as each new IRP completes
1606 the count in the original IRP is decremented. When the count goes to
1607 zero, the original IRP is completed.
1611 DeviceObject - Pointer to the class device object to be addressed.
1613 Irp - Pointer to Irp the orginal request.
1622 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1623 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1624 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1625 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1626 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1627 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1628 ULONG dataLength
= MaximumBytes
;
1629 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1631 PSCSI_REQUEST_BLOCK srb
;
1633 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1634 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1637 // If all partial transfers complete successfully then the status and
1638 // bytes transferred are already set up. Failing a partial-transfer IRP
1639 // will set status to error and bytes transferred to 0 during
1640 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1641 // asynchronous partial transfers. This is an optimization for the
1645 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1646 Irp
->IoStatus
.Information
= transferByteCount
;
1649 // Save number of IRPs to complete count on current stack
1653 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1655 for (i
= 0; i
< irpCount
; i
++) {
1658 PIO_STACK_LOCATION newIrpStack
;
1661 // Allocate new IRP.
1664 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1666 if (newIrp
== NULL
) {
1668 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1671 // If an Irp can't be allocated then the orginal request cannot
1672 // be executed. If this is the first request then just fail the
1673 // orginal request; otherwise just return. When the pending
1674 // requests complete, they will complete the original request.
1675 // In either case set the IRP status to failure.
1678 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1679 Irp
->IoStatus
.Information
= 0;
1682 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1688 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1691 // Write MDL address to new IRP. In the port driver the SRB data
1692 // buffer field is used as an offset into the MDL, so the same MDL
1693 // can be used for each partial transfer. This saves having to build
1694 // a new MDL for each partial transfer.
1697 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1700 // At this point there is no current stack. IoSetNextIrpStackLocation
1701 // will make the first stack location the current stack so that the
1702 // SRB address can be written there.
1705 IoSetNextIrpStackLocation(newIrp
);
1706 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1708 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1709 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1710 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1711 newIrpStack
->DeviceObject
= DeviceObject
;
1714 // Build SRB and CDB.
1717 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1720 // Adjust SRB for this partial transfer.
1723 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1725 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1726 srb
->DataBuffer
= dataBuffer
;
1729 // Write original IRP address to new IRP.
1732 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1735 // Set the completion routine to ScsiClassIoCompleteAssociated.
1738 IoSetCompletionRoutine(newIrp
,
1739 ScsiClassIoCompleteAssociated
,
1746 // Call port driver with new request.
1749 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1752 // Set up for next request.
1755 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1757 transferByteCount
-= MaximumBytes
;
1759 if (transferByteCount
> MaximumBytes
) {
1761 dataLength
= MaximumBytes
;
1765 dataLength
= transferByteCount
;
1769 // Adjust disk byte offset.
1772 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1777 } // end ScsiClassSplitRequest()
1782 ScsiClassIoComplete(
1783 IN PDEVICE_OBJECT DeviceObject
,
1790 Routine Description:
1792 This routine executes when the port driver has completed a request.
1793 It looks at the SRB status in the completing SRB and if not success
1794 it checks for valid request sense buffer information. If valid, the
1795 info is used to update status with more precise message of type of
1796 error. This routine deallocates the SRB.
1800 DeviceObject - Supplies the device object which represents the logical
1803 Irp - Supplies the Irp which has completed.
1805 Context - Supplies a pointer to the SRB.
1814 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1815 PSCSI_REQUEST_BLOCK srb
= Context
;
1816 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1821 // Check SRB status for success of completing request.
1824 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1826 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1829 // Release the queue if it is frozen.
1832 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1833 ScsiClassReleaseQueue(DeviceObject
);
1836 retry
= ScsiClassInterpretSenseInfo(
1839 irpStack
->MajorFunction
,
1840 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1841 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1845 // If the status is verified required and the this request
1846 // should bypass verify required then retry the request.
1849 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1850 status
== STATUS_VERIFY_REQUIRED
) {
1852 status
= STATUS_IO_DEVICE_ERROR
;
1856 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1862 DebugPrint((1, "Retry request %lx\n", Irp
));
1863 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1864 return STATUS_MORE_PROCESSING_REQUIRED
;
1869 // Set status for successful request.
1872 status
= STATUS_SUCCESS
;
1874 } // end if (SRB_STATUS(srb->SrbStatus) ...
1877 // Return SRB to list.
1880 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1884 // Set status in completing IRP.
1887 Irp
->IoStatus
.Status
= status
;
1888 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1889 ASSERT(Irp
->IoStatus
.Information
);
1893 // Set the hard error if necessary.
1896 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1899 // Store DeviceObject for filesystem, and clear
1900 // in IoStatus.Information field.
1903 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1904 Irp
->IoStatus
.Information
= 0;
1908 // If pending has be returned for this irp then mark the current stack as
1912 if (Irp
->PendingReturned
) {
1913 IoMarkIrpPending(Irp
);
1916 if (deviceExtension
->ClassStartIo
) {
1917 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1918 IoStartNextPacket(DeviceObject
, FALSE
);
1924 } // end ScsiClassIoComplete()
1929 ScsiClassIoCompleteAssociated(
1930 IN PDEVICE_OBJECT DeviceObject
,
1937 Routine Description:
1939 This routine executes when the port driver has completed a request.
1940 It looks at the SRB status in the completing SRB and if not success
1941 it checks for valid request sense buffer information. If valid, the
1942 info is used to update status with more precise message of type of
1943 error. This routine deallocates the SRB. This routine is used for
1944 requests which were build by split request. After it has processed
1945 the request it decrements the Irp count in the master Irp. If the
1946 count goes to zero then the master Irp is completed.
1950 DeviceObject - Supplies the device object which represents the logical
1953 Irp - Supplies the Irp which has completed.
1955 Context - Supplies a pointer to the SRB.
1964 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1965 PSCSI_REQUEST_BLOCK srb
= Context
;
1966 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1967 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1973 // Check SRB status for success of completing request.
1976 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1978 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1981 // Release the queue if it is frozen.
1984 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1985 ScsiClassReleaseQueue(DeviceObject
);
1988 retry
= ScsiClassInterpretSenseInfo(
1991 irpStack
->MajorFunction
,
1992 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1993 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1997 // If the status is verified required and the this request
1998 // should bypass verify required then retry the request.
2001 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2002 status
== STATUS_VERIFY_REQUIRED
) {
2004 status
= STATUS_IO_DEVICE_ERROR
;
2008 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
2011 // Retry request. If the class driver has supplied a StartIo,
2012 // call it directly for retries.
2015 DebugPrint((1, "Retry request %lx\n", Irp
));
2018 if (!deviceExtension->ClassStartIo) {
2019 RetryRequest(DeviceObject, Irp, srb, TRUE);
2021 deviceExtension->ClassStartIo(DeviceObject, Irp);
2025 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
2027 return STATUS_MORE_PROCESSING_REQUIRED
;
2035 // Set status for successful request.
2038 status
= STATUS_SUCCESS
;
2040 } // end if (SRB_STATUS(srb->SrbStatus) ...
2043 // Return SRB to list.
2046 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
2050 // Set status in completing IRP.
2053 Irp
->IoStatus
.Status
= status
;
2055 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
2058 // Get next stack location. This original request is unused
2059 // except to keep track of the completing partial IRPs so the
2060 // stack location is valid.
2063 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
2066 // Update status only if error so that if any partial transfer
2067 // completes with error, then the original IRP will return with
2068 // error. If any of the asynchronous partial transfer IRPs fail,
2069 // with an error then the original IRP will return 0 bytes transfered.
2070 // This is an optimization for successful transfers.
2073 if (!NT_SUCCESS(status
)) {
2075 originalIrp
->IoStatus
.Status
= status
;
2076 originalIrp
->IoStatus
.Information
= 0;
2079 // Set the hard error if necessary.
2082 if (IoIsErrorUserInduced(status
)) {
2085 // Store DeviceObject for filesystem.
2088 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
2093 // Decrement and get the count of remaining IRPs.
2096 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
2098 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
2102 // Old bug could cause irp count to negative
2105 ASSERT(irpCount
>= 0);
2107 if (irpCount
== 0) {
2110 // All partial IRPs have completed.
2114 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
2117 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
2120 // If the class driver has supplied a startio, start the
2124 if (deviceExtension
->ClassStartIo
) {
2125 IoStartNextPacket(DeviceObject
, FALSE
);
2130 // Deallocate IRP and indicate the I/O system should not attempt any more
2135 return STATUS_MORE_PROCESSING_REQUIRED
;
2137 } // end ScsiClassIoCompleteAssociated()
2142 ScsiClassSendSrbSynchronous(
2143 PDEVICE_OBJECT DeviceObject
,
2144 PSCSI_REQUEST_BLOCK Srb
,
2145 PVOID BufferAddress
,
2147 BOOLEAN WriteToDevice
2152 Routine Description:
2154 This routine is called by SCSI device controls to complete an
2155 SRB and send it to the port driver synchronously (ie wait for
2156 completion). The CDB is already completed along with the SRB CDB
2157 size and request timeout value.
2161 DeviceObject - Supplies the device object which represents the logical
2164 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2166 BufferAddress - Supplies the address of the buffer.
2168 BufferLength - Supplies the length in bytes of the buffer.
2170 WriteToDevice - Indicates the data should be transfer to the device.
2174 Nt status indicating the final results of the operation.
2179 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2180 IO_STATUS_BLOCK ioStatus
;
2181 ULONG controlType
, mjFunction
;
2183 PIO_STACK_LOCATION irpStack
;
2185 PUCHAR senseInfoBuffer
;
2186 ULONG retryCount
= MAXIMUM_RETRIES
;
2189 LARGE_INTEGER dummy
;
2196 // Write length to SRB.
2199 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2202 // Set SCSI bus address.
2205 Srb
->PathId
= deviceExtension
->PathId
;
2206 Srb
->TargetId
= deviceExtension
->TargetId
;
2207 Srb
->Lun
= deviceExtension
->Lun
;
2208 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2211 // NOTICE: The SCSI-II specification indicates that this field should be
2212 // zero; however, some target controllers ignore the logical unit number
2213 // in the INDENTIFY message and only look at the logical unit number field
2217 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
2220 // Enable auto request sense.
2223 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
2226 // Sense buffer is in aligned nonpaged pool.
2229 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
2231 if (senseInfoBuffer
== NULL
) {
2234 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
2235 return(STATUS_INSUFFICIENT_RESOURCES
);
2238 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
2239 Srb
->DataBuffer
= BufferAddress
;
2242 // Start retries here.
2248 // Set the event object to the unsignaled state.
2249 // It will be used to signal request completion.
2252 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
2255 // Set controlType and Srb direction flags.
2258 if (BufferAddress
!= NULL
) {
2260 if (WriteToDevice
) {
2262 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
2263 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
2264 mjFunction
= IRP_MJ_WRITE
;
2268 controlType
= IOCTL_SCSI_EXECUTE_IN
;
2269 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
2270 mjFunction
= IRP_MJ_READ
;
2276 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
2277 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
2278 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
2282 // Build device I/O control request with data transfer.
2284 irp
= IoBuildAsynchronousFsdRequest(
2286 deviceExtension
->DeviceObject
,
2288 (BufferAddress
) ? BufferLength
: 0,
2293 ExFreePool(senseInfoBuffer
);
2294 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2295 return(STATUS_INSUFFICIENT_RESOURCES
);
2299 irp
->UserEvent
= &event
;
2302 // Disable synchronous transfer for these requests.
2305 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2308 // Set the transfer length.
2311 Srb
->DataTransferLength
= BufferLength
;
2317 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
2320 // Set completion routine
2321 IoSetCompletionRoutine(
2323 ClassCompletionRoutine
,
2330 // Get next stack location.
2333 irpStack
= IoGetNextIrpStackLocation(irp
);
2335 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2336 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2339 // Set up SRB for execute scsi request. Save SRB address in next stack
2340 // for the port driver.
2343 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2346 // Set up IRP Address.
2349 Srb
->OriginalRequest
= irp
;
2352 // Call the port driver with the request and wait for it to complete.
2355 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2357 if (status
== STATUS_PENDING
) {
2358 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2362 // Check that request completed without error.
2365 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2368 // Release the queue if it is frozen.
2371 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2372 ScsiClassReleaseQueue(DeviceObject
);
2376 // Update status and determine if request should be retried.
2379 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2383 MAXIMUM_RETRIES
- retryCount
,
2388 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2389 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2390 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2392 LARGE_INTEGER delay
;
2395 // Delay for 2 seconds.
2398 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2401 // Stall for a while to let the controller spinup.
2404 KeDelayExecutionThread(KernelMode
,
2411 // If retries are not exhausted then retry this operation.
2421 status
= STATUS_SUCCESS
;
2424 ExFreePool(senseInfoBuffer
);
2427 } // end ScsiClassSendSrbSynchronous()
2432 ScsiClassInterpretSenseInfo(
2433 IN PDEVICE_OBJECT DeviceObject
,
2434 IN PSCSI_REQUEST_BLOCK Srb
,
2435 IN UCHAR MajorFunctionCode
,
2436 IN ULONG IoDeviceCode
,
2437 IN ULONG RetryCount
,
2438 OUT NTSTATUS
*Status
2443 Routine Description:
2445 This routine interprets the data returned from the SCSI
2446 request sense. It determines the status to return in the
2447 IRP and whether this request can be retried.
2451 DeviceObject - Supplies the device object associated with this request.
2453 Srb - Supplies the scsi request block which failed.
2455 MajorFunctionCode - Supplies the function code to be used for logging.
2457 IoDeviceCode - Supplies the device code to be used for logging.
2459 Status - Returns the status for the request.
2463 BOOLEAN TRUE: Drivers should retry this request.
2464 FALSE: Drivers should not retry this request.
2469 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2470 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2471 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2472 BOOLEAN retry
= TRUE
;
2473 BOOLEAN logError
= FALSE
;
2474 ULONG badSector
= 0;
2479 PIO_ERROR_LOG_PACKET errorLogEntry
;
2486 // Check that request sense buffer is valid.
2490 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2491 for (i
= 1; i
< 12; i
++) {
2492 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2494 DebugPrint((3,"\n"));
2497 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2498 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2500 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2501 senseBuffer
->ErrorCode
));
2502 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2503 senseBuffer
->SenseKey
));
2504 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2505 senseBuffer
->AdditionalSenseCode
));
2506 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2507 senseBuffer
->AdditionalSenseCodeQualifier
));
2510 // Zero the additional sense code and additional sense code qualifier
2511 // if they were not returned by the device.
2514 readSector
= senseBuffer
->AdditionalSenseLength
+
2515 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2517 if (readSector
> Srb
->SenseInfoBufferLength
) {
2518 readSector
= Srb
->SenseInfoBufferLength
;
2521 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2522 senseBuffer
->AdditionalSenseCode
= 0;
2525 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2526 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2529 switch (senseBuffer
->SenseKey
& 0xf) {
2531 case SCSI_SENSE_NOT_READY
:
2533 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2534 *Status
= STATUS_DEVICE_NOT_READY
;
2536 switch (senseBuffer
->AdditionalSenseCode
) {
2538 case SCSI_ADSENSE_LUN_NOT_READY
:
2540 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2542 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2544 case SCSI_SENSEQ_BECOMING_READY
:
2546 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2547 " In process of becoming ready\n"));
2550 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2552 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2553 " Manual intervention required\n"));
2554 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2558 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2560 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2564 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2568 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2569 " Initializing command required\n"));
2572 // This sense code/additional sense code
2573 // combination may indicate that the device
2574 // needs to be started. Send an start unit if this
2575 // is a disk device.
2578 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2579 StartUnit(DeviceObject
);
2584 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2588 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2591 "ScsiClassInterpretSenseInfo:"
2592 " No Media in device.\n"));
2593 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2597 // signal autorun that there isn't any media in the device
2600 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2601 (!deviceExtension
->MediaChangeNoMedia
)) {
2602 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2605 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2606 "Detected No Media In Device "
2607 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2608 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2612 } // end switch (senseBuffer->AdditionalSenseCode)
2616 case SCSI_SENSE_DATA_PROTECT
:
2618 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2619 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2623 case SCSI_SENSE_MEDIUM_ERROR
:
2625 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2626 *Status
= STATUS_DEVICE_DATA_ERROR
;
2631 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2634 case SCSI_SENSE_HARDWARE_ERROR
:
2636 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2637 *Status
= STATUS_IO_DEVICE_ERROR
;
2641 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2645 case SCSI_SENSE_ILLEGAL_REQUEST
:
2647 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2648 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2650 switch (senseBuffer
->AdditionalSenseCode
) {
2652 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2653 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2657 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2658 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2659 *Status
= STATUS_NONEXISTENT_SECTOR
;
2663 case SCSI_ADSENSE_INVALID_LUN
:
2664 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2665 *Status
= STATUS_NO_SUCH_DEVICE
;
2669 case SCSI_ADSENSE_MUSIC_AREA
:
2670 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2674 case SCSI_ADSENSE_DATA_AREA
:
2675 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2679 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2680 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2684 case SCSI_ADSENSE_INVALID_CDB
:
2685 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2688 // Check if write cache enabled.
2691 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2694 // Assume FUA is not supported.
2697 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2706 } // end switch (senseBuffer->AdditionalSenseCode)
2710 case SCSI_SENSE_UNIT_ATTENTION
:
2712 switch (senseBuffer
->AdditionalSenseCode
) {
2713 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2714 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2716 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2718 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2721 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2722 "New Media Found - Setting MediaChanged event"
2723 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2724 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2729 case SCSI_ADSENSE_BUS_RESET
:
2730 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2734 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2737 } // end switch (senseBuffer->AdditionalSenseCode)
2739 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2740 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2743 // Set bit to indicate that media may have changed
2744 // and volume needs verification.
2747 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2749 *Status
= STATUS_VERIFY_REQUIRED
;
2754 *Status
= STATUS_IO_DEVICE_ERROR
;
2759 // A media change may have occured so increment the change
2760 // count for the physical device
2763 physicalExtension
->MediaChangeCount
++;
2765 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2766 "count for device %d is %d\n",
2767 physicalExtension
->DeviceNumber
,
2768 physicalExtension
->MediaChangeCount
));
2772 case SCSI_SENSE_ABORTED_COMMAND
:
2774 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2775 *Status
= STATUS_IO_DEVICE_ERROR
;
2778 case SCSI_SENSE_RECOVERED_ERROR
:
2780 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2781 *Status
= STATUS_SUCCESS
;
2786 switch(senseBuffer
->AdditionalSenseCode
) {
2787 case SCSI_ADSENSE_SEEK_ERROR
:
2788 case SCSI_ADSENSE_TRACK_ERROR
:
2789 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2792 case SCSI_ADSENSE_REC_DATA_NOECC
:
2793 case SCSI_ADSENSE_REC_DATA_ECC
:
2794 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2798 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2801 } // end switch(senseBuffer->AdditionalSenseCode)
2803 if (senseBuffer
->IncorrectLength
) {
2805 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2806 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2811 case SCSI_SENSE_NO_SENSE
:
2814 // Check other indicators.
2817 if (senseBuffer
->IncorrectLength
) {
2819 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2820 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2825 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2826 *Status
= STATUS_IO_DEVICE_ERROR
;
2834 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2835 *Status
= STATUS_IO_DEVICE_ERROR
;
2838 } // end switch (senseBuffer->SenseKey & 0xf)
2841 // Try to determine the bad sector from the inquiry data.
2844 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2845 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2846 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2848 for (index
= 0; index
< 4; index
++) {
2849 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2853 for (index
= 0; index
< 4; index
++) {
2854 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2857 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2858 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2861 // Make sure the bad sector is within the read sectors.
2864 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2865 badSector
= readSector
;
2872 // Request sense buffer not valid. No sense information
2873 // to pinpoint the error. Return general request fail.
2876 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2877 SRB_STATUS(Srb
->SrbStatus
)));
2880 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2881 case SRB_STATUS_INVALID_LUN
:
2882 case SRB_STATUS_INVALID_TARGET_ID
:
2883 case SRB_STATUS_NO_DEVICE
:
2884 case SRB_STATUS_NO_HBA
:
2885 case SRB_STATUS_INVALID_PATH_ID
:
2886 *Status
= STATUS_NO_SUCH_DEVICE
;
2890 case SRB_STATUS_COMMAND_TIMEOUT
:
2891 case SRB_STATUS_ABORTED
:
2892 case SRB_STATUS_TIMEOUT
:
2895 // Update the error count for the device.
2898 deviceExtension
->ErrorCount
++;
2899 *Status
= STATUS_IO_TIMEOUT
;
2902 case SRB_STATUS_SELECTION_TIMEOUT
:
2904 logStatus
= 0;//IO_ERR_NOT_READY;
2906 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2910 case SRB_STATUS_DATA_OVERRUN
:
2911 *Status
= STATUS_DATA_OVERRUN
;
2915 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2918 // Update the error count for the device.
2921 deviceExtension
->ErrorCount
++;
2922 *Status
= STATUS_IO_DEVICE_ERROR
;
2925 // If there was phase sequence error then limit the number of
2929 if (RetryCount
> 1 ) {
2935 case SRB_STATUS_REQUEST_FLUSHED
:
2938 // If the status needs verification bit is set. Then set
2939 // the status to need verification and no retry; otherwise,
2940 // just retry the request.
2943 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2945 *Status
= STATUS_VERIFY_REQUIRED
;
2948 *Status
= STATUS_IO_DEVICE_ERROR
;
2953 case SRB_STATUS_INVALID_REQUEST
:
2956 // An invalid request was attempted.
2959 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2963 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2964 case SRB_STATUS_PARITY_ERROR
:
2967 // Update the error count for the device.
2970 deviceExtension
->ErrorCount
++;
2973 // Fall through to below.
2976 case SRB_STATUS_BUS_RESET
:
2977 *Status
= STATUS_IO_DEVICE_ERROR
;
2980 case SRB_STATUS_ERROR
:
2982 *Status
= STATUS_IO_DEVICE_ERROR
;
2983 if (Srb
->ScsiStatus
== 0) {
2986 // This is some strange return code. Update the error
2987 // count for the device.
2990 deviceExtension
->ErrorCount
++;
2992 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2994 *Status
= STATUS_DEVICE_NOT_READY
;
2996 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2998 *Status
= STATUS_DEVICE_BUSY
;
3007 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
3009 *Status
= STATUS_IO_DEVICE_ERROR
;
3015 // If the error count has exceeded the error limit, then disable
3016 // any tagged queuing, multiple requests per lu queueing
3017 // and sychronous data transfers.
3020 if (deviceExtension
->ErrorCount
== 4) {
3023 // Clearing the no queue freeze flag prevents the port driver
3024 // from sending multiple requests per logical unit.
3027 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
3028 SRB_FLAGS_NO_QUEUE_FREEZE
);
3030 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3031 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
3033 } else if (deviceExtension
->ErrorCount
== 8) {
3036 // If a second threshold is reached, disable disconnects.
3039 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
3040 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
3045 // If there is a class specific error handler call it.
3048 if (deviceExtension
->ClassError
!= NULL
) {
3050 deviceExtension
->ClassError(DeviceObject
,
3057 // Log an error if necessary.
3062 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3064 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
3066 if (errorLogEntry
== NULL
) {
3069 // Return if no packet could be allocated.
3076 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
3077 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3079 errorLogEntry
->FinalStatus
= *Status
;
3083 // Calculate the device offset if there is a geometry.
3086 if (deviceExtension
->DiskGeometry
!= NULL
) {
3088 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
3089 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
3090 errorLogEntry
->DeviceOffset
,
3091 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
3094 errorLogEntry
->ErrorCode
= logStatus
;
3095 errorLogEntry
->SequenceNumber
= 0;
3096 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
3097 errorLogEntry
->IoControlCode
= IoDeviceCode
;
3098 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
3099 errorLogEntry
->UniqueErrorValue
= uniqueId
;
3100 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
3101 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
3102 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
3103 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
3104 errorLogEntry
->DumpData
[3] = 0;
3105 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
3107 if (senseBuffer
!= NULL
) {
3108 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
3109 senseBuffer
->AdditionalSenseCode
<< 8 |
3110 senseBuffer
->AdditionalSenseCodeQualifier
;
3115 // Write the error log packet.
3118 IoWriteErrorLogEntry(errorLogEntry
);
3123 } // end ScsiClassInterpretSenseInfo()
3129 PDEVICE_OBJECT DeviceObject
,
3131 PSCSI_REQUEST_BLOCK Srb
,
3137 Routine Description:
3139 This routine reinitializes the necessary fields, and sends the request
3144 DeviceObject - Supplies the device object associated with this request.
3146 Irp - Supplies the request to be retried.
3148 Srb - Supplies a Pointer to the SCSI request block to be retied.
3150 Assocaiated - Indicates this is an assocatied Irp created by split request.
3159 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3160 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3161 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3162 ULONG transferByteCount
;
3165 // Determine the transfer count of the request. If this is a read or a
3166 // write then the transfer count is in the Irp stack. Otherwise assume
3167 // the MDL contains the correct length. If there is no MDL then the
3168 // transfer length must be zero.
3171 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
3172 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
3174 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3176 } else if (Irp
->MdlAddress
!= NULL
) {
3179 // Note this assumes that only read and write requests are spilt and
3180 // other request do not need to be. If the data buffer address in
3181 // the MDL and the SRB don't match then transfer length is most
3182 // likely incorrect.
3185 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3186 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
3190 transferByteCount
= 0;
3194 // Reset byte count of transfer in SRB Extension.
3197 Srb
->DataTransferLength
= transferByteCount
;
3200 // Zero SRB statuses.
3203 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
3206 // Set the no disconnect flag, disable synchronous data transfers and
3207 // disable tagged queuing. This fixes some errors.
3210 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
3211 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3213 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
3214 Srb
->QueueTag
= SP_UNTAGGED
;
3217 // Set up major SCSI function.
3220 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3223 // Save SRB address in next stack for port driver.
3226 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
3229 // Set up IoCompletion routine address.
3234 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
3238 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3242 // Pass the request to the port driver.
3245 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3247 } // end RetryRequest()
3251 ScsiClassBuildRequest(
3252 PDEVICE_OBJECT DeviceObject
,
3258 Routine Description:
3260 This routine allocates and builds an Srb for a read or write request.
3261 The block address and length are supplied by the Irp. The retry count
3262 is stored in the current stack for use by ScsiClassIoComplete which
3263 processes these requests when they complete. The Irp is ready to be
3264 passed to the port driver when this routine returns.
3268 DeviceObject - Supplies the device object associated with this request.
3270 Irp - Supplies the request to be retried.
3274 If the IRP is for a disk transfer, the byteoffset field
3275 will already have been adjusted to make it relative to
3276 the beginning of the disk.
3286 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3287 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3288 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3289 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3290 PSCSI_REQUEST_BLOCK srb
;
3292 ULONG logicalBlockAddress
;
3293 USHORT transferBlocks
;
3296 // Calculate relative sector address.
3299 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
3305 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
3310 // Write length to SRB.
3313 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3316 // Set up IRP Address.
3319 srb
->OriginalRequest
= Irp
;
3322 // Set up target ID and logical unit number.
3325 srb
->PathId
= deviceExtension
->PathId
;
3326 srb
->TargetId
= deviceExtension
->TargetId
;
3327 srb
->Lun
= deviceExtension
->Lun
;
3328 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3329 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3332 // Save byte count of transfer in SRB Extension.
3335 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3338 // Initialize the queue actions field.
3341 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3344 // Queue sort key is Relative Block Address.
3347 srb
->QueueSortKey
= logicalBlockAddress
;
3350 // Indicate auto request sense by specifying buffer and size.
3353 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3354 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3357 // Set timeout value of one unit per 64k bytes of data.
3360 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3361 deviceExtension
->TimeOutValue
;
3367 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3371 // Indicate that 10-byte CDB's will be used.
3374 srb
->CdbLength
= 10;
3377 // Fill in CDB fields.
3380 cdb
= (PCDB
)srb
->Cdb
;
3383 // Zero 12 bytes for Atapi Packets
3386 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3388 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3389 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3392 // Move little endian values into CDB in big endian format.
3395 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3396 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3397 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3398 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3400 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3401 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3404 // Set transfer direction flag and Cdb command.
3407 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3409 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3411 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3412 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3416 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3418 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3419 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3423 // If this is not a write-through request, then allow caching.
3426 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3428 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3433 // If write caching is enable then force media access in the
3437 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3438 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3443 // Or in the default flags from the device object.
3446 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3449 // Set up major SCSI function.
3452 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3455 // Save SRB address in next stack for port driver.
3458 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3461 // Save retry count in current IRP stack.
3464 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3467 // Set up IoCompletion routine address.
3470 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3474 } // end ScsiClassBuildRequest()
3479 IN PDEVICE_OBJECT DeviceObject
,
3480 IN PCHAR ModeSenseBuffer
,
3487 Routine Description:
3489 This routine sends a mode sense command to a target ID and returns
3490 when it is complete.
3494 DeviceObject - Supplies the device object associated with this request.
3496 ModeSenseBuffer - Supplies a buffer to store the sense data.
3498 Length - Supplies the length in bytes of the mode sense buffer.
3500 PageMode - Supplies the page or pages of mode sense data to be retrived.
3504 Length of the transferred data is returned.
3508 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3510 SCSI_REQUEST_BLOCK srb
;
3514 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3517 // Build the MODE SENSE CDB.
3521 cdb
= (PCDB
)srb
.Cdb
;
3524 // Set timeout value from device extension.
3527 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3529 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3530 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3531 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3535 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3542 if (status
== STATUS_VERIFY_REQUIRED
) {
3545 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3546 // this status. MODE SENSE commands should be retried anyway.
3558 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3559 status
= STATUS_SUCCESS
;
3562 if (NT_SUCCESS(status
)) {
3563 return(srb
.DataTransferLength
);
3568 } // end ScsiClassModeSense()
3573 ScsiClassFindModePage(
3574 IN PCHAR ModeSenseBuffer
,
3582 Routine Description:
3584 This routine scans through the mode sense data and finds the requested
3585 mode sense page code.
3588 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3590 Length - Indicates the length of valid data.
3592 PageMode - Supplies the page mode to be searched for.
3594 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3598 A pointer to the the requested mode page. If the mode page was not found
3599 then NULL is return.
3604 ULONG parameterHeaderLength
;
3606 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3607 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3611 // Skip the mode select header and block descriptors.
3614 if (Length
< parameterHeaderLength
) {
3620 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3621 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3624 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3625 // requested page until the limit is reached.
3629 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3631 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3632 return(ModeSenseBuffer
);
3636 // Advance to the next page.
3639 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3647 ScsiClassSendSrbAsynchronous(
3648 PDEVICE_OBJECT DeviceObject
,
3649 PSCSI_REQUEST_BLOCK Srb
,
3651 PVOID BufferAddress
,
3653 BOOLEAN WriteToDevice
3657 Routine Description:
3659 This routine takes a partially built Srb and an Irp and sends it down to
3663 DeviceObject - Supplies the device object for the orginal request.
3665 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3666 CDB and the SRB timeout value must be filled in. The SRB must not be
3667 allocated from zone.
3669 Irp - Supplies the requesting Irp.
3671 BufferAddress - Supplies a pointer to the buffer to be transfered.
3673 BufferLength - Supplies the length of data transfer.
3675 WriteToDevice - Indicates the data transfer will be from system memory to
3680 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3685 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3686 PIO_STACK_LOCATION irpStack
;
3691 // Write length to SRB.
3694 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3697 // Set SCSI bus address.
3700 Srb
->PathId
= deviceExtension
->PathId
;
3701 Srb
->TargetId
= deviceExtension
->TargetId
;
3702 Srb
->Lun
= deviceExtension
->Lun
;
3704 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3707 // This is a violation of the SCSI spec but it is required for
3711 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3714 // Indicate auto request sense by specifying buffer and size.
3717 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3718 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3719 Srb
->DataBuffer
= BufferAddress
;
3721 if (BufferAddress
!= NULL
) {
3724 // Build Mdl if necessary.
3727 if (Irp
->MdlAddress
== NULL
) {
3729 if (IoAllocateMdl(BufferAddress
,
3735 return(STATUS_INSUFFICIENT_RESOURCES
);
3738 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3743 // Make sure the buffer requested matches the MDL.
3746 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3753 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3761 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3765 // Disable synchronous transfer for these requests.
3768 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3771 // Set the transfer length.
3774 Srb
->DataTransferLength
= BufferLength
;
3780 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3785 // Save a few parameters in the current stack location.
3788 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3791 // Save retry count in current Irp stack.
3794 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3797 // Set up IoCompletion routine address.
3800 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3803 // Get next stack location and
3804 // set major function code.
3807 irpStack
= IoGetNextIrpStackLocation(Irp
);
3809 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3812 // Save SRB address in next stack for port driver.
3815 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3818 // Set up Irp Address.
3821 Srb
->OriginalRequest
= Irp
;
3824 // Call the port driver to process the request.
3827 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3834 ScsiClassDeviceControlDispatch(
3835 PDEVICE_OBJECT DeviceObject
,
3841 Routine Description:
3843 The routine is the common class driver device control dispatch entry point.
3844 This routine is invokes the device-specific drivers DeviceControl routine,
3845 (which may call the Class driver's common DeviceControl routine).
3849 DeviceObject - Supplies a pointer to the device object for this request.
3851 Irp - Supplies the Irp making the request.
3855 Returns the status returned from the device-specific driver.
3861 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3865 // Call the class specific driver DeviceControl routine.
3866 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3869 ASSERT(deviceExtension
->ClassDeviceControl
);
3871 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3877 ScsiClassDeviceControl(
3878 PDEVICE_OBJECT DeviceObject
,
3883 Routine Description:
3885 The routine is the common class driver device control dispatch function.
3886 This routine is called by a class driver when it get an unrecognized
3887 device control request. This routine will perform the correct action for
3888 common requests such as lock media. If the device request is unknown it
3889 passed down to the next level.
3893 DeviceObject - Supplies a pointer to the device object for this request.
3895 Irp - Supplies the Irp making the request.
3899 Returns back a STATUS_PENDING or a completion status.
3904 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3905 PIO_STACK_LOCATION nextStack
;
3906 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3907 PSCSI_REQUEST_BLOCK srb
;
3910 ULONG modifiedIoControlCode
;
3912 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3913 IOCTL_STORAGE_RESET_DEVICE
) {
3915 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3916 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3917 status
= STATUS_UNSUCCESSFUL
;
3918 goto SetStatusAndReturn
;
3922 // If this is a pass through I/O control, set the minor function code
3923 // and device address and pass it to the port driver.
3926 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3927 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3929 PSCSI_PASS_THROUGH scsiPass
;
3931 nextStack
= IoGetNextIrpStackLocation(Irp
);
3934 // Validiate the user buffer.
3937 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3939 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3940 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3941 status
= STATUS_INVALID_PARAMETER
;
3942 goto SetStatusAndReturn
;
3946 // Force the SCSI address to the correct value.
3949 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3950 scsiPass
->PathId
= deviceExtension
->PathId
;
3951 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3952 scsiPass
->Lun
= deviceExtension
->Lun
;
3955 // NOTICE: The SCSI-II specificaiton indicates that this field
3956 // should be zero; however, some target controllers ignore the logical
3957 // unit number in the INDENTIFY message and only look at the logical
3958 // unit number field in the CDB.
3961 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3963 nextStack
->Parameters
= irpStack
->Parameters
;
3964 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3965 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3967 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3968 goto SetStatusAndReturn
;
3971 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3973 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3975 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3976 sizeof(SCSI_ADDRESS
)) {
3979 // Indicate unsuccessful status and no data transferred.
3982 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3983 Irp
->IoStatus
.Information
= 0;
3984 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3985 status
= STATUS_BUFFER_TOO_SMALL
;
3986 goto SetStatusAndReturn
;
3990 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3991 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3992 scsiAddress
->PathId
= deviceExtension
->PathId
;
3993 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3994 scsiAddress
->Lun
= deviceExtension
->Lun
;
3995 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3996 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3997 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3998 status
= STATUS_SUCCESS
;
3999 goto SetStatusAndReturn
;
4002 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
4006 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4007 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4008 status
= STATUS_INSUFFICIENT_RESOURCES
;
4009 goto SetStatusAndReturn
;
4013 // Write zeros to Srb.
4016 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4018 cdb
= (PCDB
)srb
->Cdb
;
4021 // Change the device type to disk for the switch statement.
4024 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
4025 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
4027 switch (modifiedIoControlCode
) {
4029 case IOCTL_DISK_CHECK_VERIFY
: {
4032 PIO_STACK_LOCATION newStack
;
4034 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
4037 // If a buffer for a media change count was provided, make sure it's
4038 // big enough to hold the result
4041 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
4044 // If the buffer is too small to hold the media change count
4045 // then return an error to the caller
4048 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4051 DebugPrint((3,"ScsiDeviceIoControl: media count "
4052 "buffer too small\n"));
4054 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4055 Irp
->IoStatus
.Information
= 0;
4057 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4058 status
= STATUS_BUFFER_TOO_SMALL
;
4059 goto SetStatusAndReturn
;
4064 // The caller has provided a valid buffer. Allocate an additional
4065 // irp and stick the CheckVerify completion routine on it. We will
4066 // then send this down to the port driver instead of the irp the
4070 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
4074 // Allocate a new irp to send the TestUnitReady to the port driver
4077 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
4080 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4081 Irp
->IoStatus
.Information
= 0;
4083 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4084 status
= STATUS_INSUFFICIENT_RESOURCES
;
4085 goto SetStatusAndReturn
;
4090 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
4091 IoSetNextIrpStackLocation(irp2
);
4094 // Set the top stack location and shove the master Irp into the
4098 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4099 newStack
->Parameters
.Others
.Argument1
= Irp
;
4100 newStack
->DeviceObject
= DeviceObject
;
4103 // Stick the check verify completion routine onto the stack
4104 // and prepare the irp for the port driver
4107 IoSetCompletionRoutine(irp2
,
4108 ScsiClassCheckVerifyComplete
,
4114 IoSetNextIrpStackLocation(irp2
);
4115 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4116 newStack
->DeviceObject
= DeviceObject
;
4119 // Mark the master irp as pending - whether the lower level
4120 // driver completes it immediately or not this should allow it
4121 // to go all the way back up.
4124 IoMarkIrpPending(Irp
);
4135 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
4138 // Set timeout value.
4141 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4144 // Since this routine will always hand the request to the
4145 // port driver if there isn't a data transfer to be done
4146 // we don't have to worry about completing the request here
4150 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4160 case IOCTL_DISK_MEDIA_REMOVAL
: {
4162 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
4165 // Prevent/Allow media removal.
4168 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4170 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4171 sizeof(PREVENT_MEDIA_REMOVAL
)) {
4174 // Indicate unsuccessful status and no data transferred.
4177 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4178 Irp
->IoStatus
.Information
= 0;
4180 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4181 status
= STATUS_BUFFER_TOO_SMALL
;
4182 goto SetStatusAndReturn
;
4186 // Get physical device extension. This is where the
4187 // lock count is stored.
4190 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
4193 // If command succeeded then increment or decrement lock counter.
4196 if (MediaRemoval
->PreventMediaRemoval
) {
4199 // This is a lock command. Reissue the command in case bus or device
4200 // was reset and lock cleared.
4203 InterlockedIncrement(&deviceExtension
->LockCount
);
4206 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4207 deviceExtension
->LockCount
,
4208 deviceExtension
->DeviceNumber
));
4213 // This is an unlock command.
4216 if (!deviceExtension
->LockCount
||
4217 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
4220 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4221 deviceExtension
->LockCount
,
4222 deviceExtension
->DeviceNumber
));
4225 // Don't unlock because someone still wants it locked.
4228 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4230 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4231 status
= STATUS_SUCCESS
;
4232 goto SetStatusAndReturn
;
4236 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4237 deviceExtension
->LockCount
,
4238 deviceExtension
->DeviceNumber
));
4243 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
4246 // TRUE - prevent media removal.
4247 // FALSE - allow media removal.
4250 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
4253 // Set timeout value.
4256 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4257 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4265 // Some devices will not support lock/unlock.
4266 // Pretend that it worked.
4272 case IOCTL_DISK_RESERVE
: {
4275 // Reserve logical unit.
4280 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
4283 // Set timeout value.
4286 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4288 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4298 case IOCTL_DISK_RELEASE
: {
4301 // Release logical unit.
4306 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
4309 // Set timeout value.
4312 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4314 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4324 case IOCTL_DISK_EJECT_MEDIA
: {
4332 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4333 cdb
->START_STOP
.LoadEject
= 1;
4334 cdb
->START_STOP
.Start
= 0;
4337 // Set timeout value.
4340 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4341 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4350 case IOCTL_DISK_LOAD_MEDIA
: {
4356 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4360 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4361 cdb
->START_STOP
.LoadEject
= 1;
4362 cdb
->START_STOP
.Start
= 1;
4365 // Set timeout value.
4368 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4369 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4379 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4382 // Search for devices that have been powered on since the last
4383 // device search or system initialization.
4386 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4387 status
= DriverEntry(DeviceObject
->DriverObject
,
4390 Irp
->IoStatus
.Status
= status
;
4392 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4399 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4402 // Pass the device control to the next driver.
4408 // Copy the Irp stack parameters to the next stack location.
4411 nextStack
= IoGetNextIrpStackLocation(Irp
);
4412 nextStack
->Parameters
= irpStack
->Parameters
;
4413 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4414 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4416 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4420 } // end switch( ...
4430 ScsiClassShutdownFlush(
4431 IN PDEVICE_OBJECT DeviceObject
,
4437 Routine Description:
4439 This routine is called for a shutdown and flush IRPs. These are sent by the
4440 system before it actually shuts down or when the file system does a flush.
4441 If it exists, the device-specific driver's routine will be invoked. If there
4442 wasn't one specified, the Irp will be completed with an Invalid device request.
4446 DriverObject - Pointer to device object to being shutdown by system.
4457 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4459 if (deviceExtension
->ClassShutdownFlush
) {
4462 // Call the device-specific driver's routine.
4465 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4469 // Device-specific driver doesn't support this.
4472 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4473 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4475 return STATUS_INVALID_DEVICE_REQUEST
;
4481 ScsiClassFindUnclaimedDevices(
4482 IN PCLASS_INIT_DATA InitializationData
,
4483 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4487 ULONG scsiBus
,deviceCount
= 0;
4488 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4489 PSCSI_INQUIRY_DATA lunInfo
;
4490 PINQUIRYDATA inquiryData
;
4492 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4495 // Get the SCSI bus scan data for this bus.
4498 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4501 // Search list for unclaimed disk devices.
4504 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4506 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4508 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4510 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4515 if (lunInfo
->NextInquiryDataOffset
== 0) {
4519 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4529 ScsiClassCreateDeviceObject(
4530 IN PDRIVER_OBJECT DriverObject
,
4531 IN PCCHAR ObjectNameBuffer
,
4532 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4533 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4534 IN PCLASS_INIT_DATA InitializationData
4539 Routine Description:
4541 This routine creates an object for the physical device specified and
4542 sets up the deviceExtension's function pointers for each entry point
4543 in the device-specific driver.
4547 DriverObject - Pointer to driver object created by system.
4549 ObjectNameBuffer - Dir. name of the object to create.
4551 PhysicalDeviceObject - Pointer to the physical (class) device object for
4552 this logical unit or NULL if this is it.
4554 DeviceObject - Pointer to the device object pointer we will return.
4556 InitializationData - Pointer to the init data created by the device-specific driver.
4565 STRING ntNameString
;
4566 UNICODE_STRING ntUnicodeString
;
4568 PDEVICE_OBJECT deviceObject
= NULL
;
4570 *DeviceObject
= NULL
;
4573 "ScsiClassCreateDeviceObject: Create device object %s\n",
4576 RtlInitString(&ntNameString
,
4579 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4583 if (!NT_SUCCESS(status
)) {
4586 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4589 ntUnicodeString
.Buffer
= NULL
;
4593 status
= IoCreateDevice(DriverObject
,
4594 InitializationData
->DeviceExtensionSize
,
4596 InitializationData
->DeviceType
,
4597 InitializationData
->DeviceCharacteristics
,
4602 if (!NT_SUCCESS(status
)) {
4605 "CreateDiskDeviceObjects: Can not create device object %s\n",
4610 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4613 // Fill in entry points
4616 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4617 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4618 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4619 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4620 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4621 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4622 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4624 deviceExtension
->MediaChangeCount
= 0;
4627 // If a pointer to the physical device object was passed in then use
4628 // that. If the value was NULL, then this is the physical device so
4629 // use the pointer to the device we just created.
4632 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4633 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4635 deviceExtension
->PhysicalDevice
= deviceObject
;
4639 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4641 *DeviceObject
= deviceObject
;
4643 RtlFreeUnicodeString(&ntUnicodeString
);
4646 // Indicate the ntUnicodeString is free.
4649 ntUnicodeString
.Buffer
= NULL
;
4657 ScsiClassClaimDevice(
4658 IN PDEVICE_OBJECT PortDeviceObject
,
4659 IN PSCSI_INQUIRY_DATA LunInfo
,
4661 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4665 Routine Description:
4667 This function claims a device in the port driver. The port driver object
4668 is updated with the correct driver object if the device is successfully
4673 PortDeviceObject - Supplies the base port device object.
4675 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4677 Release - Indicates the logical unit should be released rather than claimed.
4679 NewPortDeviceObject - Returns the updated port device object to be used
4680 for all future accesses.
4684 Returns a status indicating success or failure of the operation.
4689 IO_STATUS_BLOCK ioStatus
;
4691 PIO_STACK_LOCATION irpStack
;
4694 SCSI_REQUEST_BLOCK srb
;
4698 if (NewPortDeviceObject
!= NULL
) {
4699 *NewPortDeviceObject
= NULL
;
4703 // Clear the SRB fields.
4706 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4709 // Write length to SRB.
4712 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4715 // Set SCSI bus address.
4718 srb
.PathId
= LunInfo
->PathId
;
4719 srb
.TargetId
= LunInfo
->TargetId
;
4720 srb
.Lun
= LunInfo
->Lun
;
4722 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4723 SRB_FUNCTION_CLAIM_DEVICE
;
4726 // Set the event object to the unsignaled state.
4727 // It will be used to signal request completion.
4730 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4733 // Build synchronous request with no transfer.
4736 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4748 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4749 return STATUS_INSUFFICIENT_RESOURCES
;
4752 irpStack
= IoGetNextIrpStackLocation(irp
);
4755 // Save SRB address in next stack for port driver.
4758 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4761 // Set up IRP Address.
4764 srb
.OriginalRequest
= irp
;
4767 // Call the port driver with the request and wait for it to complete.
4770 status
= IoCallDriver(PortDeviceObject
, irp
);
4771 if (status
== STATUS_PENDING
) {
4773 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4774 status
= ioStatus
.Status
;
4778 // If this is a release request, then just decrement the reference count
4779 // and return. The status does not matter.
4784 ObDereferenceObject(PortDeviceObject
);
4785 return STATUS_SUCCESS
;
4788 if (!NT_SUCCESS(status
)) {
4792 ASSERT(srb
.DataBuffer
!= NULL
);
4795 // Reference the new port driver object so that it will not go away while
4796 // it is being used.
4799 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4804 if (!NT_SUCCESS(status
)) {
4810 // Return the new port device object pointer.
4813 if (NewPortDeviceObject
!= NULL
) {
4814 *NewPortDeviceObject
= srb
.DataBuffer
;
4823 ScsiClassInternalIoControl (
4824 IN PDEVICE_OBJECT DeviceObject
,
4830 Routine Description:
4832 This routine passes internal device controls to the port driver.
4833 Internal device controls are used by higher level class drivers to
4834 send scsi requests to a device that are not normally sent by a generic
4837 The path ID, target ID and logical unit ID are set in the srb so the
4838 higher level driver does not have to figure out what values are actually
4843 DeviceObject - Supplies a pointer to the device object for this request.
4845 Irp - Supplies the Irp making the request.
4849 Returns back a STATUS_PENDING or a completion status.
4853 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4854 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4855 PSCSI_REQUEST_BLOCK srb
;
4858 // Get a pointer to the SRB.
4861 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4864 // Set SCSI bus address.
4867 srb
->PathId
= deviceExtension
->PathId
;
4868 srb
->TargetId
= deviceExtension
->TargetId
;
4869 srb
->Lun
= deviceExtension
->Lun
;
4872 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4873 // zero; however, some target controllers ignore the logical unit number
4874 // in the INDENTIFY message and only look at the logical unit number field
4878 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4881 // Set the parameters in the next stack location.
4884 irpStack
= IoGetNextIrpStackLocation(Irp
);
4886 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4887 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4888 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4890 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4891 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4897 IN PDEVICE_OBJECT DeviceObject
,
4904 Routine Description:
4906 This routine is called when an internal device control I/O request
4907 has completed. It marks the IRP pending if necessary and returns the
4908 status of the request.
4912 DeviceObject - Target device object.
4914 Irp - Completed request.
4920 Returns the status of the completed request.
4925 UNREFERENCED_PARAMETER(Context
);
4926 UNREFERENCED_PARAMETER(DeviceObject
);
4929 // If pending is returned for this Irp then mark current stack
4933 if (Irp
->PendingReturned
) {
4935 IoMarkIrpPending( Irp
);
4938 return Irp
->IoStatus
.Status
;
4944 ScsiClassInitializeSrbLookasideList(
4945 IN PDEVICE_EXTENSION DeviceExtension
,
4946 IN ULONG NumberElements
4951 Routine Description:
4953 This routine sets up a lookaside listhead for srbs.
4957 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4959 NumberElements - Supplies the maximum depth of the lookaside list.
4969 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4972 NonPagedPoolMustSucceed
,
4973 SCSI_REQUEST_BLOCK_SIZE
,
4975 (USHORT
)NumberElements
);
4982 ScsiClassQueryTimeOutRegistryValue(
4983 IN PUNICODE_STRING RegistryPath
4988 Routine Description:
4990 This routine determines whether a reg key for a user-specified timeout value exists.
4994 RegistryPath - Pointer to the hardware reg. entry describing the key.
4998 New default timeout for a class of devices.
5004 // Find the appropriate reg. key
5007 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
5014 if (!RegistryPath
) {
5018 parameters
= ExAllocatePool(NonPagedPool
,
5019 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
5025 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
5026 path
= ExAllocatePool(NonPagedPool
, size
);
5029 ExFreePool(parameters
);
5033 RtlZeroMemory(path
,size
);
5034 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
5038 // Check for the Timeout value.
5041 RtlZeroMemory(parameters
,
5042 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
5044 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
5045 parameters
[0].Name
= L
"TimeOutValue";
5046 parameters
[0].EntryContext
= &timeOut
;
5047 parameters
[0].DefaultType
= REG_DWORD
;
5048 parameters
[0].DefaultData
= &zero
;
5049 parameters
[0].DefaultLength
= sizeof(ULONG
);
5051 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
5057 if (!(NT_SUCCESS(status
))) {
5061 ExFreePool(parameters
);
5065 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
5075 ScsiClassCheckVerifyComplete(
5076 IN PDEVICE_OBJECT DeviceObject
,
5083 Routine Description:
5085 This routine executes when the port driver has completed a check verify
5086 ioctl. It will set the status of the master Irp, copy the media change
5087 count and complete the request.
5091 DeviceObject - Supplies the device object which represents the logical
5094 Irp - Supplies the Irp which has completed.
5105 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5106 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5107 PDEVICE_EXTENSION physicalExtension
=
5108 deviceExtension
->PhysicalDevice
->DeviceExtension
;
5111 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
5114 // Copy the media change count and status
5117 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
5118 physicalExtension
->MediaChangeCount
;
5120 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
5121 "device %d is %d\n",
5122 physicalExtension
->DeviceNumber
,
5123 physicalExtension
->MediaChangeCount
));
5125 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
5126 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
5128 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
5132 return STATUS_MORE_PROCESSING_REQUIRED
;
5137 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
5141 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
5142 PKEVENT Event
= Irp
->UserEvent
;
5145 *IoStatusBlock
= Irp
->IoStatus
;
5146 Irp
->UserIosb
= NULL
;
5147 Irp
->UserEvent
= NULL
;
5151 Mdl
= Irp
->MdlAddress
;
5153 // if necessary - unlock pages
5154 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
5155 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
5164 // free irp and set event to unsignaled state
5166 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
5168 return STATUS_MORE_PROCESSING_REQUIRED
;