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
13 #include <include/class2.h>
16 /* Part of the drive letter hack */
24 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
25 #pragma alloc_text(PAGE, ScsiClassInitialize)
26 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
27 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
28 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
29 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
33 #define INQUIRY_DATA_SIZE 2048
34 #define START_UNIT_TIMEOUT 30
36 /* Disk layout used by Windows NT4 and earlier versions. */
37 //#define DEFAULT_SECTORS_PER_TRACK 32
38 //#define DEFAULT_TRACKS_PER_CYLINDER 64
40 /* Disk layout used by Windows 2000 and later versions. */
41 #define DEFAULT_SECTORS_PER_TRACK 63
42 #define DEFAULT_TRACKS_PER_CYLINDER 255
47 IN PDEVICE_OBJECT DeviceObject
,
54 IN PDEVICE_OBJECT DeviceObject
,
60 ScsiClassDeviceControlDispatch(
61 PDEVICE_OBJECT DeviceObject
,
67 ScsiClassDeviceControl(
68 PDEVICE_OBJECT DeviceObject
,
74 ScsiClassInternalIoControl (
75 IN PDEVICE_OBJECT DeviceObject
,
81 ScsiClassShutdownFlush(
82 IN PDEVICE_OBJECT DeviceObject
,
89 IN PDRIVER_OBJECT DriverObject
,
90 IN PUNICODE_STRING RegistryPath
94 // Class internal routines
101 PDEVICE_OBJECT DeviceObject
,
103 PSCSI_REQUEST_BLOCK Srb
,
110 IN PDEVICE_OBJECT DeviceObject
116 IN PDEVICE_OBJECT DeviceObject
,
123 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
131 IN PDRIVER_OBJECT DriverObject
,
132 IN PUNICODE_STRING RegistryPath
135 return STATUS_SUCCESS
;
138 /* The following hack to assign drive letters with a non-PnP storage stack */
140 typedef struct _CLASS_DEVICE_INFO
{
146 PDEVICE_OBJECT LowerDevice
;
147 } CLASS_DEVICE_INFO
, *PCLASS_DEVICE_INFO
;
149 typedef struct _CLASS_DRIVER_EXTENSION
{
151 UNICODE_STRING RegistryPath
;
152 CLASS_INIT_DATA InitializationData
;
153 } CLASS_DRIVER_EXTENSION
, *PCLASS_DRIVER_EXTENSION
;
157 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
160 UNICODE_STRING DriveLetterU
;
163 DriveLetterU
.Buffer
= Buffer1
;
164 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
166 /* Delete the symbolic link to PhysicalDriveX */
167 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DeviceInfo
->DriveNumber
) * sizeof(WCHAR
);
168 IoDeleteSymbolicLink(&DriveLetterU
);
170 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
172 for (Index
= 0; Index
< sizeof(ULONG
) * 8; Index
++)
174 if (DeviceInfo
->Partitions
& (1 << Index
))
176 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
177 IoDeleteSymbolicLink(&DriveLetterU
);
178 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU
);
185 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo
)
189 UNICODE_STRING DriveLetterU
, PartitionU
;
191 ULONG Index
, PartitionNumber
, DeviceNumber
, DriveNumber
;
192 OBJECT_ATTRIBUTES ObjectAttributes
;
193 IO_STATUS_BLOCK Iosb
;
194 HANDLE PartitionHandle
;
196 /* We assume this device does not current have a drive letter */
202 DriveLetterU
.Buffer
= Buffer1
;
203 DriveLetterU
.MaximumLength
= sizeof(Buffer1
);
204 PartitionU
.Buffer
= Buffer2
;
205 PartitionU
.MaximumLength
= sizeof(Buffer2
);
207 /* Determine the correct disk number */
210 /* Check that the disk exists */
211 if (DeviceInfo
->DeviceType
== FILE_DEVICE_DISK
)
213 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\HardDisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
215 else if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
217 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\CdRom%d", DeviceNumber
) * sizeof(WCHAR
);
220 InitializeObjectAttributes(&ObjectAttributes
,
222 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
225 Status
= ZwOpenFile(&PartitionHandle
,
226 FILE_READ_ATTRIBUTES
,
231 if (!NT_SUCCESS(Status
))
233 /* Return the last one that worked */
238 ZwClose(PartitionHandle
);
241 } while (Status
== STATUS_SUCCESS
);
243 /* Determine the correct drive number */
246 /* Check that the drive exists */
247 if (DeviceInfo
->DeviceType
== FILE_DEVICE_DISK
)
249 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
251 else if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
253 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\??\\%C:", ('C' + DriveNumber
)) * sizeof(WCHAR
);
255 InitializeObjectAttributes(&ObjectAttributes
,
257 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
260 Status
= ZwOpenFile(&PartitionHandle
,
261 FILE_READ_ATTRIBUTES
,
266 if (NT_SUCCESS(Status
))
268 ZwClose(PartitionHandle
);
271 } while (Status
== STATUS_SUCCESS
);
273 if (DeviceInfo
->DeviceType
== FILE_DEVICE_DISK
)
275 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition0", DeviceNumber
) * sizeof(WCHAR
);
276 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\PhysicalDrive%d", DriveNumber
) * sizeof(WCHAR
);
278 else if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
280 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\CdRom%d", DeviceNumber
) * sizeof(WCHAR
);
281 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + DriveNumber
)) * sizeof(WCHAR
);
284 /* Create the symbolic link to PhysicalDriveX */
285 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
286 if (!NT_SUCCESS(Status
))
288 /* Failed to create symbolic link */
289 DbgPrint("Failed to create symbolic link %wZ -> %wZ with %lx\n", &PartitionU
, &DriveLetterU
, Status
);
293 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
295 DeviceInfo
->DeviceNumber
= DeviceNumber
;
296 DeviceInfo
->DriveNumber
= DriveNumber
;
298 if (DeviceInfo
->DeviceType
== FILE_DEVICE_CD_ROM
)
300 /* done for cdroms */
301 return STATUS_SUCCESS
;
306 /* Check that the disk exists */
307 PartitionU
.Length
= swprintf(PartitionU
.Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", DeviceNumber
, PartitionNumber
) * sizeof(WCHAR
);
308 InitializeObjectAttributes(&ObjectAttributes
,
310 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
313 Status
= ZwOpenFile(&PartitionHandle
,
314 FILE_READ_ATTRIBUTES
,
319 if (!NT_SUCCESS(Status
))
323 ZwClose(PartitionHandle
);
325 /* Assign it a drive letter */
328 DriveLetterU
.Length
= swprintf(DriveLetterU
.Buffer
, L
"\\??\\%C:", ('C' + Index
)) * sizeof(WCHAR
);
330 Status
= IoCreateSymbolicLink(&DriveLetterU
, &PartitionU
);
333 } while (Status
!= STATUS_SUCCESS
);
335 DeviceInfo
->Partitions
|= (1 << (Index
- 1));
337 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU
, &DriveLetterU
);
342 return STATUS_SUCCESS
;
348 IN PDEVICE_OBJECT DeviceObject
,
351 PCLASS_DEVICE_INFO DeviceInfo
= DeviceObject
->DeviceExtension
;
352 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
354 if (IrpSp
->MinorFunction
== IRP_MN_START_DEVICE
)
356 ASSERT(DeviceInfo
->Signature
== '2slc');
357 IoSkipCurrentIrpStackLocation(Irp
);
358 return IoCallDriver(DeviceInfo
->LowerDevice
, Irp
);
360 else if (IrpSp
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
362 ASSERT(DeviceInfo
->Signature
== '2slc');
363 ScsiClassRemoveDriveLetter(DeviceInfo
);
365 IoForwardIrpSynchronously(DeviceInfo
->LowerDevice
, Irp
);
367 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
368 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
370 IoDetachDevice(DeviceInfo
->LowerDevice
);
371 IoDeleteDevice(DeviceObject
);
372 return STATUS_SUCCESS
;
376 if (DeviceInfo
->Signature
== '2slc')
378 IoSkipCurrentIrpStackLocation(Irp
);
379 return IoCallDriver(DeviceInfo
->LowerDevice
, Irp
);
382 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
383 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
384 return STATUS_NOT_SUPPORTED
;
391 IN PDRIVER_OBJECT DriverObject
,
392 IN PDEVICE_OBJECT PhysicalDeviceObject
)
394 PCLASS_DRIVER_EXTENSION DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
395 PCLASS_DEVICE_INFO DeviceInfo
;
396 PDEVICE_OBJECT DeviceObject
;
399 if (DriverExtension
->InitializationData
.ClassFindDevices(DriverObject
, &DriverExtension
->RegistryPath
, &DriverExtension
->InitializationData
,
400 PhysicalDeviceObject
, DriverExtension
->PortNumber
))
402 /* Create a device object */
403 Status
= IoCreateDevice(DriverObject
,
404 sizeof(CLASS_DEVICE_INFO
),
406 DriverExtension
->InitializationData
.DeviceType
,
410 if (!NT_SUCCESS(Status
))
415 DeviceInfo
= DeviceObject
->DeviceExtension
;
416 RtlZeroMemory(DeviceInfo
, sizeof(CLASS_DEVICE_INFO
));
417 DeviceInfo
->Signature
= '2slc';
419 /* Attach it to the PDO */
420 DeviceInfo
->LowerDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
421 DeviceInfo
->DeviceType
= DriverExtension
->InitializationData
.DeviceType
;
423 /* Check that the kernel has already assigned drive letters */
424 if (KeLoaderBlock
== NULL
)
426 /* Assign a drive letter */
427 ScsiClassAssignDriveLetter(DeviceInfo
);
431 /* The kernel will handle it */
434 /* Move to the next port number */
435 DriverExtension
->PortNumber
++;
439 /* Failed to find device */
440 DbgPrint("FAILED TO FIND DEVICE!\n");
443 return STATUS_SUCCESS
;
445 /* ---- End hack ---- */
454 IN PCLASS_INIT_DATA InitializationData
461 This routine is called by a class driver during its
462 DriverEntry routine to initialize the driver.
466 Argument1 - Driver Object.
467 Argument2 - Registry Path.
468 InitializationData - Device-specific driver's initialization data.
472 A valid return code for a DriverEntry routine.
479 PDRIVER_OBJECT DriverObject
= Argument1
;
480 PDEVICE_OBJECT portDeviceObject
;
482 STRING deviceNameString
;
483 UNICODE_STRING unicodeDeviceName
;
484 PFILE_OBJECT fileObject
;
485 CCHAR deviceNameBuffer
[256];
486 /* BOOLEAN deviceFound = FALSE; See note at the end */
487 PCLASS_DRIVER_EXTENSION DriverExtension
;
488 PUNICODE_STRING RegistryPath
= Argument2
;
490 DebugPrint((3,"\n\nSCSI Class Driver\n"));
493 // Validate the length of this structure. This is effectively a
497 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
499 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
500 return (ULONG
) STATUS_REVISION_MISMATCH
;
504 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
505 // are not required entry points.
508 if ((!InitializationData
->ClassFindDevices
) ||
509 (!InitializationData
->ClassDeviceControl
) ||
510 (!((InitializationData
->ClassReadWriteVerification
) ||
511 (InitializationData
->ClassStartIo
)))) {
514 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
516 return (ULONG
) STATUS_REVISION_MISMATCH
;
519 status
= IoAllocateDriverObjectExtension(DriverObject
,
521 sizeof(CLASS_DRIVER_EXTENSION
),
522 (PVOID
*)&DriverExtension
);
523 if (!NT_SUCCESS(status
))
526 RtlCopyMemory(&DriverExtension
->InitializationData
, InitializationData
, sizeof(CLASS_INIT_DATA
));
527 DriverExtension
->PortNumber
= 0;
529 DriverExtension
->RegistryPath
.Buffer
= ExAllocatePool(PagedPool
, RegistryPath
->MaximumLength
);
530 if (!DriverExtension
->RegistryPath
.Buffer
)
531 return STATUS_NO_MEMORY
;
533 DriverExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
534 DriverExtension
->RegistryPath
.MaximumLength
= RegistryPath
->MaximumLength
;
536 RtlCopyMemory(DriverExtension
->RegistryPath
.Buffer
,
537 RegistryPath
->Buffer
,
538 RegistryPath
->Length
);
541 // Update driver object with entry points.
544 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
545 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
546 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
547 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
548 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ScsiClassPlugPlay
;
549 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
550 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
551 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
552 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
553 DriverObject
->DriverExtension
->AddDevice
= ScsiClassAddDevice
;
555 if (InitializationData
->ClassStartIo
) {
556 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
560 // Open port driver controller device objects by name.
565 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", DriverExtension
->PortNumber
);
567 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
569 RtlInitString(&deviceNameString
, deviceNameBuffer
);
571 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
575 if (!NT_SUCCESS(status
)){
579 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
580 FILE_READ_ATTRIBUTES
,
584 if (NT_SUCCESS(status
)) {
587 // Call the device-specific driver's FindDevice routine.
590 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
591 portDeviceObject
, DriverExtension
->PortNumber
)) {
593 /* deviceFound = TRUE; See note at the end */
598 // Check next SCSI adapter.
601 DriverExtension
->PortNumber
++;
603 } while(NT_SUCCESS(status
));
605 /* We don't want to fail init just because we don't have devices right now */
606 return STATUS_SUCCESS
; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
612 ScsiClassCreateClose(
613 IN PDEVICE_OBJECT DeviceObject
,
621 SCSI class driver create and close routine. This is called by the I/O system
622 when the device is opened or closed.
626 DriverObject - Pointer to driver object created by system.
632 Device-specific drivers return value or STATUS_SUCCESS.
637 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
639 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
642 // Invoke the device-specific routine, if one exists. Otherwise complete
646 if (deviceExtension
->ClassCreateClose
) {
648 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
651 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
653 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
654 return(STATUS_SUCCESS
);
663 IN PDEVICE_OBJECT DeviceObject
,
671 This is the system entry point for read and write requests. The device-specific handler is invoked
672 to perform any validation necessary. The number of bytes in the request are
673 checked against the maximum byte counts that the adapter supports and requests are broken up into
674 smaller sizes if necessary.
688 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
689 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
691 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
692 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
695 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
697 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
698 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
701 // if DO_VERIFY_VOLUME bit is set
702 // in device object flags, fail request.
705 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
707 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
708 Irp
->IoStatus
.Information
= 0;
710 IoCompleteRequest(Irp
, 0);
711 return STATUS_VERIFY_REQUIRED
;
715 // Invoke the device specific routine to do whatever it needs to verify
719 ASSERT(deviceExtension
->ClassReadWriteVerification
);
721 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
723 if (!NT_SUCCESS(status
)) {
726 // It is up to the device specific driver to set the Irp status.
729 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
731 } else if (status
== STATUS_PENDING
) {
733 IoMarkIrpPending(Irp
);
734 return STATUS_PENDING
;
738 // Check for a zero length IO, as several macros will turn this into
739 // seemingly a 0xffffffff length request.
742 if (transferByteCount
== 0) {
743 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
744 Irp
->IoStatus
.Information
= 0;
745 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
746 return STATUS_SUCCESS
;
750 if (deviceExtension
->ClassStartIo
) {
752 IoMarkIrpPending(Irp
);
754 IoStartPacket(DeviceObject
,
759 return STATUS_PENDING
;
763 // Mark IRP with status pending.
766 IoMarkIrpPending(Irp
);
769 // Add partition byte offset to make starting byte relative to
770 // beginning of disk. In addition, add in skew for DM Driver, if any.
773 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
774 deviceExtension
->DMByteSkew
);
777 // Calculate number of pages in this transfer.
780 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
781 currentIrpStack
->Parameters
.Read
.Length
);
784 // Check if request length is greater than the maximum number of
785 // bytes that the hardware can transfer.
788 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
789 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
791 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
792 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
793 maximumTransferLength
));
794 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
795 currentIrpStack
->Parameters
.Read
.Length
));
798 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
800 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
801 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
805 // Check that maximum transfer size is not zero.
808 if (maximumTransferLength
== 0) {
809 maximumTransferLength
= PAGE_SIZE
;
813 // Mark IRP with status pending.
816 IoMarkIrpPending(Irp
);
819 // Request greater than port driver maximum.
820 // Break up into smaller routines.
823 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
826 return STATUS_PENDING
;
830 // Build SRB and CDB for this IRP.
833 ScsiClassBuildRequest(DeviceObject
, Irp
);
836 // Return the results of the call to the port driver.
839 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
841 } // end ScsiClassReadWrite()
846 ScsiClassGetCapabilities(
847 IN PDEVICE_OBJECT PortDeviceObject
,
848 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
855 This routine builds and sends a request to the port driver to
856 get a pointer to a structure that describes the adapter's
857 capabilities/limitations. This routine is synchronous.
861 PortDeviceObject - Port driver device object representing the HBA.
863 PortCapabilities - Location to store pointer to capabilities structure.
867 Nt status indicating the results of the operation.
871 This routine should only be called at initialization time.
877 IO_STATUS_BLOCK ioStatus
;
884 // Create notification event object to be used to signal the
885 // request completion.
888 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
891 // Build the synchronous request to be sent to the port driver
892 // to perform the request.
895 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
906 return STATUS_INSUFFICIENT_RESOURCES
;
910 // Pass request to port driver and wait for request to complete.
913 status
= IoCallDriver(PortDeviceObject
, irp
);
915 if (status
== STATUS_PENDING
) {
916 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
917 return(ioStatus
.Status
);
922 } // end ScsiClassGetCapabilities()
927 ScsiClassGetInquiryData(
928 IN PDEVICE_OBJECT PortDeviceObject
,
929 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
936 This routine sends a request to a port driver to return
937 configuration information. Space for the information is
938 allocated by this routine. The caller is responsible for
939 freeing the configuration information. This routine is
944 PortDeviceObject - Port driver device object representing the HBA.
946 ConfigInfo - Returns a pointer to the configuration information.
950 Nt status indicating the results of the operation.
954 This routine should be called only at initialization time.
960 IO_STATUS_BLOCK ioStatus
;
963 PSCSI_ADAPTER_BUS_INFO buffer
;
967 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
968 *ConfigInfo
= buffer
;
970 if (buffer
== NULL
) {
971 return(STATUS_INSUFFICIENT_RESOURCES
);
975 // Create notification event object to be used to signal the inquiry
976 // request completion.
979 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
982 // Build the synchronous request to be sent to the port driver
983 // to perform the inquiries.
986 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
997 return(STATUS_INSUFFICIENT_RESOURCES
);
1001 // Pass request to port driver and wait for request to complete.
1004 status
= IoCallDriver(PortDeviceObject
, irp
);
1006 if (status
== STATUS_PENDING
) {
1007 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
1008 status
= ioStatus
.Status
;
1011 if (!NT_SUCCESS(status
)) {
1014 // Free the buffer on an error.
1024 } // end ScsiClassGetInquiryData()
1029 ScsiClassReadDriveCapacity(
1030 IN PDEVICE_OBJECT DeviceObject
1035 Routine Description:
1037 This routine sends a READ CAPACITY to the requested device, updates
1038 the geometry information in the device object and returns
1039 when it is complete. This routine is synchronous.
1043 DeviceObject - Supplies a pointer to the device object that represents
1044 the device whose capacity is to be read.
1052 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1056 PREAD_CAPACITY_DATA readCapacityBuffer
;
1057 SCSI_REQUEST_BLOCK srb
;
1060 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1063 // Allocate read capacity buffer from nonpaged pool.
1066 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
1067 sizeof(READ_CAPACITY_DATA
));
1069 if (!readCapacityBuffer
) {
1070 return(STATUS_INSUFFICIENT_RESOURCES
);
1073 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
1076 // Build the read capacity CDB.
1080 cdb
= (PCDB
)srb
.Cdb
;
1083 // Set timeout value from device extension.
1086 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
1088 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1092 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
1095 sizeof(READ_CAPACITY_DATA
),
1098 if (NT_SUCCESS(status
)) {
1101 // Copy sector size from read capacity buffer to device extension
1102 // in reverse byte order.
1105 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
1106 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
1108 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
1109 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
1111 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
1112 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
1114 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
1115 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
1118 // Copy last sector in reverse byte order.
1121 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
1122 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
1124 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
1125 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
1127 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
1128 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
1130 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
1131 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
1134 // Calculate sector to byte shift.
1137 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
1139 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
1140 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
1142 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
1146 // Calculate media capacity in bytes.
1149 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
1152 // Calculate number of cylinders.
1155 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
1157 deviceExtension
->PartitionLength
.QuadPart
=
1158 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
1160 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1163 // This device supports removable media.
1166 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1171 // Assume media type is fixed disk.
1174 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1178 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
1181 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
1184 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
1187 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
1190 if (status
== STATUS_VERIFY_REQUIRED
) {
1193 // Routine ScsiClassSendSrbSynchronous does not retry
1194 // requests returned with this status.
1195 // Read Capacities should be retried
1209 if (!NT_SUCCESS(status
)) {
1212 // If the read capacity fails, set the geometry to reasonable parameter
1213 // so things don't fail at unexpected places. Zero the geometry
1214 // except for the bytes per sector and sector shift.
1217 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
1218 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
1219 deviceExtension
->SectorShift
= 9;
1220 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
1222 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1225 // This device supports removable media.
1228 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
1233 // Assume media type is fixed disk.
1236 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
1241 // Deallocate read capacity buffer.
1244 ExFreePool(readCapacityBuffer
);
1248 } // end ScsiClassReadDriveCapacity()
1253 ScsiClassReleaseQueue(
1254 IN PDEVICE_OBJECT DeviceObject
1259 Routine Description:
1261 This routine issues an internal device control command
1262 to the port driver to release a frozen queue. The call
1263 is issued asynchronously as ScsiClassReleaseQueue will be invoked
1264 from the IO completion DPC (and will have no context to
1265 wait for a synchronous call to complete).
1269 DeviceObject - The device object for the logical unit with
1278 PIO_STACK_LOCATION irpStack
;
1280 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1281 PCOMPLETION_CONTEXT context
;
1282 PSCSI_REQUEST_BLOCK srb
;
1285 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1288 // Allocate context from nonpaged pool.
1291 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1292 sizeof(COMPLETION_CONTEXT
));
1295 // Save the device object in the context for use by the completion
1299 context
->DeviceObject
= DeviceObject
;
1300 srb
= &context
->Srb
;
1306 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1309 // Write length to SRB.
1312 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1315 // Set up SCSI bus address.
1318 srb
->PathId
= deviceExtension
->PathId
;
1319 srb
->TargetId
= deviceExtension
->TargetId
;
1320 srb
->Lun
= deviceExtension
->Lun
;
1323 // If this device is removable then flush the queue. This will also
1327 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1329 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
1333 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
1338 // Build the asynchronous request to be sent to the port driver.
1341 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1346 // We have no better way of dealing with this at the moment
1349 KeBugCheck((ULONG
)0x0000002DL
);
1353 IoSetCompletionRoutine(irp
,
1354 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1360 irpStack
= IoGetNextIrpStackLocation(irp
);
1362 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1364 srb
->OriginalRequest
= irp
;
1367 // Store the SRB address in next stack for port driver.
1370 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1373 // Since this routine can cause outstanding requests to be completed, and
1374 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1375 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1376 // issuing the request
1379 currentIrql
= KeGetCurrentIrql();
1381 if(currentIrql
< DISPATCH_LEVEL
) {
1382 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1383 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1384 KeLowerIrql(currentIrql
);
1386 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1391 } // end ScsiClassReleaseQueue()
1397 IN PDEVICE_OBJECT DeviceObject
1402 Routine Description:
1404 Send command to SCSI unit to start or power up.
1405 Because this command is issued asynchronously, that is, without
1406 waiting on it to complete, the IMMEDIATE flag is not set. This
1407 means that the CDB will not return until the drive has powered up.
1408 This should keep subsequent requests from being submitted to the
1409 device before it has completely spun up.
1410 This routine is called from the InterpretSense routine, when a
1411 request sense returns data indicating that a drive must be
1416 DeviceObject - The device object for the logical unit with
1425 PIO_STACK_LOCATION irpStack
;
1427 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1428 PSCSI_REQUEST_BLOCK srb
;
1429 PCOMPLETION_CONTEXT context
;
1432 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1435 // Allocate Srb from nonpaged pool.
1438 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1439 sizeof(COMPLETION_CONTEXT
));
1442 // Save the device object in the context for use by the completion
1446 context
->DeviceObject
= DeviceObject
;
1447 srb
= &context
->Srb
;
1453 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1456 // Write length to SRB.
1459 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1462 // Set up SCSI bus address.
1465 srb
->PathId
= deviceExtension
->PathId
;
1466 srb
->TargetId
= deviceExtension
->TargetId
;
1467 srb
->Lun
= deviceExtension
->Lun
;
1469 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1472 // Set timeout value large enough for drive to spin up.
1475 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1478 // Set the transfer length.
1481 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1484 // Build the start unit CDB.
1488 cdb
= (PCDB
)srb
->Cdb
;
1490 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1491 cdb
->START_STOP
.Start
= 1;
1492 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1495 // Build the asynchronous request to be sent to the port driver.
1496 // Since this routine is called from a DPC the IRP should always be
1500 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1501 IoSetCompletionRoutine(irp
,
1502 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1508 irpStack
= IoGetNextIrpStackLocation(irp
);
1509 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1510 srb
->OriginalRequest
= irp
;
1513 // Store the SRB address in next stack for port driver.
1516 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1519 // Call the port driver with the IRP.
1522 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1526 } // end StartUnit()
1531 ScsiClassAsynchronousCompletion(
1532 PDEVICE_OBJECT DeviceObject
,
1538 Routine Description:
1540 This routine is called when an asynchronous I/O request
1541 which was issued by the class driver completes. Examples of such requests
1542 are release queue or START UNIT. This routine releases the queue if
1543 necessary. It then frees the context and the IRP.
1547 DeviceObject - The device object for the logical unit; however since this
1548 is the top stack location the value is NULL.
1550 Irp - Supplies a pointer to the Irp to be processed.
1552 Context - Supplies the context to be used to process this request.
1561 PCOMPLETION_CONTEXT context
= Context
;
1562 PSCSI_REQUEST_BLOCK srb
;
1564 srb
= &context
->Srb
;
1567 // If this is an execute srb, then check the return status and make sure.
1568 // the queue is not frozen.
1571 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1574 // Check for a frozen queue.
1577 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1580 // Unfreeze the queue getting the device object from the context.
1583 ScsiClassReleaseQueue(context
->DeviceObject
);
1588 // Free the context and the Irp.
1591 if (Irp
->MdlAddress
!= NULL
) {
1592 MmUnlockPages(Irp
->MdlAddress
);
1593 IoFreeMdl(Irp
->MdlAddress
);
1595 Irp
->MdlAddress
= NULL
;
1598 ExFreePool(context
);
1602 // Indicate the I/O system should stop processing the Irp completion.
1605 return STATUS_MORE_PROCESSING_REQUIRED
;
1607 } // ScsiClassAsynchronousCompletion()
1612 ScsiClassSplitRequest(
1613 IN PDEVICE_OBJECT DeviceObject
,
1615 IN ULONG MaximumBytes
1620 Routine Description:
1622 Break request into smaller requests. Each new request will be the
1623 maximum transfer size that the port driver can handle or if it
1624 is the final request, it may be the residual size.
1626 The number of IRPs required to process this request is written in the
1627 current stack of the original IRP. Then as each new IRP completes
1628 the count in the original IRP is decremented. When the count goes to
1629 zero, the original IRP is completed.
1633 DeviceObject - Pointer to the class device object to be addressed.
1635 Irp - Pointer to Irp the original request.
1644 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1645 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1646 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1647 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1648 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1649 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1650 ULONG dataLength
= MaximumBytes
;
1651 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1653 PSCSI_REQUEST_BLOCK srb
;
1655 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1656 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1658 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1661 // If all partial transfers complete successfully then the status and
1662 // bytes transferred are already set up. Failing a partial-transfer IRP
1663 // will set status to error and bytes transferred to 0 during
1664 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1665 // asynchronous partial transfers. This is an optimization for the
1669 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1670 Irp
->IoStatus
.Information
= transferByteCount
;
1673 // Save number of IRPs to complete count on current stack
1677 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1679 for (i
= 0; i
< irpCount
; i
++) {
1682 PIO_STACK_LOCATION newIrpStack
;
1685 // Allocate new IRP.
1688 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1690 if (newIrp
== NULL
) {
1692 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1695 // If an Irp can't be allocated then the original request cannot
1696 // be executed. If this is the first request then just fail the
1697 // original request; otherwise just return. When the pending
1698 // requests complete, they will complete the original request.
1699 // In either case set the IRP status to failure.
1702 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1703 Irp
->IoStatus
.Information
= 0;
1706 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1712 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1715 // Write MDL address to new IRP. In the port driver the SRB data
1716 // buffer field is used as an offset into the MDL, so the same MDL
1717 // can be used for each partial transfer. This saves having to build
1718 // a new MDL for each partial transfer.
1721 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1724 // At this point there is no current stack. IoSetNextIrpStackLocation
1725 // will make the first stack location the current stack so that the
1726 // SRB address can be written there.
1729 IoSetNextIrpStackLocation(newIrp
);
1730 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1732 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1733 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1734 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1735 newIrpStack
->DeviceObject
= DeviceObject
;
1738 // Build SRB and CDB.
1741 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1744 // Adjust SRB for this partial transfer.
1747 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1749 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1750 srb
->DataBuffer
= dataBuffer
;
1753 // Write original IRP address to new IRP.
1756 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1759 // Set the completion routine to ScsiClassIoCompleteAssociated.
1762 IoSetCompletionRoutine(newIrp
,
1763 ScsiClassIoCompleteAssociated
,
1770 // Call port driver with new request.
1773 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1776 // Set up for next request.
1779 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1781 transferByteCount
-= MaximumBytes
;
1783 if (transferByteCount
> MaximumBytes
) {
1785 dataLength
= MaximumBytes
;
1789 dataLength
= transferByteCount
;
1793 // Adjust disk byte offset.
1796 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1801 } // end ScsiClassSplitRequest()
1806 ScsiClassIoComplete(
1807 IN PDEVICE_OBJECT DeviceObject
,
1814 Routine Description:
1816 This routine executes when the port driver has completed a request.
1817 It looks at the SRB status in the completing SRB and if not success
1818 it checks for valid request sense buffer information. If valid, the
1819 info is used to update status with more precise message of type of
1820 error. This routine deallocates the SRB.
1824 DeviceObject - Supplies the device object which represents the logical
1827 Irp - Supplies the Irp which has completed.
1829 Context - Supplies a pointer to the SRB.
1838 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1839 PSCSI_REQUEST_BLOCK srb
= Context
;
1840 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1844 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1847 // Check SRB status for success of completing request.
1850 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1852 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1855 // Release the queue if it is frozen.
1858 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1859 ScsiClassReleaseQueue(DeviceObject
);
1862 retry
= ScsiClassInterpretSenseInfo(
1865 irpStack
->MajorFunction
,
1866 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1867 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1871 // If the status is verified required and the this request
1872 // should bypass verify required then retry the request.
1875 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1876 status
== STATUS_VERIFY_REQUIRED
) {
1878 status
= STATUS_IO_DEVICE_ERROR
;
1882 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1888 DebugPrint((1, "Retry request %lx\n", Irp
));
1889 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1890 return STATUS_MORE_PROCESSING_REQUIRED
;
1895 // Set status for successful request.
1898 status
= STATUS_SUCCESS
;
1900 } // end if (SRB_STATUS(srb->SrbStatus) ...
1903 // Return SRB to list.
1906 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1910 // Set status in completing IRP.
1913 Irp
->IoStatus
.Status
= status
;
1914 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1915 ASSERT(Irp
->IoStatus
.Information
);
1919 // Set the hard error if necessary.
1922 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1925 // Store DeviceObject for filesystem, and clear
1926 // in IoStatus.Information field.
1929 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1930 Irp
->IoStatus
.Information
= 0;
1934 // If pending has be returned for this irp then mark the current stack as
1938 if (Irp
->PendingReturned
) {
1939 IoMarkIrpPending(Irp
);
1942 if (deviceExtension
->ClassStartIo
) {
1943 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1944 IoStartNextPacket(DeviceObject
, FALSE
);
1950 } // end ScsiClassIoComplete()
1955 ScsiClassIoCompleteAssociated(
1956 IN PDEVICE_OBJECT DeviceObject
,
1963 Routine Description:
1965 This routine executes when the port driver has completed a request.
1966 It looks at the SRB status in the completing SRB and if not success
1967 it checks for valid request sense buffer information. If valid, the
1968 info is used to update status with more precise message of type of
1969 error. This routine deallocates the SRB. This routine is used for
1970 requests which were build by split request. After it has processed
1971 the request it decrements the Irp count in the master Irp. If the
1972 count goes to zero then the master Irp is completed.
1976 DeviceObject - Supplies the device object which represents the logical
1979 Irp - Supplies the Irp which has completed.
1981 Context - Supplies a pointer to the SRB.
1990 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1991 PSCSI_REQUEST_BLOCK srb
= Context
;
1992 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1993 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1998 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
2001 // Check SRB status for success of completing request.
2004 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2006 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
2009 // Release the queue if it is frozen.
2012 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2013 ScsiClassReleaseQueue(DeviceObject
);
2016 retry
= ScsiClassInterpretSenseInfo(
2019 irpStack
->MajorFunction
,
2020 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
2021 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
2025 // If the status is verified required and the this request
2026 // should bypass verify required then retry the request.
2029 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2030 status
== STATUS_VERIFY_REQUIRED
) {
2032 status
= STATUS_IO_DEVICE_ERROR
;
2036 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
2039 // Retry request. If the class driver has supplied a StartIo,
2040 // call it directly for retries.
2043 DebugPrint((1, "Retry request %lx\n", Irp
));
2046 if (!deviceExtension->ClassStartIo) {
2047 RetryRequest(DeviceObject, Irp, srb, TRUE);
2049 deviceExtension->ClassStartIo(DeviceObject, Irp);
2053 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
2055 return STATUS_MORE_PROCESSING_REQUIRED
;
2063 // Set status for successful request.
2066 status
= STATUS_SUCCESS
;
2068 } // end if (SRB_STATUS(srb->SrbStatus) ...
2071 // Return SRB to list.
2074 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
2078 // Set status in completing IRP.
2081 Irp
->IoStatus
.Status
= status
;
2083 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
2086 // Get next stack location. This original request is unused
2087 // except to keep track of the completing partial IRPs so the
2088 // stack location is valid.
2091 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
2094 // Update status only if error so that if any partial transfer
2095 // completes with error, then the original IRP will return with
2096 // error. If any of the asynchronous partial transfer IRPs fail,
2097 // with an error then the original IRP will return 0 bytes transfered.
2098 // This is an optimization for successful transfers.
2101 if (!NT_SUCCESS(status
)) {
2103 originalIrp
->IoStatus
.Status
= status
;
2104 originalIrp
->IoStatus
.Information
= 0;
2107 // Set the hard error if necessary.
2110 if (IoIsErrorUserInduced(status
)) {
2113 // Store DeviceObject for filesystem.
2116 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
2121 // Decrement and get the count of remaining IRPs.
2124 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
2126 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
2130 // Old bug could cause irp count to negative
2133 ASSERT(irpCount
>= 0);
2135 if (irpCount
== 0) {
2138 // All partial IRPs have completed.
2142 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
2145 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
2148 // If the class driver has supplied a startio, start the
2152 if (deviceExtension
->ClassStartIo
) {
2153 IoStartNextPacket(DeviceObject
, FALSE
);
2158 // Deallocate IRP and indicate the I/O system should not attempt any more
2163 return STATUS_MORE_PROCESSING_REQUIRED
;
2165 } // end ScsiClassIoCompleteAssociated()
2170 ScsiClassSendSrbSynchronous(
2171 PDEVICE_OBJECT DeviceObject
,
2172 PSCSI_REQUEST_BLOCK Srb
,
2173 PVOID BufferAddress
,
2175 BOOLEAN WriteToDevice
2180 Routine Description:
2182 This routine is called by SCSI device controls to complete an
2183 SRB and send it to the port driver synchronously (ie wait for
2184 completion). The CDB is already completed along with the SRB CDB
2185 size and request timeout value.
2189 DeviceObject - Supplies the device object which represents the logical
2192 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2194 BufferAddress - Supplies the address of the buffer.
2196 BufferLength - Supplies the length in bytes of the buffer.
2198 WriteToDevice - Indicates the data should be transfer to the device.
2202 Nt status indicating the final results of the operation.
2207 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2208 IO_STATUS_BLOCK ioStatus
;
2209 ULONG controlType
, mjFunction
;
2211 PIO_STACK_LOCATION irpStack
;
2213 PUCHAR senseInfoBuffer
;
2214 ULONG retryCount
= MAXIMUM_RETRIES
;
2217 LARGE_INTEGER dummy
;
2221 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
2226 // Write length to SRB.
2229 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2232 // Set SCSI bus address.
2235 Srb
->PathId
= deviceExtension
->PathId
;
2236 Srb
->TargetId
= deviceExtension
->TargetId
;
2237 Srb
->Lun
= deviceExtension
->Lun
;
2238 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2241 // NOTICE: The SCSI-II specification indicates that this field should be
2242 // zero; however, some target controllers ignore the logical unit number
2243 // in the IDENTIFY message and only look at the logical unit number field
2247 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
2250 // Enable auto request sense.
2253 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
2256 // Sense buffer is in aligned nonpaged pool.
2259 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
2261 if (senseInfoBuffer
== NULL
) {
2264 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
2265 return(STATUS_INSUFFICIENT_RESOURCES
);
2268 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
2269 Srb
->DataBuffer
= BufferAddress
;
2272 // Start retries here.
2278 // Set the event object to the unsignaled state.
2279 // It will be used to signal request completion.
2282 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
2285 // Set controlType and Srb direction flags.
2288 if (BufferAddress
!= NULL
) {
2290 if (WriteToDevice
) {
2292 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
2293 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
2294 mjFunction
= IRP_MJ_WRITE
;
2298 controlType
= IOCTL_SCSI_EXECUTE_IN
;
2299 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
2300 mjFunction
= IRP_MJ_READ
;
2306 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
2307 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
2308 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
2312 // Build device I/O control request with data transfer.
2314 irp
= IoBuildAsynchronousFsdRequest(
2316 deviceExtension
->DeviceObject
,
2318 (BufferAddress
) ? BufferLength
: 0,
2323 ExFreePool(senseInfoBuffer
);
2324 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2325 return(STATUS_INSUFFICIENT_RESOURCES
);
2329 irp
->UserEvent
= &event
;
2332 // Disable synchronous transfer for these requests.
2335 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2338 // Set the transfer length.
2341 Srb
->DataTransferLength
= BufferLength
;
2347 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
2350 // Set completion routine
2351 IoSetCompletionRoutine(
2353 ClassCompletionRoutine
,
2360 // Get next stack location.
2363 irpStack
= IoGetNextIrpStackLocation(irp
);
2365 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2366 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2369 // Set up SRB for execute scsi request. Save SRB address in next stack
2370 // for the port driver.
2373 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2376 // Set up IRP Address.
2379 Srb
->OriginalRequest
= irp
;
2382 // Call the port driver with the request and wait for it to complete.
2385 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2387 if (status
== STATUS_PENDING
) {
2388 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2392 // Check that request completed without error.
2395 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2398 // Release the queue if it is frozen.
2401 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2402 ScsiClassReleaseQueue(DeviceObject
);
2406 // Update status and determine if request should be retried.
2409 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2413 MAXIMUM_RETRIES
- retryCount
,
2418 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2419 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2420 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2422 LARGE_INTEGER delay
;
2425 // Delay for 2 seconds.
2428 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2431 // Stall for a while to let the controller spinup.
2434 KeDelayExecutionThread(KernelMode
,
2441 // If retries are not exhausted then retry this operation.
2451 status
= STATUS_SUCCESS
;
2454 ExFreePool(senseInfoBuffer
);
2457 } // end ScsiClassSendSrbSynchronous()
2462 ScsiClassInterpretSenseInfo(
2463 IN PDEVICE_OBJECT DeviceObject
,
2464 IN PSCSI_REQUEST_BLOCK Srb
,
2465 IN UCHAR MajorFunctionCode
,
2466 IN ULONG IoDeviceCode
,
2467 IN ULONG RetryCount
,
2468 OUT NTSTATUS
*Status
2473 Routine Description:
2475 This routine interprets the data returned from the SCSI
2476 request sense. It determines the status to return in the
2477 IRP and whether this request can be retried.
2481 DeviceObject - Supplies the device object associated with this request.
2483 Srb - Supplies the scsi request block which failed.
2485 MajorFunctionCode - Supplies the function code to be used for logging.
2487 IoDeviceCode - Supplies the device code to be used for logging.
2489 Status - Returns the status for the request.
2493 BOOLEAN TRUE: Drivers should retry this request.
2494 FALSE: Drivers should not retry this request.
2499 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2500 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2501 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2502 BOOLEAN retry
= TRUE
;
2503 BOOLEAN logError
= FALSE
;
2504 ULONG badSector
= 0;
2509 PIO_ERROR_LOG_PACKET errorLogEntry
;
2514 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
2517 // Check that request sense buffer is valid.
2521 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2522 for (i
= 1; i
< 12; i
++) {
2523 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2525 DebugPrint((3,"\n"));
2528 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2529 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2531 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2532 senseBuffer
->ErrorCode
));
2533 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2534 senseBuffer
->SenseKey
));
2535 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2536 senseBuffer
->AdditionalSenseCode
));
2537 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2538 senseBuffer
->AdditionalSenseCodeQualifier
));
2541 // Zero the additional sense code and additional sense code qualifier
2542 // if they were not returned by the device.
2545 readSector
= senseBuffer
->AdditionalSenseLength
+
2546 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2548 if (readSector
> Srb
->SenseInfoBufferLength
) {
2549 readSector
= Srb
->SenseInfoBufferLength
;
2552 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2553 senseBuffer
->AdditionalSenseCode
= 0;
2556 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2557 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2560 switch (senseBuffer
->SenseKey
& 0xf) {
2562 case SCSI_SENSE_NOT_READY
:
2564 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2565 *Status
= STATUS_DEVICE_NOT_READY
;
2567 switch (senseBuffer
->AdditionalSenseCode
) {
2569 case SCSI_ADSENSE_LUN_NOT_READY
:
2571 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2573 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2575 case SCSI_SENSEQ_BECOMING_READY
:
2577 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2578 " In process of becoming ready\n"));
2581 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2583 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2584 " Manual intervention required\n"));
2585 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2589 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2591 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2595 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2599 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2600 " Initializing command required\n"));
2603 // This sense code/additional sense code
2604 // combination may indicate that the device
2605 // needs to be started. Send an start unit if this
2606 // is a disk device.
2609 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2610 StartUnit(DeviceObject
);
2615 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2619 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2622 "ScsiClassInterpretSenseInfo:"
2623 " No Media in device.\n"));
2624 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2628 // signal autorun that there isn't any media in the device
2631 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2632 (!deviceExtension
->MediaChangeNoMedia
)) {
2633 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2636 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2637 "Detected No Media In Device "
2638 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2639 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2643 } // end switch (senseBuffer->AdditionalSenseCode)
2647 case SCSI_SENSE_DATA_PROTECT
:
2649 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2650 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2654 case SCSI_SENSE_MEDIUM_ERROR
:
2656 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2657 *Status
= STATUS_DEVICE_DATA_ERROR
;
2662 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2665 case SCSI_SENSE_HARDWARE_ERROR
:
2667 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2668 *Status
= STATUS_IO_DEVICE_ERROR
;
2672 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2676 case SCSI_SENSE_ILLEGAL_REQUEST
:
2678 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2679 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2681 switch (senseBuffer
->AdditionalSenseCode
) {
2683 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2684 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2688 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2689 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2690 *Status
= STATUS_NONEXISTENT_SECTOR
;
2694 case SCSI_ADSENSE_INVALID_LUN
:
2695 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2696 *Status
= STATUS_NO_SUCH_DEVICE
;
2700 case SCSI_ADSENSE_MUSIC_AREA
:
2701 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2705 case SCSI_ADSENSE_DATA_AREA
:
2706 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2710 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2711 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2715 case SCSI_ADSENSE_INVALID_CDB
:
2716 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2719 // Check if write cache enabled.
2722 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2725 // Assume FUA is not supported.
2728 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2737 } // end switch (senseBuffer->AdditionalSenseCode)
2741 case SCSI_SENSE_UNIT_ATTENTION
:
2743 switch (senseBuffer
->AdditionalSenseCode
) {
2744 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2745 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2747 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2749 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2752 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2753 "New Media Found - Setting MediaChanged event"
2754 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2755 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2760 case SCSI_ADSENSE_BUS_RESET
:
2761 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2765 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2768 } // end switch (senseBuffer->AdditionalSenseCode)
2770 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2771 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2774 // Set bit to indicate that media may have changed
2775 // and volume needs verification.
2778 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2780 *Status
= STATUS_VERIFY_REQUIRED
;
2785 *Status
= STATUS_IO_DEVICE_ERROR
;
2790 // A media change may have occured so increment the change
2791 // count for the physical device
2794 physicalExtension
->MediaChangeCount
++;
2796 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2797 "count for device %d is %d\n",
2798 physicalExtension
->DeviceNumber
,
2799 physicalExtension
->MediaChangeCount
));
2803 case SCSI_SENSE_ABORTED_COMMAND
:
2805 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2806 *Status
= STATUS_IO_DEVICE_ERROR
;
2809 case SCSI_SENSE_RECOVERED_ERROR
:
2811 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2812 *Status
= STATUS_SUCCESS
;
2817 switch(senseBuffer
->AdditionalSenseCode
) {
2818 case SCSI_ADSENSE_SEEK_ERROR
:
2819 case SCSI_ADSENSE_TRACK_ERROR
:
2820 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2823 case SCSI_ADSENSE_REC_DATA_NOECC
:
2824 case SCSI_ADSENSE_REC_DATA_ECC
:
2825 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2829 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2832 } // end switch(senseBuffer->AdditionalSenseCode)
2834 if (senseBuffer
->IncorrectLength
) {
2836 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2837 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2842 case SCSI_SENSE_NO_SENSE
:
2845 // Check other indicators.
2848 if (senseBuffer
->IncorrectLength
) {
2850 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2851 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2856 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2857 *Status
= STATUS_IO_DEVICE_ERROR
;
2865 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2866 *Status
= STATUS_IO_DEVICE_ERROR
;
2869 } // end switch (senseBuffer->SenseKey & 0xf)
2872 // Try to determine the bad sector from the inquiry data.
2875 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2876 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2877 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2879 for (index
= 0; index
< 4; index
++) {
2880 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2884 for (index
= 0; index
< 4; index
++) {
2885 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2888 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2889 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2892 // Make sure the bad sector is within the read sectors.
2895 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2896 badSector
= readSector
;
2903 // Request sense buffer not valid. No sense information
2904 // to pinpoint the error. Return general request fail.
2907 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2908 SRB_STATUS(Srb
->SrbStatus
)));
2911 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2912 case SRB_STATUS_INVALID_LUN
:
2913 case SRB_STATUS_INVALID_TARGET_ID
:
2914 case SRB_STATUS_NO_DEVICE
:
2915 case SRB_STATUS_NO_HBA
:
2916 case SRB_STATUS_INVALID_PATH_ID
:
2917 *Status
= STATUS_NO_SUCH_DEVICE
;
2921 case SRB_STATUS_COMMAND_TIMEOUT
:
2922 case SRB_STATUS_ABORTED
:
2923 case SRB_STATUS_TIMEOUT
:
2926 // Update the error count for the device.
2929 deviceExtension
->ErrorCount
++;
2930 *Status
= STATUS_IO_TIMEOUT
;
2933 case SRB_STATUS_SELECTION_TIMEOUT
:
2935 logStatus
= 0;//IO_ERR_NOT_READY;
2937 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2941 case SRB_STATUS_DATA_OVERRUN
:
2942 *Status
= STATUS_DATA_OVERRUN
;
2946 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2949 // Update the error count for the device.
2952 deviceExtension
->ErrorCount
++;
2953 *Status
= STATUS_IO_DEVICE_ERROR
;
2956 // If there was phase sequence error then limit the number of
2960 if (RetryCount
> 1 ) {
2966 case SRB_STATUS_REQUEST_FLUSHED
:
2969 // If the status needs verification bit is set. Then set
2970 // the status to need verification and no retry; otherwise,
2971 // just retry the request.
2974 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2976 *Status
= STATUS_VERIFY_REQUIRED
;
2979 *Status
= STATUS_IO_DEVICE_ERROR
;
2984 case SRB_STATUS_INVALID_REQUEST
:
2987 // An invalid request was attempted.
2990 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2994 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2995 case SRB_STATUS_PARITY_ERROR
:
2998 // Update the error count for the device.
3001 deviceExtension
->ErrorCount
++;
3004 // Fall through to below.
3007 case SRB_STATUS_BUS_RESET
:
3008 *Status
= STATUS_IO_DEVICE_ERROR
;
3011 case SRB_STATUS_ERROR
:
3013 *Status
= STATUS_IO_DEVICE_ERROR
;
3014 if (Srb
->ScsiStatus
== 0) {
3017 // This is some strange return code. Update the error
3018 // count for the device.
3021 deviceExtension
->ErrorCount
++;
3023 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
3025 *Status
= STATUS_DEVICE_NOT_READY
;
3027 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
3029 *Status
= STATUS_DEVICE_BUSY
;
3038 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
3040 *Status
= STATUS_IO_DEVICE_ERROR
;
3046 // If the error count has exceeded the error limit, then disable
3047 // any tagged queuing, multiple requests per lu queueing
3048 // and synchronous data transfers.
3051 if (deviceExtension
->ErrorCount
== 4) {
3054 // Clearing the no queue freeze flag prevents the port driver
3055 // from sending multiple requests per logical unit.
3058 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
3059 SRB_FLAGS_NO_QUEUE_FREEZE
);
3061 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3062 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
3064 } else if (deviceExtension
->ErrorCount
== 8) {
3067 // If a second threshold is reached, disable disconnects.
3070 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
3071 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
3076 // If there is a class specific error handler call it.
3079 if (deviceExtension
->ClassError
!= NULL
) {
3081 deviceExtension
->ClassError(DeviceObject
,
3088 // Log an error if necessary.
3093 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
3095 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
3097 if (errorLogEntry
== NULL
) {
3100 // Return if no packet could be allocated.
3107 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
3108 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
3110 errorLogEntry
->FinalStatus
= *Status
;
3114 // Calculate the device offset if there is a geometry.
3117 if (deviceExtension
->DiskGeometry
!= NULL
) {
3119 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
3120 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
3121 errorLogEntry
->DeviceOffset
,
3122 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
3125 errorLogEntry
->ErrorCode
= logStatus
;
3126 errorLogEntry
->SequenceNumber
= 0;
3127 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
3128 errorLogEntry
->IoControlCode
= IoDeviceCode
;
3129 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
3130 errorLogEntry
->UniqueErrorValue
= uniqueId
;
3131 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
3132 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
3133 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
3134 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
3135 errorLogEntry
->DumpData
[3] = 0;
3136 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
3138 if (senseBuffer
!= NULL
) {
3139 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
3140 senseBuffer
->AdditionalSenseCode
<< 8 |
3141 senseBuffer
->AdditionalSenseCodeQualifier
;
3146 // Write the error log packet.
3149 IoWriteErrorLogEntry(errorLogEntry
);
3154 } // end ScsiClassInterpretSenseInfo()
3160 PDEVICE_OBJECT DeviceObject
,
3162 PSCSI_REQUEST_BLOCK Srb
,
3168 Routine Description:
3170 This routine reinitializes the necessary fields, and sends the request
3175 DeviceObject - Supplies the device object associated with this request.
3177 Irp - Supplies the request to be retried.
3179 Srb - Supplies a Pointer to the SCSI request block to be retied.
3181 Associated - Indicates this is an associated Irp created by split request.
3190 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3191 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3192 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3193 ULONG transferByteCount
;
3195 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3198 // Determine the transfer count of the request. If this is a read or a
3199 // write then the transfer count is in the Irp stack. Otherwise assume
3200 // the MDL contains the correct length. If there is no MDL then the
3201 // transfer length must be zero.
3204 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
3205 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
3207 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3209 } else if (Irp
->MdlAddress
!= NULL
) {
3212 // Note this assumes that only read and write requests are spilt and
3213 // other request do not need to be. If the data buffer address in
3214 // the MDL and the SRB don't match then transfer length is most
3215 // likely incorrect.
3218 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3219 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
3223 transferByteCount
= 0;
3227 // Reset byte count of transfer in SRB Extension.
3230 Srb
->DataTransferLength
= transferByteCount
;
3233 // Zero SRB statuses.
3236 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
3239 // Set the no disconnect flag, disable synchronous data transfers and
3240 // disable tagged queuing. This fixes some errors.
3243 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
3244 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3246 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
3247 Srb
->QueueTag
= SP_UNTAGGED
;
3250 // Set up major SCSI function.
3253 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3256 // Save SRB address in next stack for port driver.
3259 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
3262 // Set up IoCompletion routine address.
3267 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
3271 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3275 // Pass the request to the port driver.
3278 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3280 } // end RetryRequest()
3284 ScsiClassBuildRequest(
3285 PDEVICE_OBJECT DeviceObject
,
3291 Routine Description:
3293 This routine allocates and builds an Srb for a read or write request.
3294 The block address and length are supplied by the Irp. The retry count
3295 is stored in the current stack for use by ScsiClassIoComplete which
3296 processes these requests when they complete. The Irp is ready to be
3297 passed to the port driver when this routine returns.
3301 DeviceObject - Supplies the device object associated with this request.
3303 Irp - Supplies the request to be retried.
3307 If the IRP is for a disk transfer, the byteoffset field
3308 will already have been adjusted to make it relative to
3309 the beginning of the disk.
3319 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3320 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3321 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3322 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3323 PSCSI_REQUEST_BLOCK srb
;
3325 ULONG logicalBlockAddress
;
3326 USHORT transferBlocks
;
3328 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3331 // Calculate relative sector address.
3334 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
3340 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
3345 // Write length to SRB.
3348 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3351 // Set up IRP Address.
3354 srb
->OriginalRequest
= Irp
;
3357 // Set up target ID and logical unit number.
3360 srb
->PathId
= deviceExtension
->PathId
;
3361 srb
->TargetId
= deviceExtension
->TargetId
;
3362 srb
->Lun
= deviceExtension
->Lun
;
3363 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3364 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3367 // Save byte count of transfer in SRB Extension.
3370 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3373 // Initialize the queue actions field.
3376 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3379 // Queue sort key is Relative Block Address.
3382 srb
->QueueSortKey
= logicalBlockAddress
;
3385 // Indicate auto request sense by specifying buffer and size.
3388 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3389 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3392 // Set timeout value of one unit per 64k bytes of data.
3395 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3396 deviceExtension
->TimeOutValue
;
3402 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3406 // Indicate that 10-byte CDB's will be used.
3409 srb
->CdbLength
= 10;
3412 // Fill in CDB fields.
3415 cdb
= (PCDB
)srb
->Cdb
;
3418 // Zero 12 bytes for Atapi Packets
3421 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3423 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3424 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3427 // Move little endian values into CDB in big endian format.
3430 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3431 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3432 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3433 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3435 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3436 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3439 // Set transfer direction flag and Cdb command.
3442 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3444 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3446 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3447 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3451 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3453 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3454 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3458 // If this is not a write-through request, then allow caching.
3461 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3463 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3468 // If write caching is enable then force media access in the
3472 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3473 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3478 // Or in the default flags from the device object.
3481 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3484 // Set up major SCSI function.
3487 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3490 // Save SRB address in next stack for port driver.
3493 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3496 // Save retry count in current IRP stack.
3499 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3502 // Set up IoCompletion routine address.
3505 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3509 } // end ScsiClassBuildRequest()
3514 IN PDEVICE_OBJECT DeviceObject
,
3515 IN PCHAR ModeSenseBuffer
,
3522 Routine Description:
3524 This routine sends a mode sense command to a target ID and returns
3525 when it is complete.
3529 DeviceObject - Supplies the device object associated with this request.
3531 ModeSenseBuffer - Supplies a buffer to store the sense data.
3533 Length - Supplies the length in bytes of the mode sense buffer.
3535 PageMode - Supplies the page or pages of mode sense data to be retrieved.
3539 Length of the transferred data is returned.
3543 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3545 SCSI_REQUEST_BLOCK srb
;
3549 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3551 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3554 // Build the MODE SENSE CDB.
3558 cdb
= (PCDB
)srb
.Cdb
;
3561 // Set timeout value from device extension.
3564 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3566 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3567 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3568 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3572 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3579 if (status
== STATUS_VERIFY_REQUIRED
) {
3582 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3583 // this status. MODE SENSE commands should be retried anyway.
3595 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3596 status
= STATUS_SUCCESS
;
3599 if (NT_SUCCESS(status
)) {
3600 return(srb
.DataTransferLength
);
3605 } // end ScsiClassModeSense()
3610 ScsiClassFindModePage(
3611 IN PCHAR ModeSenseBuffer
,
3619 Routine Description:
3621 This routine scans through the mode sense data and finds the requested
3622 mode sense page code.
3625 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3627 Length - Indicates the length of valid data.
3629 PageMode - Supplies the page mode to be searched for.
3631 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3635 A pointer to the the requested mode page. If the mode page was not found
3636 then NULL is return.
3641 ULONG parameterHeaderLength
;
3643 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3644 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3648 // Skip the mode select header and block descriptors.
3651 if (Length
< parameterHeaderLength
) {
3657 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3658 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3661 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3662 // requested page until the limit is reached.
3666 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3668 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3669 return(ModeSenseBuffer
);
3673 // Advance to the next page.
3676 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3684 ScsiClassSendSrbAsynchronous(
3685 PDEVICE_OBJECT DeviceObject
,
3686 PSCSI_REQUEST_BLOCK Srb
,
3688 PVOID BufferAddress
,
3690 BOOLEAN WriteToDevice
3694 Routine Description:
3696 This routine takes a partially built Srb and an Irp and sends it down to
3700 DeviceObject - Supplies the device object for the original request.
3702 Srb - Supplies a partially built ScsiRequestBlock. In particular, the
3703 CDB and the SRB timeout value must be filled in. The SRB must not be
3704 allocated from zone.
3706 Irp - Supplies the requesting Irp.
3708 BufferAddress - Supplies a pointer to the buffer to be transfered.
3710 BufferLength - Supplies the length of data transfer.
3712 WriteToDevice - Indicates the data transfer will be from system memory to
3717 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3722 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3723 PIO_STACK_LOCATION irpStack
;
3727 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3730 // Write length to SRB.
3733 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3736 // Set SCSI bus address.
3739 Srb
->PathId
= deviceExtension
->PathId
;
3740 Srb
->TargetId
= deviceExtension
->TargetId
;
3741 Srb
->Lun
= deviceExtension
->Lun
;
3743 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3746 // This is a violation of the SCSI spec but it is required for
3750 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3753 // Indicate auto request sense by specifying buffer and size.
3756 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3757 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3758 Srb
->DataBuffer
= BufferAddress
;
3760 if (BufferAddress
!= NULL
) {
3763 // Build Mdl if necessary.
3766 if (Irp
->MdlAddress
== NULL
) {
3768 if (IoAllocateMdl(BufferAddress
,
3774 return(STATUS_INSUFFICIENT_RESOURCES
);
3777 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3782 // Make sure the buffer requested matches the MDL.
3785 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3792 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3800 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3804 // Disable synchronous transfer for these requests.
3807 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3810 // Set the transfer length.
3813 Srb
->DataTransferLength
= BufferLength
;
3819 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3824 // Save a few parameters in the current stack location.
3827 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3830 // Save retry count in current Irp stack.
3833 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3836 // Set up IoCompletion routine address.
3839 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3842 // Get next stack location and
3843 // set major function code.
3846 irpStack
= IoGetNextIrpStackLocation(Irp
);
3848 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3851 // Save SRB address in next stack for port driver.
3854 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3857 // Set up Irp Address.
3860 Srb
->OriginalRequest
= Irp
;
3863 // Call the port driver to process the request.
3866 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3873 ScsiClassDeviceControlDispatch(
3874 PDEVICE_OBJECT DeviceObject
,
3880 Routine Description:
3882 The routine is the common class driver device control dispatch entry point.
3883 This routine is invokes the device-specific drivers DeviceControl routine,
3884 (which may call the Class driver's common DeviceControl routine).
3888 DeviceObject - Supplies a pointer to the device object for this request.
3890 Irp - Supplies the Irp making the request.
3894 Returns the status returned from the device-specific driver.
3900 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3902 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3905 // Call the class specific driver DeviceControl routine.
3906 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3909 ASSERT(deviceExtension
->ClassDeviceControl
);
3911 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3917 ScsiClassDeviceControl(
3918 PDEVICE_OBJECT DeviceObject
,
3923 Routine Description:
3925 The routine is the common class driver device control dispatch function.
3926 This routine is called by a class driver when it get an unrecognized
3927 device control request. This routine will perform the correct action for
3928 common requests such as lock media. If the device request is unknown it
3929 passed down to the next level.
3933 DeviceObject - Supplies a pointer to the device object for this request.
3935 Irp - Supplies the Irp making the request.
3939 Returns back a STATUS_PENDING or a completion status.
3944 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3945 PIO_STACK_LOCATION nextStack
;
3946 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3947 PSCSI_REQUEST_BLOCK srb
;
3950 ULONG modifiedIoControlCode
;
3952 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3954 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3955 IOCTL_STORAGE_RESET_DEVICE
) {
3957 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3958 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3959 status
= STATUS_UNSUCCESSFUL
;
3960 goto SetStatusAndReturn
;
3964 // If this is a pass through I/O control, set the minor function code
3965 // and device address and pass it to the port driver.
3968 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3969 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3971 PSCSI_PASS_THROUGH scsiPass
;
3973 nextStack
= IoGetNextIrpStackLocation(Irp
);
3976 // Validate the user buffer.
3979 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3981 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3982 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3983 status
= STATUS_INVALID_PARAMETER
;
3984 goto SetStatusAndReturn
;
3988 // Force the SCSI address to the correct value.
3991 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3992 scsiPass
->PathId
= deviceExtension
->PathId
;
3993 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3994 scsiPass
->Lun
= deviceExtension
->Lun
;
3997 // NOTICE: The SCSI-II specification indicates that this field
3998 // should be zero; however, some target controllers ignore the logical
3999 // unit number in the IDENTIFY message and only look at the logical
4000 // unit number field in the CDB.
4003 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4005 nextStack
->Parameters
= irpStack
->Parameters
;
4006 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4007 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4009 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4010 goto SetStatusAndReturn
;
4013 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
4015 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
4017 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4018 sizeof(SCSI_ADDRESS
)) {
4021 // Indicate unsuccessful status and no data transferred.
4024 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4025 Irp
->IoStatus
.Information
= 0;
4026 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4027 status
= STATUS_BUFFER_TOO_SMALL
;
4028 goto SetStatusAndReturn
;
4032 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
4033 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
4034 scsiAddress
->PathId
= deviceExtension
->PathId
;
4035 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
4036 scsiAddress
->Lun
= deviceExtension
->Lun
;
4037 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
4038 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4039 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4040 status
= STATUS_SUCCESS
;
4041 goto SetStatusAndReturn
;
4044 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
||
4045 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
) {
4048 Irp
->IoStatus
.Information
= 0;
4049 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
4050 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4051 status
= STATUS_NOT_IMPLEMENTED
;
4052 goto SetStatusAndReturn
;
4055 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
) {
4057 PMOUNTDEV_NAME name
= Irp
->AssociatedIrp
.SystemBuffer
;
4059 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTDEV_NAME
)) {
4061 Irp
->IoStatus
.Information
= 0;
4062 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
4063 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4064 status
= STATUS_INVALID_PARAMETER
;
4065 goto SetStatusAndReturn
;
4068 RtlZeroMemory(name
, sizeof(MOUNTDEV_NAME
));
4069 name
->NameLength
= deviceExtension
->DeviceName
.Length
;
4071 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< FIELD_OFFSET(MOUNTDEV_NAME
, Name
) + name
->NameLength
) {
4073 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_NAME
);
4074 Irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
4075 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4076 status
= STATUS_BUFFER_OVERFLOW
;
4077 goto SetStatusAndReturn
;
4080 RtlCopyMemory(name
->Name
, deviceExtension
->DeviceName
.Buffer
,
4082 status
= STATUS_SUCCESS
;
4083 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4084 Irp
->IoStatus
.Information
= FIELD_OFFSET(MOUNTDEV_NAME
, Name
) + name
->NameLength
;
4085 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4086 goto SetStatusAndReturn
;
4089 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
4093 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4094 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4095 status
= STATUS_INSUFFICIENT_RESOURCES
;
4096 goto SetStatusAndReturn
;
4100 // Write zeros to Srb.
4103 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4105 cdb
= (PCDB
)srb
->Cdb
;
4108 // Change the device type to disk for the switch statement.
4111 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
4112 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
4114 switch (modifiedIoControlCode
) {
4116 case IOCTL_DISK_CHECK_VERIFY
: {
4119 PIO_STACK_LOCATION newStack
;
4121 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
4124 // If a buffer for a media change count was provided, make sure it's
4125 // big enough to hold the result
4128 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
4131 // If the buffer is too small to hold the media change count
4132 // then return an error to the caller
4135 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
4138 DebugPrint((3,"ScsiDeviceIoControl: media count "
4139 "buffer too small\n"));
4141 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4142 Irp
->IoStatus
.Information
= 0;
4144 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4145 status
= STATUS_BUFFER_TOO_SMALL
;
4146 goto SetStatusAndReturn
;
4151 // The caller has provided a valid buffer. Allocate an additional
4152 // irp and stick the CheckVerify completion routine on it. We will
4153 // then send this down to the port driver instead of the irp the
4157 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
4161 // Allocate a new irp to send the TestUnitReady to the port driver
4164 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
4167 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
4168 Irp
->IoStatus
.Information
= 0;
4170 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4171 status
= STATUS_INSUFFICIENT_RESOURCES
;
4172 goto SetStatusAndReturn
;
4175 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
4176 IoSetNextIrpStackLocation(irp2
);
4179 // Set the top stack location and shove the master Irp into the
4183 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4184 newStack
->Parameters
.Others
.Argument1
= Irp
;
4185 newStack
->DeviceObject
= DeviceObject
;
4188 // Stick the check verify completion routine onto the stack
4189 // and prepare the irp for the port driver
4192 IoSetCompletionRoutine(irp2
,
4193 ScsiClassCheckVerifyComplete
,
4199 IoSetNextIrpStackLocation(irp2
);
4200 newStack
= IoGetCurrentIrpStackLocation(irp2
);
4201 newStack
->DeviceObject
= DeviceObject
;
4204 // Mark the master irp as pending - whether the lower level
4205 // driver completes it immediately or not this should allow it
4206 // to go all the way back up.
4209 IoMarkIrpPending(Irp
);
4220 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
4223 // Set timeout value.
4226 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4229 // Since this routine will always hand the request to the
4230 // port driver if there isn't a data transfer to be done
4231 // we don't have to worry about completing the request here
4235 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4245 case IOCTL_DISK_MEDIA_REMOVAL
: {
4247 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
4250 // Prevent/Allow media removal.
4253 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4255 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4256 sizeof(PREVENT_MEDIA_REMOVAL
)) {
4259 // Indicate unsuccessful status and no data transferred.
4262 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4263 Irp
->IoStatus
.Information
= 0;
4265 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4266 status
= STATUS_BUFFER_TOO_SMALL
;
4267 goto SetStatusAndReturn
;
4271 // Get physical device extension. This is where the
4272 // lock count is stored.
4275 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
4278 // If command succeeded then increment or decrement lock counter.
4281 if (MediaRemoval
->PreventMediaRemoval
) {
4284 // This is a lock command. Reissue the command in case bus or device
4285 // was reset and lock cleared.
4288 InterlockedIncrement(&deviceExtension
->LockCount
);
4291 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4292 deviceExtension
->LockCount
,
4293 deviceExtension
->DeviceNumber
));
4298 // This is an unlock command.
4301 if (!deviceExtension
->LockCount
||
4302 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
4305 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4306 deviceExtension
->LockCount
,
4307 deviceExtension
->DeviceNumber
));
4310 // Don't unlock because someone still wants it locked.
4313 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4315 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4316 status
= STATUS_SUCCESS
;
4317 goto SetStatusAndReturn
;
4321 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4322 deviceExtension
->LockCount
,
4323 deviceExtension
->DeviceNumber
));
4328 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
4331 // TRUE - prevent media removal.
4332 // FALSE - allow media removal.
4335 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
4338 // Set timeout value.
4341 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4342 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4350 // Some devices will not support lock/unlock.
4351 // Pretend that it worked.
4357 case IOCTL_DISK_RESERVE
: {
4360 // Reserve logical unit.
4365 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
4368 // Set timeout value.
4371 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4373 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4383 case IOCTL_DISK_RELEASE
: {
4386 // Release logical unit.
4391 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
4394 // Set timeout value.
4397 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4399 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4409 case IOCTL_DISK_EJECT_MEDIA
: {
4417 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4418 cdb
->START_STOP
.LoadEject
= 1;
4419 cdb
->START_STOP
.Start
= 0;
4422 // Set timeout value.
4425 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4426 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4435 case IOCTL_DISK_LOAD_MEDIA
: {
4441 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4445 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4446 cdb
->START_STOP
.LoadEject
= 1;
4447 cdb
->START_STOP
.Start
= 1;
4450 // Set timeout value.
4453 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4454 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4464 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4467 // Search for devices that have been powered on since the last
4468 // device search or system initialization.
4471 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4472 status
= DriverEntry(DeviceObject
->DriverObject
,
4475 Irp
->IoStatus
.Status
= status
;
4477 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4484 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4487 // Pass the device control to the next driver.
4493 // Copy the Irp stack parameters to the next stack location.
4496 nextStack
= IoGetNextIrpStackLocation(Irp
);
4497 nextStack
->Parameters
= irpStack
->Parameters
;
4498 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4499 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4501 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4505 } // end switch( ...
4515 ScsiClassShutdownFlush(
4516 IN PDEVICE_OBJECT DeviceObject
,
4522 Routine Description:
4524 This routine is called for a shutdown and flush IRPs. These are sent by the
4525 system before it actually shuts down or when the file system does a flush.
4526 If it exists, the device-specific driver's routine will be invoked. If there
4527 wasn't one specified, the Irp will be completed with an Invalid device request.
4531 DriverObject - Pointer to device object to being shutdown by system.
4542 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4544 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4546 if (deviceExtension
->ClassShutdownFlush
) {
4549 // Call the device-specific driver's routine.
4552 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4556 // Device-specific driver doesn't support this.
4559 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4560 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4562 return STATUS_INVALID_DEVICE_REQUEST
;
4568 ScsiClassFindUnclaimedDevices(
4569 IN PCLASS_INIT_DATA InitializationData
,
4570 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4574 ULONG scsiBus
,deviceCount
= 0;
4575 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4576 PSCSI_INQUIRY_DATA lunInfo
;
4577 PINQUIRYDATA inquiryData
;
4579 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4582 // Get the SCSI bus scan data for this bus.
4585 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4588 // Search list for unclaimed disk devices.
4591 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4593 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4595 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4597 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4602 if (lunInfo
->NextInquiryDataOffset
== 0) {
4606 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4616 ScsiClassCreateDeviceObject(
4617 IN PDRIVER_OBJECT DriverObject
,
4618 IN PCCHAR ObjectNameBuffer
,
4619 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4620 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4621 IN PCLASS_INIT_DATA InitializationData
4626 Routine Description:
4628 This routine creates an object for the physical device specified and
4629 sets up the deviceExtension's function pointers for each entry point
4630 in the device-specific driver.
4634 DriverObject - Pointer to driver object created by system.
4636 ObjectNameBuffer - Dir. name of the object to create.
4638 PhysicalDeviceObject - Pointer to the physical (class) device object for
4639 this logical unit or NULL if this is it.
4641 DeviceObject - Pointer to the device object pointer we will return.
4643 InitializationData - Pointer to the init data created by the device-specific driver.
4652 STRING ntNameString
;
4653 UNICODE_STRING ntUnicodeString
;
4655 PDEVICE_OBJECT deviceObject
= NULL
;
4657 *DeviceObject
= NULL
;
4660 "ScsiClassCreateDeviceObject: Create device object %s\n",
4663 RtlInitString(&ntNameString
,
4666 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4670 if (!NT_SUCCESS(status
)) {
4673 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4676 ntUnicodeString
.Buffer
= NULL
;
4680 status
= IoCreateDevice(DriverObject
,
4681 InitializationData
->DeviceExtensionSize
,
4683 InitializationData
->DeviceType
,
4684 InitializationData
->DeviceCharacteristics
,
4689 if (!NT_SUCCESS(status
)) {
4692 "CreateDiskDeviceObjects: Can not create device object %s\n",
4697 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4699 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4702 // Fill in entry points
4705 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4706 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4707 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4708 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4709 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4710 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4711 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4713 deviceExtension
->MediaChangeCount
= 0;
4716 // If a pointer to the physical device object was passed in then use
4717 // that. If the value was NULL, then this is the physical device so
4718 // use the pointer to the device we just created.
4721 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4722 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4724 deviceExtension
->PhysicalDevice
= deviceObject
;
4727 deviceExtension
->DeviceName
= ntUnicodeString
;
4730 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4732 *DeviceObject
= deviceObject
;
4740 ScsiClassClaimDevice(
4741 IN PDEVICE_OBJECT PortDeviceObject
,
4742 IN PSCSI_INQUIRY_DATA LunInfo
,
4744 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4748 Routine Description:
4750 This function claims a device in the port driver. The port driver object
4751 is updated with the correct driver object if the device is successfully
4756 PortDeviceObject - Supplies the base port device object.
4758 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4760 Release - Indicates the logical unit should be released rather than claimed.
4762 NewPortDeviceObject - Returns the updated port device object to be used
4763 for all future accesses.
4767 Returns a status indicating success or failure of the operation.
4772 IO_STATUS_BLOCK ioStatus
;
4774 PIO_STACK_LOCATION irpStack
;
4777 SCSI_REQUEST_BLOCK srb
;
4781 if (NewPortDeviceObject
!= NULL
) {
4782 *NewPortDeviceObject
= NULL
;
4786 // Clear the SRB fields.
4789 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4792 // Write length to SRB.
4795 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4798 // Set SCSI bus address.
4801 srb
.PathId
= LunInfo
->PathId
;
4802 srb
.TargetId
= LunInfo
->TargetId
;
4803 srb
.Lun
= LunInfo
->Lun
;
4805 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4806 SRB_FUNCTION_CLAIM_DEVICE
;
4809 // Set the event object to the unsignaled state.
4810 // It will be used to signal request completion.
4813 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4816 // Build synchronous request with no transfer.
4819 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4831 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4832 return STATUS_INSUFFICIENT_RESOURCES
;
4835 irpStack
= IoGetNextIrpStackLocation(irp
);
4838 // Save SRB address in next stack for port driver.
4841 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4844 // Set up IRP Address.
4847 srb
.OriginalRequest
= irp
;
4850 // Call the port driver with the request and wait for it to complete.
4853 status
= IoCallDriver(PortDeviceObject
, irp
);
4854 if (status
== STATUS_PENDING
) {
4856 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4857 status
= ioStatus
.Status
;
4861 // If this is a release request, then just decrement the reference count
4862 // and return. The status does not matter.
4867 //ObDereferenceObject(PortDeviceObject);
4868 return STATUS_SUCCESS
;
4871 if (!NT_SUCCESS(status
)) {
4875 ASSERT(srb
.DataBuffer
!= NULL
);
4878 // Reference the new port driver object so that it will not go away while
4879 // it is being used.
4882 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4887 if (!NT_SUCCESS(status
)) {
4891 ObDereferenceObject(srb
.DataBuffer
);
4894 // Return the new port device object pointer.
4897 if (NewPortDeviceObject
!= NULL
) {
4898 *NewPortDeviceObject
= srb
.DataBuffer
;
4907 ScsiClassInternalIoControl (
4908 IN PDEVICE_OBJECT DeviceObject
,
4914 Routine Description:
4916 This routine passes internal device controls to the port driver.
4917 Internal device controls are used by higher level class drivers to
4918 send scsi requests to a device that are not normally sent by a generic
4921 The path ID, target ID and logical unit ID are set in the srb so the
4922 higher level driver does not have to figure out what values are actually
4927 DeviceObject - Supplies a pointer to the device object for this request.
4929 Irp - Supplies the Irp making the request.
4933 Returns back a STATUS_PENDING or a completion status.
4937 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4938 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4939 PSCSI_REQUEST_BLOCK srb
;
4941 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4944 // Get a pointer to the SRB.
4947 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4950 // Set SCSI bus address.
4953 srb
->PathId
= deviceExtension
->PathId
;
4954 srb
->TargetId
= deviceExtension
->TargetId
;
4955 srb
->Lun
= deviceExtension
->Lun
;
4958 // NOTICE: The SCSI-II specification indicates that this field should be
4959 // zero; however, some target controllers ignore the logical unit number
4960 // in the IDENTIFY message and only look at the logical unit number field
4964 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4967 // Set the parameters in the next stack location.
4970 irpStack
= IoGetNextIrpStackLocation(Irp
);
4972 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4973 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4974 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4976 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4977 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4983 IN PDEVICE_OBJECT DeviceObject
,
4990 Routine Description:
4992 This routine is called when an internal device control I/O request
4993 has completed. It marks the IRP pending if necessary and returns the
4994 status of the request.
4998 DeviceObject - Target device object.
5000 Irp - Completed request.
5006 Returns the status of the completed request.
5011 UNREFERENCED_PARAMETER(Context
);
5012 UNREFERENCED_PARAMETER(DeviceObject
);
5015 // If pending is returned for this Irp then mark current stack
5019 if (Irp
->PendingReturned
) {
5021 IoMarkIrpPending( Irp
);
5024 return Irp
->IoStatus
.Status
;
5030 ScsiClassInitializeSrbLookasideList(
5031 IN PDEVICE_EXTENSION DeviceExtension
,
5032 IN ULONG NumberElements
5037 Routine Description:
5039 This routine sets up a lookaside listhead for srbs.
5043 DeviceExtension - Pointer to the deviceExtension containing the listhead.
5045 NumberElements - Supplies the maximum depth of the lookaside list.
5055 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
5058 NonPagedPoolMustSucceed
,
5059 SCSI_REQUEST_BLOCK_SIZE
,
5061 (USHORT
)NumberElements
);
5068 ScsiClassQueryTimeOutRegistryValue(
5069 IN PUNICODE_STRING RegistryPath
5074 Routine Description:
5076 This routine determines whether a reg key for a user-specified timeout value exists.
5080 RegistryPath - Pointer to the hardware reg. entry describing the key.
5084 New default timeout for a class of devices.
5090 // Find the appropriate reg. key
5093 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
5100 if (!RegistryPath
) {
5104 parameters
= ExAllocatePool(NonPagedPool
,
5105 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
5111 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
5112 path
= ExAllocatePool(NonPagedPool
, size
);
5115 ExFreePool(parameters
);
5119 RtlZeroMemory(path
,size
);
5120 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
5124 // Check for the Timeout value.
5127 RtlZeroMemory(parameters
,
5128 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
5130 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
5131 parameters
[0].Name
= L
"TimeOutValue";
5132 parameters
[0].EntryContext
= &timeOut
;
5133 parameters
[0].DefaultType
= REG_DWORD
;
5134 parameters
[0].DefaultData
= &zero
;
5135 parameters
[0].DefaultLength
= sizeof(ULONG
);
5137 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
5143 if (!(NT_SUCCESS(status
))) {
5147 ExFreePool(parameters
);
5151 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
5161 ScsiClassCheckVerifyComplete(
5162 IN PDEVICE_OBJECT DeviceObject
,
5169 Routine Description:
5171 This routine executes when the port driver has completed a check verify
5172 ioctl. It will set the status of the master Irp, copy the media change
5173 count and complete the request.
5177 DeviceObject - Supplies the device object which represents the logical
5180 Irp - Supplies the Irp which has completed.
5191 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
5192 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
5193 PDEVICE_EXTENSION physicalExtension
=
5194 deviceExtension
->PhysicalDevice
->DeviceExtension
;
5197 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
5198 ASSERT(*(PULONG
)physicalExtension
!= '2slc');
5200 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
5203 // Copy the media change count and status
5206 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
5207 physicalExtension
->MediaChangeCount
;
5209 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
5210 "device %d is %d\n",
5211 physicalExtension
->DeviceNumber
,
5212 physicalExtension
->MediaChangeCount
));
5214 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
5215 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
5217 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
5221 return STATUS_MORE_PROCESSING_REQUIRED
;
5226 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
5230 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
5231 PKEVENT Event
= Irp
->UserEvent
;
5234 *IoStatusBlock
= Irp
->IoStatus
;
5235 Irp
->UserIosb
= NULL
;
5236 Irp
->UserEvent
= NULL
;
5240 Mdl
= Irp
->MdlAddress
;
5242 // if necessary - unlock pages
5243 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
5244 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
5253 // free irp and set event to unsignaled state
5255 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
5257 return STATUS_MORE_PROCESSING_REQUIRED
;