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>
20 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
21 #pragma alloc_text(PAGE, ScsiClassInitialize)
22 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
23 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
24 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
25 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
29 #define INQUIRY_DATA_SIZE 2048
30 #define START_UNIT_TIMEOUT 30
32 /* Disk layout used by Windows NT4 and earlier versions. */
33 //#define DEFAULT_SECTORS_PER_TRACK 32
34 //#define DEFAULT_TRACKS_PER_CYLINDER 64
36 /* Disk layout used by Windows 2000 and later versions. */
37 #define DEFAULT_SECTORS_PER_TRACK 63
38 #define DEFAULT_TRACKS_PER_CYLINDER 255
43 IN PDEVICE_OBJECT DeviceObject
,
50 IN PDEVICE_OBJECT DeviceObject
,
56 ScsiClassDeviceControlDispatch(
57 PDEVICE_OBJECT DeviceObject
,
63 ScsiClassDeviceControl(
64 PDEVICE_OBJECT DeviceObject
,
70 ScsiClassInternalIoControl (
71 IN PDEVICE_OBJECT DeviceObject
,
77 ScsiClassShutdownFlush(
78 IN PDEVICE_OBJECT DeviceObject
,
85 IN PDRIVER_OBJECT DriverObject
,
86 IN PUNICODE_STRING RegistryPath
90 // Class internal routines
97 PDEVICE_OBJECT DeviceObject
,
99 PSCSI_REQUEST_BLOCK Srb
,
106 IN PDEVICE_OBJECT DeviceObject
112 IN PDEVICE_OBJECT DeviceObject
,
119 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
127 IN PDRIVER_OBJECT DriverObject
,
128 IN PUNICODE_STRING RegistryPath
131 return STATUS_SUCCESS
;
137 IN PDEVICE_OBJECT DeviceObject
,
140 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
142 if (IrpSp
->MinorFunction
== IRP_MN_START_DEVICE
)
144 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
145 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
146 return STATUS_SUCCESS
;
150 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
151 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
152 return STATUS_NOT_SUPPORTED
;
163 IN PCLASS_INIT_DATA InitializationData
170 This routine is called by a class driver during its
171 DriverEntry routine to initialize the driver.
175 Argument1 - Driver Object.
176 Argument2 - Registry Path.
177 InitializationData - Device-specific driver's initialization data.
181 A valid return code for a DriverEntry routine.
188 PDRIVER_OBJECT DriverObject
= Argument1
;
189 ULONG portNumber
= 0;
190 PDEVICE_OBJECT portDeviceObject
;
192 STRING deviceNameString
;
193 UNICODE_STRING unicodeDeviceName
;
194 PFILE_OBJECT fileObject
;
195 CCHAR deviceNameBuffer
[256];
196 BOOLEAN deviceFound
= FALSE
;
198 DebugPrint((3,"\n\nSCSI Class Driver\n"));
201 // Validate the length of this structure. This is effectively a
205 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
207 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
208 return (ULONG
) STATUS_REVISION_MISMATCH
;
212 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
213 // are not required entry points.
216 if ((!InitializationData
->ClassFindDevices
) ||
217 (!InitializationData
->ClassDeviceControl
) ||
218 (!((InitializationData
->ClassReadWriteVerification
) ||
219 (InitializationData
->ClassStartIo
)))) {
222 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
224 return (ULONG
) STATUS_REVISION_MISMATCH
;
228 // Update driver object with entry points.
231 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
232 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
233 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
234 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
235 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ScsiClassPlugPlay
;
236 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
237 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
238 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
239 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
241 if (InitializationData
->ClassStartIo
) {
242 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
246 // Open port driver controller device objects by name.
251 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", portNumber
);
253 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
255 RtlInitString(&deviceNameString
, deviceNameBuffer
);
257 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
261 if (!NT_SUCCESS(status
)){
265 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
266 FILE_READ_ATTRIBUTES
,
270 if (NT_SUCCESS(status
)) {
273 // Call the device-specific driver's FindDevice routine.
276 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
277 portDeviceObject
, portNumber
)) {
284 // Check next SCSI adapter.
289 } while(NT_SUCCESS(status
));
291 return deviceFound
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
297 ScsiClassCreateClose(
298 IN PDEVICE_OBJECT DeviceObject
,
306 SCSI class driver create and close routine. This is called by the I/O system
307 when the device is opened or closed.
311 DriverObject - Pointer to driver object created by system.
317 Device-specific drivers return value or STATUS_SUCCESS.
322 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
324 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
327 // Invoke the device-specific routine, if one exists. Otherwise complete
331 if (deviceExtension
->ClassCreateClose
) {
333 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
336 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
338 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
339 return(STATUS_SUCCESS
);
348 IN PDEVICE_OBJECT DeviceObject
,
356 This is the system entry point for read and write requests. The device-specific handler is invoked
357 to perform any validation necessary. The number of bytes in the request are
358 checked against the maximum byte counts that the adapter supports and requests are broken up into
359 smaller sizes if necessary.
373 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
374 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
376 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
377 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
380 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
382 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
383 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
386 // if DO_VERIFY_VOLUME bit is set
387 // in device object flags, fail request.
390 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
392 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
393 Irp
->IoStatus
.Information
= 0;
395 IoCompleteRequest(Irp
, 0);
396 return STATUS_VERIFY_REQUIRED
;
400 // Invoke the device specific routine to do whatever it needs to verify
404 ASSERT(deviceExtension
->ClassReadWriteVerification
);
406 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
408 if (!NT_SUCCESS(status
)) {
411 // It is up to the device specific driver to set the Irp status.
414 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
416 } else if (status
== STATUS_PENDING
) {
418 IoMarkIrpPending(Irp
);
419 return STATUS_PENDING
;
423 // Check for a zero length IO, as several macros will turn this into
424 // seemingly a 0xffffffff length request.
427 if (transferByteCount
== 0) {
428 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
429 Irp
->IoStatus
.Information
= 0;
430 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
431 return STATUS_SUCCESS
;
435 if (deviceExtension
->ClassStartIo
) {
437 IoMarkIrpPending(Irp
);
439 IoStartPacket(DeviceObject
,
444 return STATUS_PENDING
;
448 // Mark IRP with status pending.
451 IoMarkIrpPending(Irp
);
454 // Add partition byte offset to make starting byte relative to
455 // beginning of disk. In addition, add in skew for DM Driver, if any.
458 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
459 deviceExtension
->DMByteSkew
);
462 // Calculate number of pages in this transfer.
465 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
466 currentIrpStack
->Parameters
.Read
.Length
);
469 // Check if request length is greater than the maximum number of
470 // bytes that the hardware can transfer.
473 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
474 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
476 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
477 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
478 maximumTransferLength
));
479 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
480 currentIrpStack
->Parameters
.Read
.Length
));
483 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
485 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
486 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
490 // Check that maximum transfer size is not zero.
493 if (maximumTransferLength
== 0) {
494 maximumTransferLength
= PAGE_SIZE
;
498 // Mark IRP with status pending.
501 IoMarkIrpPending(Irp
);
504 // Request greater than port driver maximum.
505 // Break up into smaller routines.
508 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
511 return STATUS_PENDING
;
515 // Build SRB and CDB for this IRP.
518 ScsiClassBuildRequest(DeviceObject
, Irp
);
521 // Return the results of the call to the port driver.
524 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
526 } // end ScsiClassReadWrite()
531 ScsiClassGetCapabilities(
532 IN PDEVICE_OBJECT PortDeviceObject
,
533 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
540 This routine builds and sends a request to the port driver to
541 get a pointer to a structure that describes the adapter's
542 capabilities/limitations. This routine is synchronous.
546 PortDeviceObject - Port driver device object representing the HBA.
548 PortCapabilities - Location to store pointer to capabilities structure.
552 Nt status indicating the results of the operation.
556 This routine should only be called at initialization time.
562 IO_STATUS_BLOCK ioStatus
;
569 // Create notification event object to be used to signal the
570 // request completion.
573 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
576 // Build the synchronous request to be sent to the port driver
577 // to perform the request.
580 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
591 return STATUS_INSUFFICIENT_RESOURCES
;
595 // Pass request to port driver and wait for request to complete.
598 status
= IoCallDriver(PortDeviceObject
, irp
);
600 if (status
== STATUS_PENDING
) {
601 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
602 return(ioStatus
.Status
);
607 } // end ScsiClassGetCapabilities()
612 ScsiClassGetInquiryData(
613 IN PDEVICE_OBJECT PortDeviceObject
,
614 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
621 This routine sends a request to a port driver to return
622 configuration information. Space for the information is
623 allocated by this routine. The caller is responsible for
624 freeing the configuration information. This routine is
629 PortDeviceObject - Port driver device object representing the HBA.
631 ConfigInfo - Returns a pointer to the configuration information.
635 Nt status indicating the results of the operation.
639 This routine should be called only at initialization time.
645 IO_STATUS_BLOCK ioStatus
;
648 PSCSI_ADAPTER_BUS_INFO buffer
;
652 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
653 *ConfigInfo
= buffer
;
655 if (buffer
== NULL
) {
656 return(STATUS_INSUFFICIENT_RESOURCES
);
660 // Create notification event object to be used to signal the inquiry
661 // request completion.
664 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
667 // Build the synchronous request to be sent to the port driver
668 // to perform the inquiries.
671 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
682 return(STATUS_INSUFFICIENT_RESOURCES
);
686 // Pass request to port driver and wait for request to complete.
689 status
= IoCallDriver(PortDeviceObject
, irp
);
691 if (status
== STATUS_PENDING
) {
692 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
693 status
= ioStatus
.Status
;
696 if (!NT_SUCCESS(status
)) {
699 // Free the buffer on an error.
709 } // end ScsiClassGetInquiryData()
714 ScsiClassReadDriveCapacity(
715 IN PDEVICE_OBJECT DeviceObject
722 This routine sends a READ CAPACITY to the requested device, updates
723 the geometry information in the device object and returns
724 when it is complete. This routine is synchronous.
728 DeviceObject - Supplies a pointer to the device object that represents
729 the device whose capacity is to be read.
737 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
741 PREAD_CAPACITY_DATA readCapacityBuffer
;
742 SCSI_REQUEST_BLOCK srb
;
745 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
748 // Allocate read capacity buffer from nonpaged pool.
751 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
752 sizeof(READ_CAPACITY_DATA
));
754 if (!readCapacityBuffer
) {
755 return(STATUS_INSUFFICIENT_RESOURCES
);
758 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
761 // Build the read capacity CDB.
768 // Set timeout value from device extension.
771 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
773 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
777 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
780 sizeof(READ_CAPACITY_DATA
),
783 if (NT_SUCCESS(status
)) {
786 // Copy sector size from read capacity buffer to device extension
787 // in reverse byte order.
790 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
791 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
793 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
794 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
796 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
797 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
799 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
800 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
803 // Copy last sector in reverse byte order.
806 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
807 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
809 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
810 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
812 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
813 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
815 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
816 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
819 // Calculate sector to byte shift.
822 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
824 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
825 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
827 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
831 // Calculate number of cylinders.
834 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
837 // Calculate media capacity in bytes.
840 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
841 deviceExtension
->PartitionLength
.QuadPart
=
842 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
843 deviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= deviceExtension
->PartitionLength
.QuadPart
;
845 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
848 // This device supports removable media.
851 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
856 // Assume media type is fixed disk.
859 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
863 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
866 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
869 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
872 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
875 if (status
== STATUS_VERIFY_REQUIRED
) {
878 // Routine ScsiClassSendSrbSynchronous does not retry
879 // requests returned with this status.
880 // Read Capacities should be retried
894 if (!NT_SUCCESS(status
)) {
897 // If the read capacity fails, set the geometry to reasonable parameter
898 // so things don't fail at unexpected places. Zero the geometry
899 // except for the bytes per sector and sector shift.
902 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
903 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
904 deviceExtension
->SectorShift
= 9;
905 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
906 deviceExtension
->DiskGeometry
->DiskSize
.QuadPart
= (LONGLONG
) 0;
908 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
911 // This device supports removable media.
914 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
919 // Assume media type is fixed disk.
922 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
927 // Deallocate read capacity buffer.
930 ExFreePool(readCapacityBuffer
);
934 } // end ScsiClassReadDriveCapacity()
939 ScsiClassReleaseQueue(
940 IN PDEVICE_OBJECT DeviceObject
947 This routine issues an internal device control command
948 to the port driver to release a frozen queue. The call
949 is issued asynchronously as ScsiClassReleaseQueue will be invoked
950 from the IO completion DPC (and will have no context to
951 wait for a synchronous call to complete).
955 DeviceObject - The device object for the logical unit with
964 PIO_STACK_LOCATION irpStack
;
966 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
967 PCOMPLETION_CONTEXT context
;
968 PSCSI_REQUEST_BLOCK srb
;
971 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
974 // Allocate context from nonpaged pool.
977 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
978 sizeof(COMPLETION_CONTEXT
));
981 // Save the device object in the context for use by the completion
985 context
->DeviceObject
= DeviceObject
;
992 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
995 // Write length to SRB.
998 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1001 // Set up SCSI bus address.
1004 srb
->PathId
= deviceExtension
->PathId
;
1005 srb
->TargetId
= deviceExtension
->TargetId
;
1006 srb
->Lun
= deviceExtension
->Lun
;
1009 // If this device is removable then flush the queue. This will also
1013 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1015 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
1019 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
1024 // Build the asynchronous request to be sent to the port driver.
1027 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1032 // We have no better way of dealing with this at the moment
1035 KeBugCheck((ULONG
)0x0000002DL
);
1039 IoSetCompletionRoutine(irp
,
1040 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1046 irpStack
= IoGetNextIrpStackLocation(irp
);
1048 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1050 srb
->OriginalRequest
= irp
;
1053 // Store the SRB address in next stack for port driver.
1056 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1059 // Since this routine can cause outstanding requests to be completed, and
1060 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1061 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1062 // issuing the request
1065 currentIrql
= KeGetCurrentIrql();
1067 if(currentIrql
< DISPATCH_LEVEL
) {
1068 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1069 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1070 KeLowerIrql(currentIrql
);
1072 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1077 } // end ScsiClassReleaseQueue()
1083 IN PDEVICE_OBJECT DeviceObject
1088 Routine Description:
1090 Send command to SCSI unit to start or power up.
1091 Because this command is issued asynchronously, that is, without
1092 waiting on it to complete, the IMMEDIATE flag is not set. This
1093 means that the CDB will not return until the drive has powered up.
1094 This should keep subsequent requests from being submitted to the
1095 device before it has completely spun up.
1096 This routine is called from the InterpretSense routine, when a
1097 request sense returns data indicating that a drive must be
1102 DeviceObject - The device object for the logical unit with
1111 PIO_STACK_LOCATION irpStack
;
1113 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1114 PSCSI_REQUEST_BLOCK srb
;
1115 PCOMPLETION_CONTEXT context
;
1118 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1121 // Allocate Srb from nonpaged pool.
1124 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1125 sizeof(COMPLETION_CONTEXT
));
1128 // Save the device object in the context for use by the completion
1132 context
->DeviceObject
= DeviceObject
;
1133 srb
= &context
->Srb
;
1139 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1142 // Write length to SRB.
1145 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1148 // Set up SCSI bus address.
1151 srb
->PathId
= deviceExtension
->PathId
;
1152 srb
->TargetId
= deviceExtension
->TargetId
;
1153 srb
->Lun
= deviceExtension
->Lun
;
1155 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1158 // Set timeout value large enough for drive to spin up.
1161 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1164 // Set the transfer length.
1167 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1170 // Build the start unit CDB.
1174 cdb
= (PCDB
)srb
->Cdb
;
1176 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1177 cdb
->START_STOP
.Start
= 1;
1178 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1181 // Build the asynchronous request to be sent to the port driver.
1182 // Since this routine is called from a DPC the IRP should always be
1186 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1187 IoSetCompletionRoutine(irp
,
1188 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1194 irpStack
= IoGetNextIrpStackLocation(irp
);
1195 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1196 srb
->OriginalRequest
= irp
;
1199 // Store the SRB address in next stack for port driver.
1202 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1205 // Call the port driver with the IRP.
1208 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1212 } // end StartUnit()
1217 ScsiClassAsynchronousCompletion(
1218 PDEVICE_OBJECT DeviceObject
,
1224 Routine Description:
1226 This routine is called when an asynchronous I/O request
1227 which was issued by the class driver completes. Examples of such requests
1228 are release queue or START UNIT. This routine releases the queue if
1229 necessary. It then frees the context and the IRP.
1233 DeviceObject - The device object for the logical unit; however since this
1234 is the top stack location the value is NULL.
1236 Irp - Supplies a pointer to the Irp to be processed.
1238 Context - Supplies the context to be used to process this request.
1247 PCOMPLETION_CONTEXT context
= Context
;
1248 PSCSI_REQUEST_BLOCK srb
;
1250 srb
= &context
->Srb
;
1253 // If this is an execute srb, then check the return status and make sure.
1254 // the queue is not frozen.
1257 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1260 // Check for a frozen queue.
1263 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1266 // Unfreeze the queue getting the device object from the context.
1269 ScsiClassReleaseQueue(context
->DeviceObject
);
1274 // Free the context and the Irp.
1277 if (Irp
->MdlAddress
!= NULL
) {
1278 MmUnlockPages(Irp
->MdlAddress
);
1279 IoFreeMdl(Irp
->MdlAddress
);
1281 Irp
->MdlAddress
= NULL
;
1284 ExFreePool(context
);
1288 // Indicate the I/O system should stop processing the Irp completion.
1291 return STATUS_MORE_PROCESSING_REQUIRED
;
1293 } // ScsiClassAsynchronousCompletion()
1298 ScsiClassSplitRequest(
1299 IN PDEVICE_OBJECT DeviceObject
,
1301 IN ULONG MaximumBytes
1306 Routine Description:
1308 Break request into smaller requests. Each new request will be the
1309 maximum transfer size that the port driver can handle or if it
1310 is the final request, it may be the residual size.
1312 The number of IRPs required to process this request is written in the
1313 current stack of the original IRP. Then as each new IRP completes
1314 the count in the original IRP is decremented. When the count goes to
1315 zero, the original IRP is completed.
1319 DeviceObject - Pointer to the class device object to be addressed.
1321 Irp - Pointer to Irp the original request.
1330 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1331 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1332 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1333 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1334 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1335 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1336 ULONG dataLength
= MaximumBytes
;
1337 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1339 PSCSI_REQUEST_BLOCK srb
;
1341 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1342 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1344 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1347 // If all partial transfers complete successfully then the status and
1348 // bytes transferred are already set up. Failing a partial-transfer IRP
1349 // will set status to error and bytes transferred to 0 during
1350 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1351 // asynchronous partial transfers. This is an optimization for the
1355 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1356 Irp
->IoStatus
.Information
= transferByteCount
;
1359 // Save number of IRPs to complete count on current stack
1363 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1365 for (i
= 0; i
< irpCount
; i
++) {
1368 PIO_STACK_LOCATION newIrpStack
;
1371 // Allocate new IRP.
1374 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1376 if (newIrp
== NULL
) {
1378 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1381 // If an Irp can't be allocated then the original request cannot
1382 // be executed. If this is the first request then just fail the
1383 // original request; otherwise just return. When the pending
1384 // requests complete, they will complete the original request.
1385 // In either case set the IRP status to failure.
1388 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1389 Irp
->IoStatus
.Information
= 0;
1392 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1398 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1401 // Write MDL address to new IRP. In the port driver the SRB data
1402 // buffer field is used as an offset into the MDL, so the same MDL
1403 // can be used for each partial transfer. This saves having to build
1404 // a new MDL for each partial transfer.
1407 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1410 // At this point there is no current stack. IoSetNextIrpStackLocation
1411 // will make the first stack location the current stack so that the
1412 // SRB address can be written there.
1415 IoSetNextIrpStackLocation(newIrp
);
1416 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1418 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1419 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1420 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1421 newIrpStack
->DeviceObject
= DeviceObject
;
1424 // Build SRB and CDB.
1427 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1430 // Adjust SRB for this partial transfer.
1433 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1435 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1436 srb
->DataBuffer
= dataBuffer
;
1439 // Write original IRP address to new IRP.
1442 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1445 // Set the completion routine to ScsiClassIoCompleteAssociated.
1448 IoSetCompletionRoutine(newIrp
,
1449 ScsiClassIoCompleteAssociated
,
1456 // Call port driver with new request.
1459 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1462 // Set up for next request.
1465 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1467 transferByteCount
-= MaximumBytes
;
1469 if (transferByteCount
> MaximumBytes
) {
1471 dataLength
= MaximumBytes
;
1475 dataLength
= transferByteCount
;
1479 // Adjust disk byte offset.
1482 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1487 } // end ScsiClassSplitRequest()
1492 ScsiClassIoComplete(
1493 IN PDEVICE_OBJECT DeviceObject
,
1500 Routine Description:
1502 This routine executes when the port driver has completed a request.
1503 It looks at the SRB status in the completing SRB and if not success
1504 it checks for valid request sense buffer information. If valid, the
1505 info is used to update status with more precise message of type of
1506 error. This routine deallocates the SRB.
1510 DeviceObject - Supplies the device object which represents the logical
1513 Irp - Supplies the Irp which has completed.
1515 Context - Supplies a pointer to the SRB.
1524 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1525 PSCSI_REQUEST_BLOCK srb
= Context
;
1526 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1530 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1533 // Check SRB status for success of completing request.
1536 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1538 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1541 // Release the queue if it is frozen.
1544 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1545 ScsiClassReleaseQueue(DeviceObject
);
1548 retry
= ScsiClassInterpretSenseInfo(
1551 irpStack
->MajorFunction
,
1552 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1553 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1557 // If the status is verified required and the this request
1558 // should bypass verify required then retry the request.
1561 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1562 status
== STATUS_VERIFY_REQUIRED
) {
1564 status
= STATUS_IO_DEVICE_ERROR
;
1568 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1574 DebugPrint((1, "Retry request %lx\n", Irp
));
1575 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1576 return STATUS_MORE_PROCESSING_REQUIRED
;
1581 // Set status for successful request.
1584 status
= STATUS_SUCCESS
;
1586 } // end if (SRB_STATUS(srb->SrbStatus) ...
1589 // Return SRB to list.
1592 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1596 // Set status in completing IRP.
1599 Irp
->IoStatus
.Status
= status
;
1600 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1601 ASSERT(Irp
->IoStatus
.Information
);
1605 // Set the hard error if necessary.
1608 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1611 // Store DeviceObject for filesystem, and clear
1612 // in IoStatus.Information field.
1615 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1616 Irp
->IoStatus
.Information
= 0;
1620 // If pending has be returned for this irp then mark the current stack as
1624 if (Irp
->PendingReturned
) {
1625 IoMarkIrpPending(Irp
);
1628 if (deviceExtension
->ClassStartIo
) {
1629 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1630 IoStartNextPacket(DeviceObject
, FALSE
);
1636 } // end ScsiClassIoComplete()
1641 ScsiClassIoCompleteAssociated(
1642 IN PDEVICE_OBJECT DeviceObject
,
1649 Routine Description:
1651 This routine executes when the port driver has completed a request.
1652 It looks at the SRB status in the completing SRB and if not success
1653 it checks for valid request sense buffer information. If valid, the
1654 info is used to update status with more precise message of type of
1655 error. This routine deallocates the SRB. This routine is used for
1656 requests which were build by split request. After it has processed
1657 the request it decrements the Irp count in the master Irp. If the
1658 count goes to zero then the master Irp is completed.
1662 DeviceObject - Supplies the device object which represents the logical
1665 Irp - Supplies the Irp which has completed.
1667 Context - Supplies a pointer to the SRB.
1676 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1677 PSCSI_REQUEST_BLOCK srb
= Context
;
1678 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1679 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1684 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1687 // Check SRB status for success of completing request.
1690 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1692 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1695 // Release the queue if it is frozen.
1698 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1699 ScsiClassReleaseQueue(DeviceObject
);
1702 retry
= ScsiClassInterpretSenseInfo(
1705 irpStack
->MajorFunction
,
1706 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1707 MAXIMUM_RETRIES
- PtrToUlong(irpStack
->Parameters
.Others
.Argument4
),
1711 // If the status is verified required and the this request
1712 // should bypass verify required then retry the request.
1715 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1716 status
== STATUS_VERIFY_REQUIRED
) {
1718 status
= STATUS_IO_DEVICE_ERROR
;
1722 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1725 // Retry request. If the class driver has supplied a StartIo,
1726 // call it directly for retries.
1729 DebugPrint((1, "Retry request %lx\n", Irp
));
1732 if (!deviceExtension->ClassStartIo) {
1733 RetryRequest(DeviceObject, Irp, srb, TRUE);
1735 deviceExtension->ClassStartIo(DeviceObject, Irp);
1739 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1741 return STATUS_MORE_PROCESSING_REQUIRED
;
1749 // Set status for successful request.
1752 status
= STATUS_SUCCESS
;
1754 } // end if (SRB_STATUS(srb->SrbStatus) ...
1757 // Return SRB to list.
1760 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1764 // Set status in completing IRP.
1767 Irp
->IoStatus
.Status
= status
;
1769 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
1772 // Get next stack location. This original request is unused
1773 // except to keep track of the completing partial IRPs so the
1774 // stack location is valid.
1777 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
1780 // Update status only if error so that if any partial transfer
1781 // completes with error, then the original IRP will return with
1782 // error. If any of the asynchronous partial transfer IRPs fail,
1783 // with an error then the original IRP will return 0 bytes transfered.
1784 // This is an optimization for successful transfers.
1787 if (!NT_SUCCESS(status
)) {
1789 originalIrp
->IoStatus
.Status
= status
;
1790 originalIrp
->IoStatus
.Information
= 0;
1793 // Set the hard error if necessary.
1796 if (IoIsErrorUserInduced(status
)) {
1799 // Store DeviceObject for filesystem.
1802 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
1807 // Decrement and get the count of remaining IRPs.
1810 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
1812 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
1816 // Old bug could cause irp count to negative
1819 ASSERT(irpCount
>= 0);
1821 if (irpCount
== 0) {
1824 // All partial IRPs have completed.
1828 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
1831 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
1834 // If the class driver has supplied a startio, start the
1838 if (deviceExtension
->ClassStartIo
) {
1839 IoStartNextPacket(DeviceObject
, FALSE
);
1844 // Deallocate IRP and indicate the I/O system should not attempt any more
1849 return STATUS_MORE_PROCESSING_REQUIRED
;
1851 } // end ScsiClassIoCompleteAssociated()
1856 ScsiClassSendSrbSynchronous(
1857 PDEVICE_OBJECT DeviceObject
,
1858 PSCSI_REQUEST_BLOCK Srb
,
1859 PVOID BufferAddress
,
1861 BOOLEAN WriteToDevice
1866 Routine Description:
1868 This routine is called by SCSI device controls to complete an
1869 SRB and send it to the port driver synchronously (ie wait for
1870 completion). The CDB is already completed along with the SRB CDB
1871 size and request timeout value.
1875 DeviceObject - Supplies the device object which represents the logical
1878 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
1880 BufferAddress - Supplies the address of the buffer.
1882 BufferLength - Supplies the length in bytes of the buffer.
1884 WriteToDevice - Indicates the data should be transfer to the device.
1888 Nt status indicating the final results of the operation.
1893 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1894 IO_STATUS_BLOCK ioStatus
;
1895 ULONG controlType
, mjFunction
;
1897 PIO_STACK_LOCATION irpStack
;
1899 PUCHAR senseInfoBuffer
;
1900 ULONG retryCount
= MAXIMUM_RETRIES
;
1903 LARGE_INTEGER dummy
;
1907 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
1912 // Write length to SRB.
1915 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1918 // Set SCSI bus address.
1921 Srb
->PathId
= deviceExtension
->PathId
;
1922 Srb
->TargetId
= deviceExtension
->TargetId
;
1923 Srb
->Lun
= deviceExtension
->Lun
;
1924 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1927 // NOTICE: The SCSI-II specification indicates that this field should be
1928 // zero; however, some target controllers ignore the logical unit number
1929 // in the IDENTIFY message and only look at the logical unit number field
1933 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1936 // Enable auto request sense.
1939 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1942 // Sense buffer is in aligned nonpaged pool.
1945 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1947 if (senseInfoBuffer
== NULL
) {
1950 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
1951 return(STATUS_INSUFFICIENT_RESOURCES
);
1954 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
1955 Srb
->DataBuffer
= BufferAddress
;
1958 // Start retries here.
1964 // Set the event object to the unsignaled state.
1965 // It will be used to signal request completion.
1968 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1971 // Set controlType and Srb direction flags.
1974 if (BufferAddress
!= NULL
) {
1976 if (WriteToDevice
) {
1978 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
1979 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
1980 mjFunction
= IRP_MJ_WRITE
;
1984 controlType
= IOCTL_SCSI_EXECUTE_IN
;
1985 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
1986 mjFunction
= IRP_MJ_READ
;
1992 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
1993 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1994 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
1998 // Build device I/O control request with data transfer.
2000 irp
= IoBuildAsynchronousFsdRequest(
2002 deviceExtension
->DeviceObject
,
2004 (BufferAddress
) ? BufferLength
: 0,
2009 ExFreePool(senseInfoBuffer
);
2010 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2011 return(STATUS_INSUFFICIENT_RESOURCES
);
2015 irp
->UserEvent
= &event
;
2018 // Disable synchronous transfer for these requests.
2021 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2024 // Set the transfer length.
2027 Srb
->DataTransferLength
= BufferLength
;
2033 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
2036 // Set completion routine
2037 IoSetCompletionRoutine(
2039 ClassCompletionRoutine
,
2046 // Get next stack location.
2049 irpStack
= IoGetNextIrpStackLocation(irp
);
2051 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2052 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2055 // Set up SRB for execute scsi request. Save SRB address in next stack
2056 // for the port driver.
2059 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2062 // Set up IRP Address.
2065 Srb
->OriginalRequest
= irp
;
2068 // Call the port driver with the request and wait for it to complete.
2071 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2073 if (status
== STATUS_PENDING
) {
2074 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2078 // Check that request completed without error.
2081 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2084 // Release the queue if it is frozen.
2087 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2088 ScsiClassReleaseQueue(DeviceObject
);
2092 // Update status and determine if request should be retried.
2095 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2099 MAXIMUM_RETRIES
- retryCount
,
2104 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2105 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2106 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2108 LARGE_INTEGER delay
;
2111 // Delay for 2 seconds.
2114 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2117 // Stall for a while to let the controller spinup.
2120 KeDelayExecutionThread(KernelMode
,
2127 // If retries are not exhausted then retry this operation.
2137 status
= STATUS_SUCCESS
;
2140 ExFreePool(senseInfoBuffer
);
2143 } // end ScsiClassSendSrbSynchronous()
2148 ScsiClassInterpretSenseInfo(
2149 IN PDEVICE_OBJECT DeviceObject
,
2150 IN PSCSI_REQUEST_BLOCK Srb
,
2151 IN UCHAR MajorFunctionCode
,
2152 IN ULONG IoDeviceCode
,
2153 IN ULONG RetryCount
,
2154 OUT NTSTATUS
*Status
2159 Routine Description:
2161 This routine interprets the data returned from the SCSI
2162 request sense. It determines the status to return in the
2163 IRP and whether this request can be retried.
2167 DeviceObject - Supplies the device object associated with this request.
2169 Srb - Supplies the scsi request block which failed.
2171 MajorFunctionCode - Supplies the function code to be used for logging.
2173 IoDeviceCode - Supplies the device code to be used for logging.
2175 Status - Returns the status for the request.
2179 BOOLEAN TRUE: Drivers should retry this request.
2180 FALSE: Drivers should not retry this request.
2185 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2186 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2187 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2188 BOOLEAN retry
= TRUE
;
2189 BOOLEAN logError
= FALSE
;
2190 ULONG badSector
= 0;
2195 PIO_ERROR_LOG_PACKET errorLogEntry
;
2200 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
2203 // Check that request sense buffer is valid.
2207 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2208 for (i
= 1; i
< 12; i
++) {
2209 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2211 DebugPrint((3,"\n"));
2214 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2215 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2217 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2218 senseBuffer
->ErrorCode
));
2219 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2220 senseBuffer
->SenseKey
));
2221 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2222 senseBuffer
->AdditionalSenseCode
));
2223 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2224 senseBuffer
->AdditionalSenseCodeQualifier
));
2227 // Zero the additional sense code and additional sense code qualifier
2228 // if they were not returned by the device.
2231 readSector
= senseBuffer
->AdditionalSenseLength
+
2232 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2234 if (readSector
> Srb
->SenseInfoBufferLength
) {
2235 readSector
= Srb
->SenseInfoBufferLength
;
2238 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2239 senseBuffer
->AdditionalSenseCode
= 0;
2242 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2243 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2246 switch (senseBuffer
->SenseKey
& 0xf) {
2248 case SCSI_SENSE_NOT_READY
:
2250 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2251 *Status
= STATUS_DEVICE_NOT_READY
;
2253 switch (senseBuffer
->AdditionalSenseCode
) {
2255 case SCSI_ADSENSE_LUN_NOT_READY
:
2257 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2259 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2261 case SCSI_SENSEQ_BECOMING_READY
:
2263 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2264 " In process of becoming ready\n"));
2267 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2269 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2270 " Manual intervention required\n"));
2271 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2275 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2277 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2281 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2285 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2286 " Initializing command required\n"));
2289 // This sense code/additional sense code
2290 // combination may indicate that the device
2291 // needs to be started. Send an start unit if this
2292 // is a disk device.
2295 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2296 StartUnit(DeviceObject
);
2301 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2305 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2308 "ScsiClassInterpretSenseInfo:"
2309 " No Media in device.\n"));
2310 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2314 // signal autorun that there isn't any media in the device
2317 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2318 (!deviceExtension
->MediaChangeNoMedia
)) {
2319 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2322 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2323 "Detected No Media In Device "
2324 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2325 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2329 } // end switch (senseBuffer->AdditionalSenseCode)
2333 case SCSI_SENSE_DATA_PROTECT
:
2335 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2336 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2340 case SCSI_SENSE_MEDIUM_ERROR
:
2342 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2343 *Status
= STATUS_DEVICE_DATA_ERROR
;
2348 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2351 case SCSI_SENSE_HARDWARE_ERROR
:
2353 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2354 *Status
= STATUS_IO_DEVICE_ERROR
;
2358 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2362 case SCSI_SENSE_ILLEGAL_REQUEST
:
2364 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2365 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2367 switch (senseBuffer
->AdditionalSenseCode
) {
2369 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2370 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2374 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2375 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2376 *Status
= STATUS_NONEXISTENT_SECTOR
;
2380 case SCSI_ADSENSE_INVALID_LUN
:
2381 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2382 *Status
= STATUS_NO_SUCH_DEVICE
;
2386 case SCSI_ADSENSE_MUSIC_AREA
:
2387 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2391 case SCSI_ADSENSE_DATA_AREA
:
2392 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2396 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2397 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2401 case SCSI_ADSENSE_INVALID_CDB
:
2402 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2405 // Check if write cache enabled.
2408 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2411 // Assume FUA is not supported.
2414 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2423 } // end switch (senseBuffer->AdditionalSenseCode)
2427 case SCSI_SENSE_UNIT_ATTENTION
:
2429 switch (senseBuffer
->AdditionalSenseCode
) {
2430 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2431 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2433 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2435 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2438 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2439 "New Media Found - Setting MediaChanged event"
2440 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2441 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2446 case SCSI_ADSENSE_BUS_RESET
:
2447 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2451 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2454 } // end switch (senseBuffer->AdditionalSenseCode)
2456 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2457 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2460 // Set bit to indicate that media may have changed
2461 // and volume needs verification.
2464 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2466 *Status
= STATUS_VERIFY_REQUIRED
;
2471 *Status
= STATUS_IO_DEVICE_ERROR
;
2476 // A media change may have occured so increment the change
2477 // count for the physical device
2480 physicalExtension
->MediaChangeCount
++;
2482 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2483 "count for device %d is %d\n",
2484 physicalExtension
->DeviceNumber
,
2485 physicalExtension
->MediaChangeCount
));
2489 case SCSI_SENSE_ABORTED_COMMAND
:
2491 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2492 *Status
= STATUS_IO_DEVICE_ERROR
;
2495 case SCSI_SENSE_RECOVERED_ERROR
:
2497 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2498 *Status
= STATUS_SUCCESS
;
2503 switch(senseBuffer
->AdditionalSenseCode
) {
2504 case SCSI_ADSENSE_SEEK_ERROR
:
2505 case SCSI_ADSENSE_TRACK_ERROR
:
2506 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2509 case SCSI_ADSENSE_REC_DATA_NOECC
:
2510 case SCSI_ADSENSE_REC_DATA_ECC
:
2511 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2515 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2518 } // end switch(senseBuffer->AdditionalSenseCode)
2520 if (senseBuffer
->IncorrectLength
) {
2522 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2523 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2528 case SCSI_SENSE_NO_SENSE
:
2531 // Check other indicators.
2534 if (senseBuffer
->IncorrectLength
) {
2536 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2537 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2542 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2543 *Status
= STATUS_IO_DEVICE_ERROR
;
2551 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2552 *Status
= STATUS_IO_DEVICE_ERROR
;
2555 } // end switch (senseBuffer->SenseKey & 0xf)
2558 // Try to determine the bad sector from the inquiry data.
2561 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2562 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2563 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2565 for (index
= 0; index
< 4; index
++) {
2566 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2570 for (index
= 0; index
< 4; index
++) {
2571 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2574 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2575 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2578 // Make sure the bad sector is within the read sectors.
2581 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2582 badSector
= readSector
;
2589 // Request sense buffer not valid. No sense information
2590 // to pinpoint the error. Return general request fail.
2593 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2594 SRB_STATUS(Srb
->SrbStatus
)));
2597 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2598 case SRB_STATUS_INVALID_LUN
:
2599 case SRB_STATUS_INVALID_TARGET_ID
:
2600 case SRB_STATUS_NO_DEVICE
:
2601 case SRB_STATUS_NO_HBA
:
2602 case SRB_STATUS_INVALID_PATH_ID
:
2603 *Status
= STATUS_NO_SUCH_DEVICE
;
2607 case SRB_STATUS_COMMAND_TIMEOUT
:
2608 case SRB_STATUS_ABORTED
:
2609 case SRB_STATUS_TIMEOUT
:
2612 // Update the error count for the device.
2615 deviceExtension
->ErrorCount
++;
2616 *Status
= STATUS_IO_TIMEOUT
;
2619 case SRB_STATUS_SELECTION_TIMEOUT
:
2621 logStatus
= 0;//IO_ERR_NOT_READY;
2623 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2627 case SRB_STATUS_DATA_OVERRUN
:
2628 *Status
= STATUS_DATA_OVERRUN
;
2632 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2635 // Update the error count for the device.
2638 deviceExtension
->ErrorCount
++;
2639 *Status
= STATUS_IO_DEVICE_ERROR
;
2642 // If there was phase sequence error then limit the number of
2646 if (RetryCount
> 1 ) {
2652 case SRB_STATUS_REQUEST_FLUSHED
:
2655 // If the status needs verification bit is set. Then set
2656 // the status to need verification and no retry; otherwise,
2657 // just retry the request.
2660 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2662 *Status
= STATUS_VERIFY_REQUIRED
;
2665 *Status
= STATUS_IO_DEVICE_ERROR
;
2670 case SRB_STATUS_INVALID_REQUEST
:
2673 // An invalid request was attempted.
2676 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2680 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2681 case SRB_STATUS_PARITY_ERROR
:
2684 // Update the error count for the device.
2687 deviceExtension
->ErrorCount
++;
2690 // Fall through to below.
2693 case SRB_STATUS_BUS_RESET
:
2694 *Status
= STATUS_IO_DEVICE_ERROR
;
2697 case SRB_STATUS_ERROR
:
2699 *Status
= STATUS_IO_DEVICE_ERROR
;
2700 if (Srb
->ScsiStatus
== 0) {
2703 // This is some strange return code. Update the error
2704 // count for the device.
2707 deviceExtension
->ErrorCount
++;
2709 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2711 *Status
= STATUS_DEVICE_NOT_READY
;
2713 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2715 *Status
= STATUS_DEVICE_BUSY
;
2724 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2726 *Status
= STATUS_IO_DEVICE_ERROR
;
2732 // If the error count has exceeded the error limit, then disable
2733 // any tagged queuing, multiple requests per lu queueing
2734 // and synchronous data transfers.
2737 if (deviceExtension
->ErrorCount
== 4) {
2740 // Clearing the no queue freeze flag prevents the port driver
2741 // from sending multiple requests per logical unit.
2744 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2745 SRB_FLAGS_NO_QUEUE_FREEZE
);
2747 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2748 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2750 } else if (deviceExtension
->ErrorCount
== 8) {
2753 // If a second threshold is reached, disable disconnects.
2756 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
2757 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2762 // If there is a class specific error handler call it.
2765 if (deviceExtension
->ClassError
!= NULL
) {
2767 deviceExtension
->ClassError(DeviceObject
,
2774 // Log an error if necessary.
2779 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
2781 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
2783 if (errorLogEntry
== NULL
) {
2786 // Return if no packet could be allocated.
2793 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
2794 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
2796 errorLogEntry
->FinalStatus
= *Status
;
2800 // Calculate the device offset if there is a geometry.
2803 if (deviceExtension
->DiskGeometry
!= NULL
) {
2805 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
2806 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
2807 errorLogEntry
->DeviceOffset
,
2808 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
2811 errorLogEntry
->ErrorCode
= logStatus
;
2812 errorLogEntry
->SequenceNumber
= 0;
2813 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
2814 errorLogEntry
->IoControlCode
= IoDeviceCode
;
2815 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
2816 errorLogEntry
->UniqueErrorValue
= uniqueId
;
2817 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
2818 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
2819 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
2820 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
2821 errorLogEntry
->DumpData
[3] = 0;
2822 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
2824 if (senseBuffer
!= NULL
) {
2825 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
2826 senseBuffer
->AdditionalSenseCode
<< 8 |
2827 senseBuffer
->AdditionalSenseCodeQualifier
;
2832 // Write the error log packet.
2835 IoWriteErrorLogEntry(errorLogEntry
);
2840 } // end ScsiClassInterpretSenseInfo()
2846 PDEVICE_OBJECT DeviceObject
,
2848 PSCSI_REQUEST_BLOCK Srb
,
2854 Routine Description:
2856 This routine reinitializes the necessary fields, and sends the request
2861 DeviceObject - Supplies the device object associated with this request.
2863 Irp - Supplies the request to be retried.
2865 Srb - Supplies a Pointer to the SCSI request block to be retied.
2867 Associated - Indicates this is an associated Irp created by split request.
2876 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2877 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2878 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2879 ULONG transferByteCount
;
2881 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
2884 // Determine the transfer count of the request. If this is a read or a
2885 // write then the transfer count is in the Irp stack. Otherwise assume
2886 // the MDL contains the correct length. If there is no MDL then the
2887 // transfer length must be zero.
2890 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
2891 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
2893 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2895 } else if (Irp
->MdlAddress
!= NULL
) {
2898 // Note this assumes that only read and write requests are spilt and
2899 // other request do not need to be. If the data buffer address in
2900 // the MDL and the SRB don't match then transfer length is most
2901 // likely incorrect.
2904 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2905 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
2909 transferByteCount
= 0;
2913 // Reset byte count of transfer in SRB Extension.
2916 Srb
->DataTransferLength
= transferByteCount
;
2919 // Zero SRB statuses.
2922 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
2925 // Set the no disconnect flag, disable synchronous data transfers and
2926 // disable tagged queuing. This fixes some errors.
2929 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
2930 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2932 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
2933 Srb
->QueueTag
= SP_UNTAGGED
;
2936 // Set up major SCSI function.
2939 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2942 // Save SRB address in next stack for port driver.
2945 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
2948 // Set up IoCompletion routine address.
2953 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
2957 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
2961 // Pass the request to the port driver.
2964 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2966 } // end RetryRequest()
2970 ScsiClassBuildRequest(
2971 PDEVICE_OBJECT DeviceObject
,
2977 Routine Description:
2979 This routine allocates and builds an Srb for a read or write request.
2980 The block address and length are supplied by the Irp. The retry count
2981 is stored in the current stack for use by ScsiClassIoComplete which
2982 processes these requests when they complete. The Irp is ready to be
2983 passed to the port driver when this routine returns.
2987 DeviceObject - Supplies the device object associated with this request.
2989 Irp - Supplies the request to be retried.
2993 If the IRP is for a disk transfer, the byteoffset field
2994 will already have been adjusted to make it relative to
2995 the beginning of the disk.
3005 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3006 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3007 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3008 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3009 PSCSI_REQUEST_BLOCK srb
;
3011 ULONG logicalBlockAddress
;
3012 USHORT transferBlocks
;
3014 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3017 // Calculate relative sector address.
3020 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
3026 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
3031 // Write length to SRB.
3034 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3037 // Set up IRP Address.
3040 srb
->OriginalRequest
= Irp
;
3043 // Set up target ID and logical unit number.
3046 srb
->PathId
= deviceExtension
->PathId
;
3047 srb
->TargetId
= deviceExtension
->TargetId
;
3048 srb
->Lun
= deviceExtension
->Lun
;
3049 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3050 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3053 // Save byte count of transfer in SRB Extension.
3056 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3059 // Initialize the queue actions field.
3062 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3065 // Queue sort key is Relative Block Address.
3068 srb
->QueueSortKey
= logicalBlockAddress
;
3071 // Indicate auto request sense by specifying buffer and size.
3074 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3075 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3078 // Set timeout value of one unit per 64k bytes of data.
3081 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3082 deviceExtension
->TimeOutValue
;
3088 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3092 // Indicate that 10-byte CDB's will be used.
3095 srb
->CdbLength
= 10;
3098 // Fill in CDB fields.
3101 cdb
= (PCDB
)srb
->Cdb
;
3104 // Zero 12 bytes for Atapi Packets
3107 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3109 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3110 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3113 // Move little endian values into CDB in big endian format.
3116 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3117 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3118 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3119 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3121 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3122 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3125 // Set transfer direction flag and Cdb command.
3128 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3130 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3132 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3133 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3137 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3139 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3140 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3144 // If this is not a write-through request, then allow caching.
3147 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3149 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3154 // If write caching is enable then force media access in the
3158 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3159 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3164 // Or in the default flags from the device object.
3167 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3170 // Set up major SCSI function.
3173 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3176 // Save SRB address in next stack for port driver.
3179 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3182 // Save retry count in current IRP stack.
3185 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3188 // Set up IoCompletion routine address.
3191 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3195 } // end ScsiClassBuildRequest()
3200 IN PDEVICE_OBJECT DeviceObject
,
3201 IN PCHAR ModeSenseBuffer
,
3208 Routine Description:
3210 This routine sends a mode sense command to a target ID and returns
3211 when it is complete.
3215 DeviceObject - Supplies the device object associated with this request.
3217 ModeSenseBuffer - Supplies a buffer to store the sense data.
3219 Length - Supplies the length in bytes of the mode sense buffer.
3221 PageMode - Supplies the page or pages of mode sense data to be retrieved.
3225 Length of the transferred data is returned.
3229 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3231 SCSI_REQUEST_BLOCK srb
;
3235 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3237 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3240 // Build the MODE SENSE CDB.
3244 cdb
= (PCDB
)srb
.Cdb
;
3247 // Set timeout value from device extension.
3250 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3252 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3253 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3254 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3258 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3265 if (status
== STATUS_VERIFY_REQUIRED
) {
3268 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3269 // this status. MODE SENSE commands should be retried anyway.
3281 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3282 status
= STATUS_SUCCESS
;
3285 if (NT_SUCCESS(status
)) {
3286 return(srb
.DataTransferLength
);
3291 } // end ScsiClassModeSense()
3296 ScsiClassFindModePage(
3297 IN PCHAR ModeSenseBuffer
,
3305 Routine Description:
3307 This routine scans through the mode sense data and finds the requested
3308 mode sense page code.
3311 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3313 Length - Indicates the length of valid data.
3315 PageMode - Supplies the page mode to be searched for.
3317 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3321 A pointer to the the requested mode page. If the mode page was not found
3322 then NULL is return.
3327 ULONG parameterHeaderLength
;
3329 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3330 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3334 // Skip the mode select header and block descriptors.
3337 if (Length
< parameterHeaderLength
) {
3343 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3344 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3347 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3348 // requested page until the limit is reached.
3352 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3354 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3355 return(ModeSenseBuffer
);
3359 // Advance to the next page.
3362 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3370 ScsiClassSendSrbAsynchronous(
3371 PDEVICE_OBJECT DeviceObject
,
3372 PSCSI_REQUEST_BLOCK Srb
,
3374 PVOID BufferAddress
,
3376 BOOLEAN WriteToDevice
3380 Routine Description:
3382 This routine takes a partially built Srb and an Irp and sends it down to
3386 DeviceObject - Supplies the device object for the original request.
3388 Srb - Supplies a partially built ScsiRequestBlock. In particular, the
3389 CDB and the SRB timeout value must be filled in. The SRB must not be
3390 allocated from zone.
3392 Irp - Supplies the requesting Irp.
3394 BufferAddress - Supplies a pointer to the buffer to be transfered.
3396 BufferLength - Supplies the length of data transfer.
3398 WriteToDevice - Indicates the data transfer will be from system memory to
3403 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3408 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3409 PIO_STACK_LOCATION irpStack
;
3413 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3416 // Write length to SRB.
3419 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3422 // Set SCSI bus address.
3425 Srb
->PathId
= deviceExtension
->PathId
;
3426 Srb
->TargetId
= deviceExtension
->TargetId
;
3427 Srb
->Lun
= deviceExtension
->Lun
;
3429 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3432 // This is a violation of the SCSI spec but it is required for
3436 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3439 // Indicate auto request sense by specifying buffer and size.
3442 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3443 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3444 Srb
->DataBuffer
= BufferAddress
;
3446 if (BufferAddress
!= NULL
) {
3449 // Build Mdl if necessary.
3452 if (Irp
->MdlAddress
== NULL
) {
3454 if (IoAllocateMdl(BufferAddress
,
3460 return(STATUS_INSUFFICIENT_RESOURCES
);
3463 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3468 // Make sure the buffer requested matches the MDL.
3471 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3478 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3486 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3490 // Disable synchronous transfer for these requests.
3493 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3496 // Set the transfer length.
3499 Srb
->DataTransferLength
= BufferLength
;
3505 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3510 // Save a few parameters in the current stack location.
3513 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3516 // Save retry count in current Irp stack.
3519 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3522 // Set up IoCompletion routine address.
3525 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3528 // Get next stack location and
3529 // set major function code.
3532 irpStack
= IoGetNextIrpStackLocation(Irp
);
3534 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3537 // Save SRB address in next stack for port driver.
3540 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3543 // Set up Irp Address.
3546 Srb
->OriginalRequest
= Irp
;
3549 // Call the port driver to process the request.
3552 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3559 ScsiClassDeviceControlDispatch(
3560 PDEVICE_OBJECT DeviceObject
,
3566 Routine Description:
3568 The routine is the common class driver device control dispatch entry point.
3569 This routine is invokes the device-specific drivers DeviceControl routine,
3570 (which may call the Class driver's common DeviceControl routine).
3574 DeviceObject - Supplies a pointer to the device object for this request.
3576 Irp - Supplies the Irp making the request.
3580 Returns the status returned from the device-specific driver.
3586 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3588 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3591 // Call the class specific driver DeviceControl routine.
3592 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3595 ASSERT(deviceExtension
->ClassDeviceControl
);
3597 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3603 ScsiClassDeviceControl(
3604 PDEVICE_OBJECT DeviceObject
,
3609 Routine Description:
3611 The routine is the common class driver device control dispatch function.
3612 This routine is called by a class driver when it get an unrecognized
3613 device control request. This routine will perform the correct action for
3614 common requests such as lock media. If the device request is unknown it
3615 passed down to the next level.
3619 DeviceObject - Supplies a pointer to the device object for this request.
3621 Irp - Supplies the Irp making the request.
3625 Returns back a STATUS_PENDING or a completion status.
3630 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3631 PIO_STACK_LOCATION nextStack
;
3632 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3633 PSCSI_REQUEST_BLOCK srb
;
3636 ULONG modifiedIoControlCode
;
3638 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
3640 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3641 IOCTL_STORAGE_RESET_DEVICE
) {
3643 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3644 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3645 status
= STATUS_UNSUCCESSFUL
;
3646 goto SetStatusAndReturn
;
3650 // If this is a pass through I/O control, set the minor function code
3651 // and device address and pass it to the port driver.
3654 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3655 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3657 PSCSI_PASS_THROUGH scsiPass
;
3659 nextStack
= IoGetNextIrpStackLocation(Irp
);
3662 // Validate the user buffer.
3665 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3667 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3668 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3669 status
= STATUS_INVALID_PARAMETER
;
3670 goto SetStatusAndReturn
;
3674 // Force the SCSI address to the correct value.
3677 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3678 scsiPass
->PathId
= deviceExtension
->PathId
;
3679 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3680 scsiPass
->Lun
= deviceExtension
->Lun
;
3683 // NOTICE: The SCSI-II specification indicates that this field
3684 // should be zero; however, some target controllers ignore the logical
3685 // unit number in the IDENTIFY message and only look at the logical
3686 // unit number field in the CDB.
3689 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3691 nextStack
->Parameters
= irpStack
->Parameters
;
3692 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3693 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3695 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3696 goto SetStatusAndReturn
;
3699 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3701 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3703 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3704 sizeof(SCSI_ADDRESS
)) {
3707 // Indicate unsuccessful status and no data transferred.
3710 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3711 Irp
->IoStatus
.Information
= 0;
3712 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3713 status
= STATUS_BUFFER_TOO_SMALL
;
3714 goto SetStatusAndReturn
;
3718 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3719 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3720 scsiAddress
->PathId
= deviceExtension
->PathId
;
3721 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3722 scsiAddress
->Lun
= deviceExtension
->Lun
;
3723 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3724 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3725 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3726 status
= STATUS_SUCCESS
;
3727 goto SetStatusAndReturn
;
3730 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
) {
3733 Irp
->IoStatus
.Information
= 0;
3734 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
3735 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3736 status
= STATUS_NOT_IMPLEMENTED
;
3737 goto SetStatusAndReturn
;
3740 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
) {
3744 // This is a HACK. We don't have unique ID.
3745 // We'll just return device name as unique ID.
3746 // It's unique but may not survive to a reboot,
3747 // which is not matching the requirements for
3748 // a MountMgr unique ID.
3751 PMOUNTDEV_UNIQUE_ID uniqueId
= Irp
->AssociatedIrp
.SystemBuffer
;
3754 // Check output buffer is big enough.
3757 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTDEV_UNIQUE_ID
)) {
3759 Irp
->IoStatus
.Information
= 0;
3760 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3761 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3762 status
= STATUS_INVALID_PARAMETER
;
3763 goto SetStatusAndReturn
;
3767 // Set size we'll return so that caller can allocate big enough buffer.
3770 RtlZeroMemory(uniqueId
, sizeof(MOUNTDEV_UNIQUE_ID
));
3771 uniqueId
->UniqueIdLength
= deviceExtension
->DeviceName
.Length
;
3774 // Check buffer is big enough to contain device name.
3777 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< FIELD_OFFSET(MOUNTDEV_UNIQUE_ID
, UniqueId
) + uniqueId
->UniqueIdLength
) {
3779 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_UNIQUE_ID
);
3780 Irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
3781 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3782 status
= STATUS_BUFFER_OVERFLOW
;
3783 goto SetStatusAndReturn
;
3787 // Copy device name.
3790 RtlCopyMemory(uniqueId
->UniqueId
, deviceExtension
->DeviceName
.Buffer
,
3791 uniqueId
->UniqueIdLength
);
3792 status
= STATUS_SUCCESS
;
3795 // And return to the caller.
3798 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3799 Irp
->IoStatus
.Information
= FIELD_OFFSET(MOUNTDEV_UNIQUE_ID
, UniqueId
) + uniqueId
->UniqueIdLength
;
3800 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3801 goto SetStatusAndReturn
;
3804 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
) {
3806 PMOUNTDEV_NAME name
= Irp
->AssociatedIrp
.SystemBuffer
;
3808 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTDEV_NAME
)) {
3810 Irp
->IoStatus
.Information
= 0;
3811 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3812 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3813 status
= STATUS_INVALID_PARAMETER
;
3814 goto SetStatusAndReturn
;
3817 RtlZeroMemory(name
, sizeof(MOUNTDEV_NAME
));
3818 name
->NameLength
= deviceExtension
->DeviceName
.Length
;
3820 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< FIELD_OFFSET(MOUNTDEV_NAME
, Name
) + name
->NameLength
) {
3822 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_NAME
);
3823 Irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
3824 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3825 status
= STATUS_BUFFER_OVERFLOW
;
3826 goto SetStatusAndReturn
;
3829 RtlCopyMemory(name
->Name
, deviceExtension
->DeviceName
.Buffer
,
3831 status
= STATUS_SUCCESS
;
3832 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3833 Irp
->IoStatus
.Information
= FIELD_OFFSET(MOUNTDEV_NAME
, Name
) + name
->NameLength
;
3834 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3835 goto SetStatusAndReturn
;
3838 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3842 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3843 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3844 status
= STATUS_INSUFFICIENT_RESOURCES
;
3845 goto SetStatusAndReturn
;
3849 // Write zeros to Srb.
3852 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3854 cdb
= (PCDB
)srb
->Cdb
;
3857 // Change the device type to disk for the switch statement.
3860 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3861 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3863 switch (modifiedIoControlCode
) {
3865 case IOCTL_DISK_CHECK_VERIFY
: {
3868 PIO_STACK_LOCATION newStack
;
3870 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3873 // If a buffer for a media change count was provided, make sure it's
3874 // big enough to hold the result
3877 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
3880 // If the buffer is too small to hold the media change count
3881 // then return an error to the caller
3884 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3887 DebugPrint((3,"ScsiDeviceIoControl: media count "
3888 "buffer too small\n"));
3890 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3891 Irp
->IoStatus
.Information
= 0;
3893 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3894 status
= STATUS_BUFFER_TOO_SMALL
;
3895 goto SetStatusAndReturn
;
3900 // The caller has provided a valid buffer. Allocate an additional
3901 // irp and stick the CheckVerify completion routine on it. We will
3902 // then send this down to the port driver instead of the irp the
3906 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
3910 // Allocate a new irp to send the TestUnitReady to the port driver
3913 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
3916 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3917 Irp
->IoStatus
.Information
= 0;
3919 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3920 status
= STATUS_INSUFFICIENT_RESOURCES
;
3921 goto SetStatusAndReturn
;
3924 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
3925 IoSetNextIrpStackLocation(irp2
);
3928 // Set the top stack location and shove the master Irp into the
3932 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3933 newStack
->Parameters
.Others
.Argument1
= Irp
;
3934 newStack
->DeviceObject
= DeviceObject
;
3937 // Stick the check verify completion routine onto the stack
3938 // and prepare the irp for the port driver
3941 IoSetCompletionRoutine(irp2
,
3942 ScsiClassCheckVerifyComplete
,
3948 IoSetNextIrpStackLocation(irp2
);
3949 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3950 newStack
->DeviceObject
= DeviceObject
;
3953 // Mark the master irp as pending - whether the lower level
3954 // driver completes it immediately or not this should allow it
3955 // to go all the way back up.
3958 IoMarkIrpPending(Irp
);
3969 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
3972 // Set timeout value.
3975 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3978 // Since this routine will always hand the request to the
3979 // port driver if there isn't a data transfer to be done
3980 // we don't have to worry about completing the request here
3984 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3994 case IOCTL_DISK_MEDIA_REMOVAL
: {
3996 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
3999 // Prevent/Allow media removal.
4002 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4004 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
4005 sizeof(PREVENT_MEDIA_REMOVAL
)) {
4008 // Indicate unsuccessful status and no data transferred.
4011 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
4012 Irp
->IoStatus
.Information
= 0;
4014 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4015 status
= STATUS_BUFFER_TOO_SMALL
;
4016 goto SetStatusAndReturn
;
4020 // Get physical device extension. This is where the
4021 // lock count is stored.
4024 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
4027 // If command succeeded then increment or decrement lock counter.
4030 if (MediaRemoval
->PreventMediaRemoval
) {
4033 // This is a lock command. Reissue the command in case bus or device
4034 // was reset and lock cleared.
4037 InterlockedIncrement(&deviceExtension
->LockCount
);
4040 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4041 deviceExtension
->LockCount
,
4042 deviceExtension
->DeviceNumber
));
4047 // This is an unlock command.
4050 if (!deviceExtension
->LockCount
||
4051 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
4054 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4055 deviceExtension
->LockCount
,
4056 deviceExtension
->DeviceNumber
));
4059 // Don't unlock because someone still wants it locked.
4062 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4064 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4065 status
= STATUS_SUCCESS
;
4066 goto SetStatusAndReturn
;
4070 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4071 deviceExtension
->LockCount
,
4072 deviceExtension
->DeviceNumber
));
4077 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
4080 // TRUE - prevent media removal.
4081 // FALSE - allow media removal.
4084 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
4087 // Set timeout value.
4090 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4091 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4099 // Some devices will not support lock/unlock.
4100 // Pretend that it worked.
4106 case IOCTL_DISK_RESERVE
: {
4109 // Reserve logical unit.
4114 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
4117 // Set timeout value.
4120 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4122 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4132 case IOCTL_DISK_RELEASE
: {
4135 // Release logical unit.
4140 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
4143 // Set timeout value.
4146 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4148 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4158 case IOCTL_DISK_EJECT_MEDIA
: {
4166 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4167 cdb
->START_STOP
.LoadEject
= 1;
4168 cdb
->START_STOP
.Start
= 0;
4171 // Set timeout value.
4174 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4175 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4184 case IOCTL_DISK_LOAD_MEDIA
: {
4190 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4194 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4195 cdb
->START_STOP
.LoadEject
= 1;
4196 cdb
->START_STOP
.Start
= 1;
4199 // Set timeout value.
4202 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4203 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4213 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4216 // Search for devices that have been powered on since the last
4217 // device search or system initialization.
4220 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4221 status
= DriverEntry(DeviceObject
->DriverObject
,
4224 Irp
->IoStatus
.Status
= status
;
4226 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4233 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4236 // Pass the device control to the next driver.
4242 // Copy the Irp stack parameters to the next stack location.
4245 nextStack
= IoGetNextIrpStackLocation(Irp
);
4246 nextStack
->Parameters
= irpStack
->Parameters
;
4247 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4248 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4250 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4254 } // end switch( ...
4264 ScsiClassShutdownFlush(
4265 IN PDEVICE_OBJECT DeviceObject
,
4271 Routine Description:
4273 This routine is called for a shutdown and flush IRPs. These are sent by the
4274 system before it actually shuts down or when the file system does a flush.
4275 If it exists, the device-specific driver's routine will be invoked. If there
4276 wasn't one specified, the Irp will be completed with an Invalid device request.
4280 DriverObject - Pointer to device object to being shutdown by system.
4291 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4293 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4295 if (deviceExtension
->ClassShutdownFlush
) {
4298 // Call the device-specific driver's routine.
4301 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4305 // Device-specific driver doesn't support this.
4308 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4309 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4311 return STATUS_INVALID_DEVICE_REQUEST
;
4317 ScsiClassFindUnclaimedDevices(
4318 IN PCLASS_INIT_DATA InitializationData
,
4319 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4323 ULONG scsiBus
,deviceCount
= 0;
4324 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4325 PSCSI_INQUIRY_DATA lunInfo
;
4326 PINQUIRYDATA inquiryData
;
4328 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4331 // Get the SCSI bus scan data for this bus.
4334 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4337 // Search list for unclaimed disk devices.
4340 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4342 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4344 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4346 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4351 if (lunInfo
->NextInquiryDataOffset
== 0) {
4355 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4365 ScsiClassCreateDeviceObject(
4366 IN PDRIVER_OBJECT DriverObject
,
4367 IN PCCHAR ObjectNameBuffer
,
4368 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4369 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4370 IN PCLASS_INIT_DATA InitializationData
4375 Routine Description:
4377 This routine creates an object for the physical device specified and
4378 sets up the deviceExtension's function pointers for each entry point
4379 in the device-specific driver.
4383 DriverObject - Pointer to driver object created by system.
4385 ObjectNameBuffer - Dir. name of the object to create.
4387 PhysicalDeviceObject - Pointer to the physical (class) device object for
4388 this logical unit or NULL if this is it.
4390 DeviceObject - Pointer to the device object pointer we will return.
4392 InitializationData - Pointer to the init data created by the device-specific driver.
4401 STRING ntNameString
;
4402 UNICODE_STRING ntUnicodeString
;
4404 PDEVICE_OBJECT deviceObject
= NULL
;
4406 *DeviceObject
= NULL
;
4409 "ScsiClassCreateDeviceObject: Create device object %s\n",
4412 RtlInitString(&ntNameString
,
4415 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4419 if (!NT_SUCCESS(status
)) {
4422 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4425 ntUnicodeString
.Buffer
= NULL
;
4429 status
= IoCreateDevice(DriverObject
,
4430 InitializationData
->DeviceExtensionSize
,
4432 InitializationData
->DeviceType
,
4433 InitializationData
->DeviceCharacteristics
,
4438 if (!NT_SUCCESS(status
)) {
4441 "CreateDiskDeviceObjects: Can not create device object %s\n",
4446 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4448 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4451 // Fill in entry points
4454 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4455 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4456 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4457 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4458 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4459 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4460 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4462 deviceExtension
->MediaChangeCount
= 0;
4465 // If a pointer to the physical device object was passed in then use
4466 // that. If the value was NULL, then this is the physical device so
4467 // use the pointer to the device we just created.
4470 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4471 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4473 deviceExtension
->PhysicalDevice
= deviceObject
;
4476 deviceExtension
->DeviceName
= ntUnicodeString
;
4479 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4481 *DeviceObject
= deviceObject
;
4489 ScsiClassClaimDevice(
4490 IN PDEVICE_OBJECT PortDeviceObject
,
4491 IN PSCSI_INQUIRY_DATA LunInfo
,
4493 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4497 Routine Description:
4499 This function claims a device in the port driver. The port driver object
4500 is updated with the correct driver object if the device is successfully
4505 PortDeviceObject - Supplies the base port device object.
4507 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4509 Release - Indicates the logical unit should be released rather than claimed.
4511 NewPortDeviceObject - Returns the updated port device object to be used
4512 for all future accesses.
4516 Returns a status indicating success or failure of the operation.
4521 IO_STATUS_BLOCK ioStatus
;
4523 PIO_STACK_LOCATION irpStack
;
4526 SCSI_REQUEST_BLOCK srb
;
4530 if (NewPortDeviceObject
!= NULL
) {
4531 *NewPortDeviceObject
= NULL
;
4535 // Clear the SRB fields.
4538 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4541 // Write length to SRB.
4544 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4547 // Set SCSI bus address.
4550 srb
.PathId
= LunInfo
->PathId
;
4551 srb
.TargetId
= LunInfo
->TargetId
;
4552 srb
.Lun
= LunInfo
->Lun
;
4554 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4555 SRB_FUNCTION_CLAIM_DEVICE
;
4558 // Set the event object to the unsignaled state.
4559 // It will be used to signal request completion.
4562 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4565 // Build synchronous request with no transfer.
4568 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4580 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4581 return STATUS_INSUFFICIENT_RESOURCES
;
4584 irpStack
= IoGetNextIrpStackLocation(irp
);
4587 // Save SRB address in next stack for port driver.
4590 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4593 // Set up IRP Address.
4596 srb
.OriginalRequest
= irp
;
4599 // Call the port driver with the request and wait for it to complete.
4602 status
= IoCallDriver(PortDeviceObject
, irp
);
4603 if (status
== STATUS_PENDING
) {
4605 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4606 status
= ioStatus
.Status
;
4610 // If this is a release request, then just decrement the reference count
4611 // and return. The status does not matter.
4616 //ObDereferenceObject(PortDeviceObject);
4617 return STATUS_SUCCESS
;
4620 if (!NT_SUCCESS(status
)) {
4624 ASSERT(srb
.DataBuffer
!= NULL
);
4627 // Reference the new port driver object so that it will not go away while
4628 // it is being used.
4631 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4636 if (!NT_SUCCESS(status
)) {
4640 ObDereferenceObject(srb
.DataBuffer
);
4643 // Return the new port device object pointer.
4646 if (NewPortDeviceObject
!= NULL
) {
4647 *NewPortDeviceObject
= srb
.DataBuffer
;
4656 ScsiClassInternalIoControl (
4657 IN PDEVICE_OBJECT DeviceObject
,
4663 Routine Description:
4665 This routine passes internal device controls to the port driver.
4666 Internal device controls are used by higher level class drivers to
4667 send scsi requests to a device that are not normally sent by a generic
4670 The path ID, target ID and logical unit ID are set in the srb so the
4671 higher level driver does not have to figure out what values are actually
4676 DeviceObject - Supplies a pointer to the device object for this request.
4678 Irp - Supplies the Irp making the request.
4682 Returns back a STATUS_PENDING or a completion status.
4686 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4687 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4688 PSCSI_REQUEST_BLOCK srb
;
4690 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4693 // Get a pointer to the SRB.
4696 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4699 // Set SCSI bus address.
4702 srb
->PathId
= deviceExtension
->PathId
;
4703 srb
->TargetId
= deviceExtension
->TargetId
;
4704 srb
->Lun
= deviceExtension
->Lun
;
4707 // NOTICE: The SCSI-II specification indicates that this field should be
4708 // zero; however, some target controllers ignore the logical unit number
4709 // in the IDENTIFY message and only look at the logical unit number field
4713 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4716 // Set the parameters in the next stack location.
4719 irpStack
= IoGetNextIrpStackLocation(Irp
);
4721 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4722 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4723 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4725 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4726 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4732 IN PDEVICE_OBJECT DeviceObject
,
4739 Routine Description:
4741 This routine is called when an internal device control I/O request
4742 has completed. It marks the IRP pending if necessary and returns the
4743 status of the request.
4747 DeviceObject - Target device object.
4749 Irp - Completed request.
4755 Returns the status of the completed request.
4760 UNREFERENCED_PARAMETER(Context
);
4761 UNREFERENCED_PARAMETER(DeviceObject
);
4764 // If pending is returned for this Irp then mark current stack
4768 if (Irp
->PendingReturned
) {
4770 IoMarkIrpPending( Irp
);
4773 return Irp
->IoStatus
.Status
;
4779 ScsiClassInitializeSrbLookasideList(
4780 IN PDEVICE_EXTENSION DeviceExtension
,
4781 IN ULONG NumberElements
4786 Routine Description:
4788 This routine sets up a lookaside listhead for srbs.
4792 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4794 NumberElements - Supplies the maximum depth of the lookaside list.
4804 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4807 NonPagedPoolMustSucceed
,
4808 SCSI_REQUEST_BLOCK_SIZE
,
4810 (USHORT
)NumberElements
);
4817 ScsiClassQueryTimeOutRegistryValue(
4818 IN PUNICODE_STRING RegistryPath
4823 Routine Description:
4825 This routine determines whether a reg key for a user-specified timeout value exists.
4829 RegistryPath - Pointer to the hardware reg. entry describing the key.
4833 New default timeout for a class of devices.
4839 // Find the appropriate reg. key
4842 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4849 if (!RegistryPath
) {
4853 parameters
= ExAllocatePool(NonPagedPool
,
4854 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4860 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4861 path
= ExAllocatePool(NonPagedPool
, size
);
4864 ExFreePool(parameters
);
4868 RtlZeroMemory(path
,size
);
4869 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
4873 // Check for the Timeout value.
4876 RtlZeroMemory(parameters
,
4877 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
4879 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
4880 parameters
[0].Name
= L
"TimeOutValue";
4881 parameters
[0].EntryContext
= &timeOut
;
4882 parameters
[0].DefaultType
= REG_DWORD
;
4883 parameters
[0].DefaultData
= &zero
;
4884 parameters
[0].DefaultLength
= sizeof(ULONG
);
4886 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
4892 if (!(NT_SUCCESS(status
))) {
4896 ExFreePool(parameters
);
4900 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
4910 ScsiClassCheckVerifyComplete(
4911 IN PDEVICE_OBJECT DeviceObject
,
4918 Routine Description:
4920 This routine executes when the port driver has completed a check verify
4921 ioctl. It will set the status of the master Irp, copy the media change
4922 count and complete the request.
4926 DeviceObject - Supplies the device object which represents the logical
4929 Irp - Supplies the Irp which has completed.
4940 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4941 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4942 PDEVICE_EXTENSION physicalExtension
=
4943 deviceExtension
->PhysicalDevice
->DeviceExtension
;
4946 ASSERT(*(PULONG
)deviceExtension
!= '2slc');
4947 ASSERT(*(PULONG
)physicalExtension
!= '2slc');
4949 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
4952 // Copy the media change count and status
4955 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
4956 physicalExtension
->MediaChangeCount
;
4958 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
4959 "device %d is %d\n",
4960 physicalExtension
->DeviceNumber
,
4961 physicalExtension
->MediaChangeCount
));
4963 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
4964 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
4966 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
4970 return STATUS_MORE_PROCESSING_REQUIRED
;
4975 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
4979 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
4980 PKEVENT Event
= Irp
->UserEvent
;
4983 *IoStatusBlock
= Irp
->IoStatus
;
4984 Irp
->UserIosb
= NULL
;
4985 Irp
->UserEvent
= NULL
;
4989 Mdl
= Irp
->MdlAddress
;
4991 // if necessary - unlock pages
4992 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
4993 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
5002 // free irp and set event to unsignaled state
5004 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
5006 return STATUS_MORE_PROCESSING_REQUIRED
;