2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/class2/class2.c
5 * PURPOSE: SCSI Class driver routines
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
12 #include <include/class2.h>
19 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
20 #pragma alloc_text(PAGE, ScsiClassInitialize)
21 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
22 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
23 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
24 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
28 #define INQUIRY_DATA_SIZE 2048
29 #define START_UNIT_TIMEOUT 30
31 /* Disk layout used by Windows NT4 and earlier versions. */
32 //#define DEFAULT_SECTORS_PER_TRACK 32
33 //#define DEFAULT_TRACKS_PER_CYLINDER 64
35 /* Disk layout used by Windows 2000 and later versions. */
36 #define DEFAULT_SECTORS_PER_TRACK 63
37 #define DEFAULT_TRACKS_PER_CYLINDER 255
42 IN PDEVICE_OBJECT DeviceObject
,
49 IN PDEVICE_OBJECT DeviceObject
,
55 ScsiClassDeviceControlDispatch(
56 PDEVICE_OBJECT DeviceObject
,
62 ScsiClassDeviceControl(
63 PDEVICE_OBJECT DeviceObject
,
69 ScsiClassInternalIoControl (
70 IN PDEVICE_OBJECT DeviceObject
,
76 ScsiClassShutdownFlush(
77 IN PDEVICE_OBJECT DeviceObject
,
84 IN PDRIVER_OBJECT DriverObject
,
85 IN PUNICODE_STRING RegistryPath
89 // Class internal routines
96 PDEVICE_OBJECT DeviceObject
,
98 PSCSI_REQUEST_BLOCK Srb
,
105 IN PDEVICE_OBJECT DeviceObject
111 IN PDEVICE_OBJECT DeviceObject
,
118 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
126 IN PDRIVER_OBJECT DriverObject
,
127 IN PUNICODE_STRING RegistryPath
130 return STATUS_SUCCESS
;
139 IN PCLASS_INIT_DATA InitializationData
146 This routine is called by a class driver during its
147 DriverEntry routine to initialize the driver.
151 Argument1 - Driver Object.
152 Argument2 - Registry Path.
153 InitializationData - Device-specific driver's initialization data.
157 A valid return code for a DriverEntry routine.
164 PDRIVER_OBJECT DriverObject
= Argument1
;
165 ULONG portNumber
= 0;
166 PDEVICE_OBJECT portDeviceObject
;
168 STRING deviceNameString
;
169 UNICODE_STRING unicodeDeviceName
;
170 PFILE_OBJECT fileObject
;
171 CCHAR deviceNameBuffer
[256];
172 BOOLEAN deviceFound
= FALSE
;
174 DebugPrint((3,"\n\nSCSI Class Driver\n"));
177 // Validate the length of this structure. This is effectively a
181 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
183 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
184 return (ULONG
) STATUS_REVISION_MISMATCH
;
188 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
189 // are not required entry points.
192 if ((!InitializationData
->ClassFindDevices
) ||
193 (!InitializationData
->ClassDeviceControl
) ||
194 (!((InitializationData
->ClassReadWriteVerification
) ||
195 (InitializationData
->ClassStartIo
)))) {
198 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
200 return (ULONG
) STATUS_REVISION_MISMATCH
;
204 // Update driver object with entry points.
207 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
208 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
209 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
210 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
211 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
212 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
213 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
214 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
216 if (InitializationData
->ClassStartIo
) {
217 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
221 // Open port driver controller device objects by name.
226 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", portNumber
);
228 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
230 RtlInitString(&deviceNameString
, deviceNameBuffer
);
232 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
236 if (!NT_SUCCESS(status
)){
240 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
241 FILE_READ_ATTRIBUTES
,
245 if (NT_SUCCESS(status
)) {
248 // Call the device-specific driver's FindDevice routine.
251 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
252 portDeviceObject
, portNumber
)) {
259 // Check next SCSI adapter.
264 } while(NT_SUCCESS(status
));
266 return deviceFound
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
272 ScsiClassCreateClose(
273 IN PDEVICE_OBJECT DeviceObject
,
281 SCSI class driver create and close routine. This is called by the I/O system
282 when the device is opened or closed.
286 DriverObject - Pointer to driver object created by system.
292 Device-specific drivers return value or STATUS_SUCCESS.
297 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
300 // Invoke the device-specific routine, if one exists. Otherwise complete
304 if (deviceExtension
->ClassCreateClose
) {
306 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
309 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
311 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
312 return(STATUS_SUCCESS
);
321 IN PDEVICE_OBJECT DeviceObject
,
329 This is the system entry point for read and write requests. The device-specific handler is invoked
330 to perform any validation necessary. The number of bytes in the request are
331 checked against the maximum byte counts that the adapter supports and requests are broken up into
332 smaller sizes if necessary.
346 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
347 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
349 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
350 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
353 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
354 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
357 // if DO_VERIFY_VOLUME bit is set
358 // in device object flags, fail request.
361 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
363 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
364 Irp
->IoStatus
.Information
= 0;
366 IoCompleteRequest(Irp
, 0);
367 return STATUS_VERIFY_REQUIRED
;
371 // Invoke the device specific routine to do whatever it needs to verify
375 ASSERT(deviceExtension
->ClassReadWriteVerification
);
377 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
379 if (!NT_SUCCESS(status
)) {
382 // It is up to the device specific driver to set the Irp status.
385 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
387 } else if (status
== STATUS_PENDING
) {
389 IoMarkIrpPending(Irp
);
390 return STATUS_PENDING
;
394 // Check for a zero length IO, as several macros will turn this into
395 // seemingly a 0xffffffff length request.
398 if (transferByteCount
== 0) {
399 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
400 Irp
->IoStatus
.Information
= 0;
401 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
402 return STATUS_SUCCESS
;
406 if (deviceExtension
->ClassStartIo
) {
408 IoMarkIrpPending(Irp
);
410 IoStartPacket(DeviceObject
,
415 return STATUS_PENDING
;
419 // Mark IRP with status pending.
422 IoMarkIrpPending(Irp
);
425 // Add partition byte offset to make starting byte relative to
426 // beginning of disk. In addition, add in skew for DM Driver, if any.
429 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
430 deviceExtension
->DMByteSkew
);
433 // Calculate number of pages in this transfer.
436 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
437 currentIrpStack
->Parameters
.Read
.Length
);
440 // Check if request length is greater than the maximum number of
441 // bytes that the hardware can transfer.
444 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
445 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
447 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
448 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
449 maximumTransferLength
));
450 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
451 currentIrpStack
->Parameters
.Read
.Length
));
454 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
456 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
457 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
461 // Check that maximum transfer size is not zero.
464 if (maximumTransferLength
== 0) {
465 maximumTransferLength
= PAGE_SIZE
;
469 // Mark IRP with status pending.
472 IoMarkIrpPending(Irp
);
475 // Request greater than port driver maximum.
476 // Break up into smaller routines.
479 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
482 return STATUS_PENDING
;
486 // Build SRB and CDB for this IRP.
489 ScsiClassBuildRequest(DeviceObject
, Irp
);
492 // Return the results of the call to the port driver.
495 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
497 } // end ScsiClassReadWrite()
502 ScsiClassGetCapabilities(
503 IN PDEVICE_OBJECT PortDeviceObject
,
504 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
511 This routine builds and sends a request to the port driver to
512 get a pointer to a structure that describes the adapter's
513 capabilities/limitations. This routine is sychronous.
517 PortDeviceObject - Port driver device object representing the HBA.
519 PortCapabilities - Location to store pointer to capabilities structure.
523 Nt status indicating the results of the operation.
527 This routine should only be called at initialization time.
533 IO_STATUS_BLOCK ioStatus
;
540 // Create notification event object to be used to signal the
541 // request completion.
544 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
547 // Build the synchronous request to be sent to the port driver
548 // to perform the request.
551 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
562 return STATUS_INSUFFICIENT_RESOURCES
;
566 // Pass request to port driver and wait for request to complete.
569 status
= IoCallDriver(PortDeviceObject
, irp
);
571 if (status
== STATUS_PENDING
) {
572 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
573 return(ioStatus
.Status
);
578 } // end ScsiClassGetCapabilities()
583 ScsiClassGetInquiryData(
584 IN PDEVICE_OBJECT PortDeviceObject
,
585 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
592 This routine sends a request to a port driver to return
593 configuration information. Space for the information is
594 allocated by this routine. The caller is responsible for
595 freeing the configuration information. This routine is
600 PortDeviceObject - Port driver device object representing the HBA.
602 ConfigInfo - Returns a pointer to the configuration information.
606 Nt status indicating the results of the operation.
610 This routine should be called only at initialization time.
616 IO_STATUS_BLOCK ioStatus
;
619 PSCSI_ADAPTER_BUS_INFO buffer
;
623 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
624 *ConfigInfo
= buffer
;
626 if (buffer
== NULL
) {
627 return(STATUS_INSUFFICIENT_RESOURCES
);
631 // Create notification event object to be used to signal the inquiry
632 // request completion.
635 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
638 // Build the synchronous request to be sent to the port driver
639 // to perform the inquiries.
642 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
653 return(STATUS_INSUFFICIENT_RESOURCES
);
657 // Pass request to port driver and wait for request to complete.
660 status
= IoCallDriver(PortDeviceObject
, irp
);
662 if (status
== STATUS_PENDING
) {
663 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
664 status
= ioStatus
.Status
;
667 if (!NT_SUCCESS(status
)) {
670 // Free the buffer on an error.
680 } // end ScsiClassGetInquiryData()
685 ScsiClassReadDriveCapacity(
686 IN PDEVICE_OBJECT DeviceObject
693 This routine sends a READ CAPACITY to the requested device, updates
694 the geometry information in the device object and returns
695 when it is complete. This routine is synchronous.
699 DeviceObject - Supplies a pointer to the device object that represents
700 the device whose capacity is to be read.
708 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
712 PREAD_CAPACITY_DATA readCapacityBuffer
;
713 SCSI_REQUEST_BLOCK srb
;
717 // Allocate read capacity buffer from nonpaged pool.
720 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
721 sizeof(READ_CAPACITY_DATA
));
723 if (!readCapacityBuffer
) {
724 return(STATUS_INSUFFICIENT_RESOURCES
);
727 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
730 // Build the read capacity CDB.
737 // Set timeout value from device extension.
740 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
742 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
746 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
749 sizeof(READ_CAPACITY_DATA
),
752 if (NT_SUCCESS(status
)) {
755 // Copy sector size from read capacity buffer to device extension
756 // in reverse byte order.
759 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
760 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
762 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
763 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
765 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
766 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
768 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
769 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
772 // Copy last sector in reverse byte order.
775 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
776 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
778 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
779 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
781 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
782 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
784 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
785 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
788 // Calculate sector to byte shift.
791 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
793 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
794 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
796 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
800 // Calculate media capacity in bytes.
803 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
806 // Calculate number of cylinders.
809 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(DEFAULT_SECTORS_PER_TRACK
* DEFAULT_TRACKS_PER_CYLINDER
));
811 deviceExtension
->PartitionLength
.QuadPart
=
812 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
814 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
817 // This device supports removable media.
820 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
825 // Assume media type is fixed disk.
828 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
832 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
835 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= DEFAULT_SECTORS_PER_TRACK
;
838 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
841 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= DEFAULT_TRACKS_PER_CYLINDER
;
844 if (status
== STATUS_VERIFY_REQUIRED
) {
847 // Routine ScsiClassSendSrbSynchronous does not retry
848 // requests returned with this status.
849 // Read Capacities should be retried
863 if (!NT_SUCCESS(status
)) {
866 // If the read capacity fails, set the geometry to reasonable parameter
867 // so things don't fail at unexpected places. Zero the geometry
868 // except for the bytes per sector and sector shift.
871 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
872 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
873 deviceExtension
->SectorShift
= 9;
874 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
876 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
879 // This device supports removable media.
882 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
887 // Assume media type is fixed disk.
890 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
895 // Deallocate read capacity buffer.
898 ExFreePool(readCapacityBuffer
);
902 } // end ScsiClassReadDriveCapacity()
907 ScsiClassReleaseQueue(
908 IN PDEVICE_OBJECT DeviceObject
915 This routine issues an internal device control command
916 to the port driver to release a frozen queue. The call
917 is issued asynchronously as ScsiClassReleaseQueue will be invoked
918 from the IO completion DPC (and will have no context to
919 wait for a synchronous call to complete).
923 DeviceObject - The device object for the logical unit with
932 PIO_STACK_LOCATION irpStack
;
934 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
935 PCOMPLETION_CONTEXT context
;
936 PSCSI_REQUEST_BLOCK srb
;
940 // Allocate context from nonpaged pool.
943 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
944 sizeof(COMPLETION_CONTEXT
));
947 // Save the device object in the context for use by the completion
951 context
->DeviceObject
= DeviceObject
;
958 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
961 // Write length to SRB.
964 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
967 // Set up SCSI bus address.
970 srb
->PathId
= deviceExtension
->PathId
;
971 srb
->TargetId
= deviceExtension
->TargetId
;
972 srb
->Lun
= deviceExtension
->Lun
;
975 // If this device is removable then flush the queue. This will also
979 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
981 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
985 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
990 // Build the asynchronous request to be sent to the port driver.
993 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
998 // We have no better way of dealing with this at the moment
1001 KeBugCheck((ULONG
)0x0000002DL
);
1005 IoSetCompletionRoutine(irp
,
1006 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1012 irpStack
= IoGetNextIrpStackLocation(irp
);
1014 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1016 srb
->OriginalRequest
= irp
;
1019 // Store the SRB address in next stack for port driver.
1022 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1025 // Since this routine can cause outstanding requests to be completed, and
1026 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1027 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1028 // issuing the request
1031 currentIrql
= KeGetCurrentIrql();
1033 if(currentIrql
< DISPATCH_LEVEL
) {
1034 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1035 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1036 KeLowerIrql(currentIrql
);
1038 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1043 } // end ScsiClassReleaseQueue()
1049 IN PDEVICE_OBJECT DeviceObject
1054 Routine Description:
1056 Send command to SCSI unit to start or power up.
1057 Because this command is issued asynchronounsly, that is, without
1058 waiting on it to complete, the IMMEDIATE flag is not set. This
1059 means that the CDB will not return until the drive has powered up.
1060 This should keep subsequent requests from being submitted to the
1061 device before it has completely spun up.
1062 This routine is called from the InterpretSense routine, when a
1063 request sense returns data indicating that a drive must be
1068 DeviceObject - The device object for the logical unit with
1077 PIO_STACK_LOCATION irpStack
;
1079 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1080 PSCSI_REQUEST_BLOCK srb
;
1081 PCOMPLETION_CONTEXT context
;
1085 // Allocate Srb from nonpaged pool.
1088 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1089 sizeof(COMPLETION_CONTEXT
));
1092 // Save the device object in the context for use by the completion
1096 context
->DeviceObject
= DeviceObject
;
1097 srb
= &context
->Srb
;
1103 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1106 // Write length to SRB.
1109 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1112 // Set up SCSI bus address.
1115 srb
->PathId
= deviceExtension
->PathId
;
1116 srb
->TargetId
= deviceExtension
->TargetId
;
1117 srb
->Lun
= deviceExtension
->Lun
;
1119 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1122 // Set timeout value large enough for drive to spin up.
1125 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1128 // Set the transfer length.
1131 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1134 // Build the start unit CDB.
1138 cdb
= (PCDB
)srb
->Cdb
;
1140 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1141 cdb
->START_STOP
.Start
= 1;
1142 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1145 // Build the asynchronous request to be sent to the port driver.
1146 // Since this routine is called from a DPC the IRP should always be
1150 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1151 IoSetCompletionRoutine(irp
,
1152 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1158 irpStack
= IoGetNextIrpStackLocation(irp
);
1159 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1160 srb
->OriginalRequest
= irp
;
1163 // Store the SRB address in next stack for port driver.
1166 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1169 // Call the port driver with the IRP.
1172 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1176 } // end StartUnit()
1181 ScsiClassAsynchronousCompletion(
1182 PDEVICE_OBJECT DeviceObject
,
1188 Routine Description:
1190 This routine is called when an asynchronous I/O request
1191 which was issused by the class driver completes. Examples of such requests
1192 are release queue or START UNIT. This routine releases the queue if
1193 necessary. It then frees the context and the IRP.
1197 DeviceObject - The device object for the logical unit; however since this
1198 is the top stack location the value is NULL.
1200 Irp - Supplies a pointer to the Irp to be processed.
1202 Context - Supplies the context to be used to process this request.
1211 PCOMPLETION_CONTEXT context
= Context
;
1212 PSCSI_REQUEST_BLOCK srb
;
1214 srb
= &context
->Srb
;
1217 // If this is an execute srb, then check the return status and make sure.
1218 // the queue is not frozen.
1221 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1224 // Check for a frozen queue.
1227 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1230 // Unfreeze the queue getting the device object from the context.
1233 ScsiClassReleaseQueue(context
->DeviceObject
);
1238 // Free the context and the Irp.
1241 if (Irp
->MdlAddress
!= NULL
) {
1242 MmUnlockPages(Irp
->MdlAddress
);
1243 IoFreeMdl(Irp
->MdlAddress
);
1245 Irp
->MdlAddress
= NULL
;
1248 ExFreePool(context
);
1252 // Indicate the I/O system should stop processing the Irp completion.
1255 return STATUS_MORE_PROCESSING_REQUIRED
;
1257 } // ScsiClassAsynchronousCompletion()
1262 ScsiClassSplitRequest(
1263 IN PDEVICE_OBJECT DeviceObject
,
1265 IN ULONG MaximumBytes
1270 Routine Description:
1272 Break request into smaller requests. Each new request will be the
1273 maximum transfer size that the port driver can handle or if it
1274 is the final request, it may be the residual size.
1276 The number of IRPs required to process this request is written in the
1277 current stack of the original IRP. Then as each new IRP completes
1278 the count in the original IRP is decremented. When the count goes to
1279 zero, the original IRP is completed.
1283 DeviceObject - Pointer to the class device object to be addressed.
1285 Irp - Pointer to Irp the orginal request.
1294 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1295 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1296 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1297 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1298 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1299 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1300 ULONG dataLength
= MaximumBytes
;
1301 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1303 PSCSI_REQUEST_BLOCK srb
;
1305 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1306 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1309 // If all partial transfers complete successfully then the status and
1310 // bytes transferred are already set up. Failing a partial-transfer IRP
1311 // will set status to error and bytes transferred to 0 during
1312 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1313 // asynchronous partial transfers. This is an optimization for the
1317 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1318 Irp
->IoStatus
.Information
= transferByteCount
;
1321 // Save number of IRPs to complete count on current stack
1325 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1327 for (i
= 0; i
< irpCount
; i
++) {
1330 PIO_STACK_LOCATION newIrpStack
;
1333 // Allocate new IRP.
1336 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1338 if (newIrp
== NULL
) {
1340 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1343 // If an Irp can't be allocated then the orginal request cannot
1344 // be executed. If this is the first request then just fail the
1345 // orginal request; otherwise just return. When the pending
1346 // requests complete, they will complete the original request.
1347 // In either case set the IRP status to failure.
1350 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1351 Irp
->IoStatus
.Information
= 0;
1354 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1360 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1363 // Write MDL address to new IRP. In the port driver the SRB data
1364 // buffer field is used as an offset into the MDL, so the same MDL
1365 // can be used for each partial transfer. This saves having to build
1366 // a new MDL for each partial transfer.
1369 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1372 // At this point there is no current stack. IoSetNextIrpStackLocation
1373 // will make the first stack location the current stack so that the
1374 // SRB address can be written there.
1377 IoSetNextIrpStackLocation(newIrp
);
1378 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1380 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1381 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1382 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1383 newIrpStack
->DeviceObject
= DeviceObject
;
1386 // Build SRB and CDB.
1389 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1392 // Adjust SRB for this partial transfer.
1395 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1397 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1398 srb
->DataBuffer
= dataBuffer
;
1401 // Write original IRP address to new IRP.
1404 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1407 // Set the completion routine to ScsiClassIoCompleteAssociated.
1410 IoSetCompletionRoutine(newIrp
,
1411 ScsiClassIoCompleteAssociated
,
1418 // Call port driver with new request.
1421 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1424 // Set up for next request.
1427 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1429 transferByteCount
-= MaximumBytes
;
1431 if (transferByteCount
> MaximumBytes
) {
1433 dataLength
= MaximumBytes
;
1437 dataLength
= transferByteCount
;
1441 // Adjust disk byte offset.
1444 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1449 } // end ScsiClassSplitRequest()
1454 ScsiClassIoComplete(
1455 IN PDEVICE_OBJECT DeviceObject
,
1462 Routine Description:
1464 This routine executes when the port driver has completed a request.
1465 It looks at the SRB status in the completing SRB and if not success
1466 it checks for valid request sense buffer information. If valid, the
1467 info is used to update status with more precise message of type of
1468 error. This routine deallocates the SRB.
1472 DeviceObject - Supplies the device object which represents the logical
1475 Irp - Supplies the Irp which has completed.
1477 Context - Supplies a pointer to the SRB.
1486 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1487 PSCSI_REQUEST_BLOCK srb
= Context
;
1488 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1493 // Check SRB status for success of completing request.
1496 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1498 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1501 // Release the queue if it is frozen.
1504 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1505 ScsiClassReleaseQueue(DeviceObject
);
1508 retry
= ScsiClassInterpretSenseInfo(
1511 irpStack
->MajorFunction
,
1512 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1513 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1517 // If the status is verified required and the this request
1518 // should bypass verify required then retry the request.
1521 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1522 status
== STATUS_VERIFY_REQUIRED
) {
1524 status
= STATUS_IO_DEVICE_ERROR
;
1528 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1534 DebugPrint((1, "Retry request %lx\n", Irp
));
1535 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1536 return STATUS_MORE_PROCESSING_REQUIRED
;
1541 // Set status for successful request.
1544 status
= STATUS_SUCCESS
;
1546 } // end if (SRB_STATUS(srb->SrbStatus) ...
1549 // Return SRB to list.
1552 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1556 // Set status in completing IRP.
1559 Irp
->IoStatus
.Status
= status
;
1560 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1561 ASSERT(Irp
->IoStatus
.Information
);
1565 // Set the hard error if necessary.
1568 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1571 // Store DeviceObject for filesystem, and clear
1572 // in IoStatus.Information field.
1575 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1576 Irp
->IoStatus
.Information
= 0;
1580 // If pending has be returned for this irp then mark the current stack as
1584 if (Irp
->PendingReturned
) {
1585 IoMarkIrpPending(Irp
);
1588 if (deviceExtension
->ClassStartIo
) {
1589 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1590 IoStartNextPacket(DeviceObject
, FALSE
);
1596 } // end ScsiClassIoComplete()
1601 ScsiClassIoCompleteAssociated(
1602 IN PDEVICE_OBJECT DeviceObject
,
1609 Routine Description:
1611 This routine executes when the port driver has completed a request.
1612 It looks at the SRB status in the completing SRB and if not success
1613 it checks for valid request sense buffer information. If valid, the
1614 info is used to update status with more precise message of type of
1615 error. This routine deallocates the SRB. This routine is used for
1616 requests which were build by split request. After it has processed
1617 the request it decrements the Irp count in the master Irp. If the
1618 count goes to zero then the master Irp is completed.
1622 DeviceObject - Supplies the device object which represents the logical
1625 Irp - Supplies the Irp which has completed.
1627 Context - Supplies a pointer to the SRB.
1636 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1637 PSCSI_REQUEST_BLOCK srb
= Context
;
1638 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1639 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1645 // Check SRB status for success of completing request.
1648 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1650 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1653 // Release the queue if it is frozen.
1656 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1657 ScsiClassReleaseQueue(DeviceObject
);
1660 retry
= ScsiClassInterpretSenseInfo(
1663 irpStack
->MajorFunction
,
1664 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1665 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1669 // If the status is verified required and the this request
1670 // should bypass verify required then retry the request.
1673 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1674 status
== STATUS_VERIFY_REQUIRED
) {
1676 status
= STATUS_IO_DEVICE_ERROR
;
1680 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1683 // Retry request. If the class driver has supplied a StartIo,
1684 // call it directly for retries.
1687 DebugPrint((1, "Retry request %lx\n", Irp
));
1690 if (!deviceExtension->ClassStartIo) {
1691 RetryRequest(DeviceObject, Irp, srb, TRUE);
1693 deviceExtension->ClassStartIo(DeviceObject, Irp);
1697 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1699 return STATUS_MORE_PROCESSING_REQUIRED
;
1707 // Set status for successful request.
1710 status
= STATUS_SUCCESS
;
1712 } // end if (SRB_STATUS(srb->SrbStatus) ...
1715 // Return SRB to list.
1718 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1722 // Set status in completing IRP.
1725 Irp
->IoStatus
.Status
= status
;
1727 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
1730 // Get next stack location. This original request is unused
1731 // except to keep track of the completing partial IRPs so the
1732 // stack location is valid.
1735 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
1738 // Update status only if error so that if any partial transfer
1739 // completes with error, then the original IRP will return with
1740 // error. If any of the asynchronous partial transfer IRPs fail,
1741 // with an error then the original IRP will return 0 bytes transfered.
1742 // This is an optimization for successful transfers.
1745 if (!NT_SUCCESS(status
)) {
1747 originalIrp
->IoStatus
.Status
= status
;
1748 originalIrp
->IoStatus
.Information
= 0;
1751 // Set the hard error if necessary.
1754 if (IoIsErrorUserInduced(status
)) {
1757 // Store DeviceObject for filesystem.
1760 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
1765 // Decrement and get the count of remaining IRPs.
1768 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
1770 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
1774 // Old bug could cause irp count to negative
1777 ASSERT(irpCount
>= 0);
1779 if (irpCount
== 0) {
1782 // All partial IRPs have completed.
1786 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
1789 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
1792 // If the class driver has supplied a startio, start the
1796 if (deviceExtension
->ClassStartIo
) {
1797 IoStartNextPacket(DeviceObject
, FALSE
);
1802 // Deallocate IRP and indicate the I/O system should not attempt any more
1807 return STATUS_MORE_PROCESSING_REQUIRED
;
1809 } // end ScsiClassIoCompleteAssociated()
1814 ScsiClassSendSrbSynchronous(
1815 PDEVICE_OBJECT DeviceObject
,
1816 PSCSI_REQUEST_BLOCK Srb
,
1817 PVOID BufferAddress
,
1819 BOOLEAN WriteToDevice
1824 Routine Description:
1826 This routine is called by SCSI device controls to complete an
1827 SRB and send it to the port driver synchronously (ie wait for
1828 completion). The CDB is already completed along with the SRB CDB
1829 size and request timeout value.
1833 DeviceObject - Supplies the device object which represents the logical
1836 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
1838 BufferAddress - Supplies the address of the buffer.
1840 BufferLength - Supplies the length in bytes of the buffer.
1842 WriteToDevice - Indicates the data should be transfer to the device.
1846 Nt status indicating the final results of the operation.
1851 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1852 IO_STATUS_BLOCK ioStatus
;
1853 ULONG controlType
, mjFunction
;
1855 PIO_STACK_LOCATION irpStack
;
1857 PUCHAR senseInfoBuffer
;
1858 ULONG retryCount
= MAXIMUM_RETRIES
;
1861 LARGE_INTEGER dummy
;
1868 // Write length to SRB.
1871 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1874 // Set SCSI bus address.
1877 Srb
->PathId
= deviceExtension
->PathId
;
1878 Srb
->TargetId
= deviceExtension
->TargetId
;
1879 Srb
->Lun
= deviceExtension
->Lun
;
1880 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1883 // NOTICE: The SCSI-II specification indicates that this field should be
1884 // zero; however, some target controllers ignore the logical unit number
1885 // in the INDENTIFY message and only look at the logical unit number field
1889 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1892 // Enable auto request sense.
1895 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1898 // Sense buffer is in aligned nonpaged pool.
1901 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1903 if (senseInfoBuffer
== NULL
) {
1906 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
1907 return(STATUS_INSUFFICIENT_RESOURCES
);
1910 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
1911 Srb
->DataBuffer
= BufferAddress
;
1914 // Start retries here.
1920 // Set the event object to the unsignaled state.
1921 // It will be used to signal request completion.
1924 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1927 // Set controlType and Srb direction flags.
1930 if (BufferAddress
!= NULL
) {
1932 if (WriteToDevice
) {
1934 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
1935 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
1936 mjFunction
= IRP_MJ_WRITE
;
1940 controlType
= IOCTL_SCSI_EXECUTE_IN
;
1941 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
1942 mjFunction
= IRP_MJ_READ
;
1948 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
1949 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1950 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
1954 // Build device I/O control request with data transfer.
1956 irp
= IoBuildAsynchronousFsdRequest(
1958 deviceExtension
->DeviceObject
,
1960 (BufferAddress
) ? BufferLength
: 0,
1965 ExFreePool(senseInfoBuffer
);
1966 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
1967 return(STATUS_INSUFFICIENT_RESOURCES
);
1971 irp
->UserEvent
= &event
;
1974 // Disable synchronous transfer for these requests.
1977 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1980 // Set the transfer length.
1983 Srb
->DataTransferLength
= BufferLength
;
1989 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
1992 // Set completion routine
1993 IoSetCompletionRoutine(
1995 ClassCompletionRoutine
,
2002 // Get next stack location.
2005 irpStack
= IoGetNextIrpStackLocation(irp
);
2007 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2008 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2011 // Set up SRB for execute scsi request. Save SRB address in next stack
2012 // for the port driver.
2015 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2018 // Set up IRP Address.
2021 Srb
->OriginalRequest
= irp
;
2024 // Call the port driver with the request and wait for it to complete.
2027 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2029 if (status
== STATUS_PENDING
) {
2030 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2034 // Check that request completed without error.
2037 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2040 // Release the queue if it is frozen.
2043 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2044 ScsiClassReleaseQueue(DeviceObject
);
2048 // Update status and determine if request should be retried.
2051 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2055 MAXIMUM_RETRIES
- retryCount
,
2060 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2061 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2062 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2064 LARGE_INTEGER delay
;
2067 // Delay for 2 seconds.
2070 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2073 // Stall for a while to let the controller spinup.
2076 KeDelayExecutionThread(KernelMode
,
2083 // If retries are not exhausted then retry this operation.
2093 status
= STATUS_SUCCESS
;
2096 ExFreePool(senseInfoBuffer
);
2099 } // end ScsiClassSendSrbSynchronous()
2104 ScsiClassInterpretSenseInfo(
2105 IN PDEVICE_OBJECT DeviceObject
,
2106 IN PSCSI_REQUEST_BLOCK Srb
,
2107 IN UCHAR MajorFunctionCode
,
2108 IN ULONG IoDeviceCode
,
2109 IN ULONG RetryCount
,
2110 OUT NTSTATUS
*Status
2115 Routine Description:
2117 This routine interprets the data returned from the SCSI
2118 request sense. It determines the status to return in the
2119 IRP and whether this request can be retried.
2123 DeviceObject - Supplies the device object associated with this request.
2125 Srb - Supplies the scsi request block which failed.
2127 MajorFunctionCode - Supplies the function code to be used for logging.
2129 IoDeviceCode - Supplies the device code to be used for logging.
2131 Status - Returns the status for the request.
2135 BOOLEAN TRUE: Drivers should retry this request.
2136 FALSE: Drivers should not retry this request.
2141 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2142 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2143 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2144 BOOLEAN retry
= TRUE
;
2145 BOOLEAN logError
= FALSE
;
2146 ULONG badSector
= 0;
2151 PIO_ERROR_LOG_PACKET errorLogEntry
;
2158 // Check that request sense buffer is valid.
2162 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2163 for (i
= 1; i
< 12; i
++) {
2164 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2166 DebugPrint((3,"\n"));
2169 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2170 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2172 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2173 senseBuffer
->ErrorCode
));
2174 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2175 senseBuffer
->SenseKey
));
2176 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2177 senseBuffer
->AdditionalSenseCode
));
2178 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2179 senseBuffer
->AdditionalSenseCodeQualifier
));
2182 // Zero the additional sense code and additional sense code qualifier
2183 // if they were not returned by the device.
2186 readSector
= senseBuffer
->AdditionalSenseLength
+
2187 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2189 if (readSector
> Srb
->SenseInfoBufferLength
) {
2190 readSector
= Srb
->SenseInfoBufferLength
;
2193 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2194 senseBuffer
->AdditionalSenseCode
= 0;
2197 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2198 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2201 switch (senseBuffer
->SenseKey
& 0xf) {
2203 case SCSI_SENSE_NOT_READY
:
2205 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2206 *Status
= STATUS_DEVICE_NOT_READY
;
2208 switch (senseBuffer
->AdditionalSenseCode
) {
2210 case SCSI_ADSENSE_LUN_NOT_READY
:
2212 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2214 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2216 case SCSI_SENSEQ_BECOMING_READY
:
2218 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2219 " In process of becoming ready\n"));
2222 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2224 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2225 " Manual intervention required\n"));
2226 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2230 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2232 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2236 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2240 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2241 " Initializing command required\n"));
2244 // This sense code/additional sense code
2245 // combination may indicate that the device
2246 // needs to be started. Send an start unit if this
2247 // is a disk device.
2250 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2251 StartUnit(DeviceObject
);
2256 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2260 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2263 "ScsiClassInterpretSenseInfo:"
2264 " No Media in device.\n"));
2265 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2269 // signal autorun that there isn't any media in the device
2272 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2273 (!deviceExtension
->MediaChangeNoMedia
)) {
2274 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2277 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2278 "Detected No Media In Device "
2279 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2280 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2284 } // end switch (senseBuffer->AdditionalSenseCode)
2288 case SCSI_SENSE_DATA_PROTECT
:
2290 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2291 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2295 case SCSI_SENSE_MEDIUM_ERROR
:
2297 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2298 *Status
= STATUS_DEVICE_DATA_ERROR
;
2303 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2306 case SCSI_SENSE_HARDWARE_ERROR
:
2308 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2309 *Status
= STATUS_IO_DEVICE_ERROR
;
2313 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2317 case SCSI_SENSE_ILLEGAL_REQUEST
:
2319 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2320 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2322 switch (senseBuffer
->AdditionalSenseCode
) {
2324 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2325 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2329 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2330 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2331 *Status
= STATUS_NONEXISTENT_SECTOR
;
2335 case SCSI_ADSENSE_INVALID_LUN
:
2336 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2337 *Status
= STATUS_NO_SUCH_DEVICE
;
2341 case SCSI_ADSENSE_MUSIC_AREA
:
2342 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2346 case SCSI_ADSENSE_DATA_AREA
:
2347 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2351 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2352 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2356 case SCSI_ADSENSE_INVALID_CDB
:
2357 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2360 // Check if write cache enabled.
2363 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2366 // Assume FUA is not supported.
2369 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2378 } // end switch (senseBuffer->AdditionalSenseCode)
2382 case SCSI_SENSE_UNIT_ATTENTION
:
2384 switch (senseBuffer
->AdditionalSenseCode
) {
2385 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2386 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2388 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2390 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2393 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2394 "New Media Found - Setting MediaChanged event"
2395 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2396 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2401 case SCSI_ADSENSE_BUS_RESET
:
2402 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2406 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2409 } // end switch (senseBuffer->AdditionalSenseCode)
2411 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2412 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2415 // Set bit to indicate that media may have changed
2416 // and volume needs verification.
2419 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2421 *Status
= STATUS_VERIFY_REQUIRED
;
2426 *Status
= STATUS_IO_DEVICE_ERROR
;
2431 // A media change may have occured so increment the change
2432 // count for the physical device
2435 physicalExtension
->MediaChangeCount
++;
2437 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2438 "count for device %d is %d\n",
2439 physicalExtension
->DeviceNumber
,
2440 physicalExtension
->MediaChangeCount
));
2444 case SCSI_SENSE_ABORTED_COMMAND
:
2446 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2447 *Status
= STATUS_IO_DEVICE_ERROR
;
2450 case SCSI_SENSE_RECOVERED_ERROR
:
2452 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2453 *Status
= STATUS_SUCCESS
;
2458 switch(senseBuffer
->AdditionalSenseCode
) {
2459 case SCSI_ADSENSE_SEEK_ERROR
:
2460 case SCSI_ADSENSE_TRACK_ERROR
:
2461 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2464 case SCSI_ADSENSE_REC_DATA_NOECC
:
2465 case SCSI_ADSENSE_REC_DATA_ECC
:
2466 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2470 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2473 } // end switch(senseBuffer->AdditionalSenseCode)
2475 if (senseBuffer
->IncorrectLength
) {
2477 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2478 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2483 case SCSI_SENSE_NO_SENSE
:
2486 // Check other indicators.
2489 if (senseBuffer
->IncorrectLength
) {
2491 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2492 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2497 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2498 *Status
= STATUS_IO_DEVICE_ERROR
;
2506 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2507 *Status
= STATUS_IO_DEVICE_ERROR
;
2510 } // end switch (senseBuffer->SenseKey & 0xf)
2513 // Try to determine the bad sector from the inquiry data.
2516 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2517 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2518 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2520 for (index
= 0; index
< 4; index
++) {
2521 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2525 for (index
= 0; index
< 4; index
++) {
2526 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2529 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2530 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2533 // Make sure the bad sector is within the read sectors.
2536 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2537 badSector
= readSector
;
2544 // Request sense buffer not valid. No sense information
2545 // to pinpoint the error. Return general request fail.
2548 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2549 SRB_STATUS(Srb
->SrbStatus
)));
2552 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2553 case SRB_STATUS_INVALID_LUN
:
2554 case SRB_STATUS_INVALID_TARGET_ID
:
2555 case SRB_STATUS_NO_DEVICE
:
2556 case SRB_STATUS_NO_HBA
:
2557 case SRB_STATUS_INVALID_PATH_ID
:
2558 *Status
= STATUS_NO_SUCH_DEVICE
;
2562 case SRB_STATUS_COMMAND_TIMEOUT
:
2563 case SRB_STATUS_ABORTED
:
2564 case SRB_STATUS_TIMEOUT
:
2567 // Update the error count for the device.
2570 deviceExtension
->ErrorCount
++;
2571 *Status
= STATUS_IO_TIMEOUT
;
2574 case SRB_STATUS_SELECTION_TIMEOUT
:
2576 logStatus
= 0;//IO_ERR_NOT_READY;
2578 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2582 case SRB_STATUS_DATA_OVERRUN
:
2583 *Status
= STATUS_DATA_OVERRUN
;
2587 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2590 // Update the error count for the device.
2593 deviceExtension
->ErrorCount
++;
2594 *Status
= STATUS_IO_DEVICE_ERROR
;
2597 // If there was phase sequence error then limit the number of
2601 if (RetryCount
> 1 ) {
2607 case SRB_STATUS_REQUEST_FLUSHED
:
2610 // If the status needs verification bit is set. Then set
2611 // the status to need verification and no retry; otherwise,
2612 // just retry the request.
2615 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2617 *Status
= STATUS_VERIFY_REQUIRED
;
2620 *Status
= STATUS_IO_DEVICE_ERROR
;
2625 case SRB_STATUS_INVALID_REQUEST
:
2628 // An invalid request was attempted.
2631 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2635 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2636 case SRB_STATUS_PARITY_ERROR
:
2639 // Update the error count for the device.
2642 deviceExtension
->ErrorCount
++;
2645 // Fall through to below.
2648 case SRB_STATUS_BUS_RESET
:
2649 *Status
= STATUS_IO_DEVICE_ERROR
;
2652 case SRB_STATUS_ERROR
:
2654 *Status
= STATUS_IO_DEVICE_ERROR
;
2655 if (Srb
->ScsiStatus
== 0) {
2658 // This is some strange return code. Update the error
2659 // count for the device.
2662 deviceExtension
->ErrorCount
++;
2664 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2666 *Status
= STATUS_DEVICE_NOT_READY
;
2668 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2670 *Status
= STATUS_DEVICE_BUSY
;
2679 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2681 *Status
= STATUS_IO_DEVICE_ERROR
;
2687 // If the error count has exceeded the error limit, then disable
2688 // any tagged queuing, multiple requests per lu queueing
2689 // and sychronous data transfers.
2692 if (deviceExtension
->ErrorCount
== 4) {
2695 // Clearing the no queue freeze flag prevents the port driver
2696 // from sending multiple requests per logical unit.
2699 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2700 SRB_FLAGS_NO_QUEUE_FREEZE
);
2702 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2703 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2705 } else if (deviceExtension
->ErrorCount
== 8) {
2708 // If a second threshold is reached, disable disconnects.
2711 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
2712 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2717 // If there is a class specific error handler call it.
2720 if (deviceExtension
->ClassError
!= NULL
) {
2722 deviceExtension
->ClassError(DeviceObject
,
2729 // Log an error if necessary.
2734 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
2736 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
2738 if (errorLogEntry
== NULL
) {
2741 // Return if no packet could be allocated.
2748 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
2749 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
2751 errorLogEntry
->FinalStatus
= *Status
;
2755 // Calculate the device offset if there is a geometry.
2758 if (deviceExtension
->DiskGeometry
!= NULL
) {
2760 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
2761 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
2762 errorLogEntry
->DeviceOffset
,
2763 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
2766 errorLogEntry
->ErrorCode
= logStatus
;
2767 errorLogEntry
->SequenceNumber
= 0;
2768 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
2769 errorLogEntry
->IoControlCode
= IoDeviceCode
;
2770 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
2771 errorLogEntry
->UniqueErrorValue
= uniqueId
;
2772 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
2773 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
2774 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
2775 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
2776 errorLogEntry
->DumpData
[3] = 0;
2777 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
2779 if (senseBuffer
!= NULL
) {
2780 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
2781 senseBuffer
->AdditionalSenseCode
<< 8 |
2782 senseBuffer
->AdditionalSenseCodeQualifier
;
2787 // Write the error log packet.
2790 IoWriteErrorLogEntry(errorLogEntry
);
2795 } // end ScsiClassInterpretSenseInfo()
2801 PDEVICE_OBJECT DeviceObject
,
2803 PSCSI_REQUEST_BLOCK Srb
,
2809 Routine Description:
2811 This routine reinitalizes the necessary fields, and sends the request
2816 DeviceObject - Supplies the device object associated with this request.
2818 Irp - Supplies the request to be retried.
2820 Srb - Supplies a Pointer to the SCSI request block to be retied.
2822 Assocaiated - Indicates this is an assocatied Irp created by split request.
2831 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2832 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2833 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2834 ULONG transferByteCount
;
2837 // Determine the transfer count of the request. If this is a read or a
2838 // write then the transfer count is in the Irp stack. Otherwise assume
2839 // the MDL contains the correct length. If there is no MDL then the
2840 // transfer length must be zero.
2843 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
2844 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
2846 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2848 } else if (Irp
->MdlAddress
!= NULL
) {
2851 // Note this assumes that only read and write requests are spilt and
2852 // other request do not need to be. If the data buffer address in
2853 // the MDL and the SRB don't match then transfer length is most
2854 // likely incorrect.
2857 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2858 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
2862 transferByteCount
= 0;
2866 // Reset byte count of transfer in SRB Extension.
2869 Srb
->DataTransferLength
= transferByteCount
;
2872 // Zero SRB statuses.
2875 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
2878 // Set the no disconnect flag, disable synchronous data transfers and
2879 // disable tagged queuing. This fixes some errors.
2882 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
2883 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2885 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
2886 Srb
->QueueTag
= SP_UNTAGGED
;
2889 // Set up major SCSI function.
2892 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2895 // Save SRB address in next stack for port driver.
2898 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
2901 // Set up IoCompletion routine address.
2906 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
2910 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
2914 // Pass the request to the port driver.
2917 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2919 } // end RetryRequest()
2923 ScsiClassBuildRequest(
2924 PDEVICE_OBJECT DeviceObject
,
2930 Routine Description:
2932 This routine allocates and builds an Srb for a read or write request.
2933 The block address and length are supplied by the Irp. The retry count
2934 is stored in the current stack for use by ScsiClassIoComplete which
2935 processes these requests when they complete. The Irp is ready to be
2936 passed to the port driver when this routine returns.
2940 DeviceObject - Supplies the device object associated with this request.
2942 Irp - Supplies the request to be retried.
2946 If the IRP is for a disk transfer, the byteoffset field
2947 will already have been adjusted to make it relative to
2948 the beginning of the disk.
2958 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2959 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2960 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2961 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2962 PSCSI_REQUEST_BLOCK srb
;
2964 ULONG logicalBlockAddress
;
2965 USHORT transferBlocks
;
2968 // Calculate relative sector address.
2971 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
2977 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
2982 // Write length to SRB.
2985 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2988 // Set up IRP Address.
2991 srb
->OriginalRequest
= Irp
;
2994 // Set up target ID and logical unit number.
2997 srb
->PathId
= deviceExtension
->PathId
;
2998 srb
->TargetId
= deviceExtension
->TargetId
;
2999 srb
->Lun
= deviceExtension
->Lun
;
3000 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3001 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
3004 // Save byte count of transfer in SRB Extension.
3007 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3010 // Initialize the queue actions field.
3013 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3016 // Queue sort key is Relative Block Address.
3019 srb
->QueueSortKey
= logicalBlockAddress
;
3022 // Indicate auto request sense by specifying buffer and size.
3025 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3026 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3029 // Set timeout value of one unit per 64k bytes of data.
3032 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3033 deviceExtension
->TimeOutValue
;
3039 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3043 // Indicate that 10-byte CDB's will be used.
3046 srb
->CdbLength
= 10;
3049 // Fill in CDB fields.
3052 cdb
= (PCDB
)srb
->Cdb
;
3055 // Zero 12 bytes for Atapi Packets
3058 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3060 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3061 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3064 // Move little endian values into CDB in big endian format.
3067 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3068 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3069 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3070 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3072 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3073 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3076 // Set transfer direction flag and Cdb command.
3079 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3081 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3083 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3084 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3088 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3090 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3091 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3095 // If this is not a write-through request, then allow caching.
3098 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3100 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3105 // If write caching is enable then force media access in the
3109 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3110 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3115 // Or in the default flags from the device object.
3118 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3121 // Set up major SCSI function.
3124 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3127 // Save SRB address in next stack for port driver.
3130 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3133 // Save retry count in current IRP stack.
3136 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3139 // Set up IoCompletion routine address.
3142 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3146 } // end ScsiClassBuildRequest()
3151 IN PDEVICE_OBJECT DeviceObject
,
3152 IN PCHAR ModeSenseBuffer
,
3159 Routine Description:
3161 This routine sends a mode sense command to a target ID and returns
3162 when it is complete.
3166 DeviceObject - Supplies the device object associated with this request.
3168 ModeSenseBuffer - Supplies a buffer to store the sense data.
3170 Length - Supplies the length in bytes of the mode sense buffer.
3172 PageMode - Supplies the page or pages of mode sense data to be retrived.
3176 Length of the transferred data is returned.
3180 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3182 SCSI_REQUEST_BLOCK srb
;
3186 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3189 // Build the MODE SENSE CDB.
3193 cdb
= (PCDB
)srb
.Cdb
;
3196 // Set timeout value from device extension.
3199 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3201 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3202 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3203 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3207 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3214 if (status
== STATUS_VERIFY_REQUIRED
) {
3217 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3218 // this status. MODE SENSE commands should be retried anyway.
3230 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3231 status
= STATUS_SUCCESS
;
3234 if (NT_SUCCESS(status
)) {
3235 return(srb
.DataTransferLength
);
3240 } // end ScsiClassModeSense()
3245 ScsiClassFindModePage(
3246 IN PCHAR ModeSenseBuffer
,
3254 Routine Description:
3256 This routine scans through the mode sense data and finds the requested
3257 mode sense page code.
3260 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3262 Length - Indicates the length of valid data.
3264 PageMode - Supplies the page mode to be searched for.
3266 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3270 A pointer to the the requested mode page. If the mode page was not found
3271 then NULL is return.
3276 ULONG parameterHeaderLength
;
3278 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3279 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3283 // Skip the mode select header and block descriptors.
3286 if (Length
< parameterHeaderLength
) {
3292 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3293 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3296 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3297 // requested page until the limit is reached.
3301 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3303 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3304 return(ModeSenseBuffer
);
3308 // Advance to the next page.
3311 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3319 ScsiClassSendSrbAsynchronous(
3320 PDEVICE_OBJECT DeviceObject
,
3321 PSCSI_REQUEST_BLOCK Srb
,
3323 PVOID BufferAddress
,
3325 BOOLEAN WriteToDevice
3329 Routine Description:
3331 This routine takes a partially built Srb and an Irp and sends it down to
3335 DeviceObject - Supplies the device object for the orginal request.
3337 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3338 CDB and the SRB timeout value must be filled in. The SRB must not be
3339 allocated from zone.
3341 Irp - Supplies the requesting Irp.
3343 BufferAddress - Supplies a pointer to the buffer to be transfered.
3345 BufferLength - Supplies the length of data transfer.
3347 WriteToDevice - Indicates the data transfer will be from system memory to
3352 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3357 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3358 PIO_STACK_LOCATION irpStack
;
3363 // Write length to SRB.
3366 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3369 // Set SCSI bus address.
3372 Srb
->PathId
= deviceExtension
->PathId
;
3373 Srb
->TargetId
= deviceExtension
->TargetId
;
3374 Srb
->Lun
= deviceExtension
->Lun
;
3376 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3379 // This is a violation of the SCSI spec but it is required for
3383 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3386 // Indicate auto request sense by specifying buffer and size.
3389 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3390 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3391 Srb
->DataBuffer
= BufferAddress
;
3393 if (BufferAddress
!= NULL
) {
3396 // Build Mdl if necessary.
3399 if (Irp
->MdlAddress
== NULL
) {
3401 if (IoAllocateMdl(BufferAddress
,
3407 return(STATUS_INSUFFICIENT_RESOURCES
);
3410 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3415 // Make sure the buffer requested matches the MDL.
3418 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3425 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3433 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3437 // Disable synchronous transfer for these requests.
3440 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3443 // Set the transfer length.
3446 Srb
->DataTransferLength
= BufferLength
;
3452 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3457 // Save a few parameters in the current stack location.
3460 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3463 // Save retry count in current Irp stack.
3466 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3469 // Set up IoCompletion routine address.
3472 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3475 // Get next stack location and
3476 // set major function code.
3479 irpStack
= IoGetNextIrpStackLocation(Irp
);
3481 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3484 // Save SRB address in next stack for port driver.
3487 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3490 // Set up Irp Address.
3493 Srb
->OriginalRequest
= Irp
;
3496 // Call the port driver to process the request.
3499 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3506 ScsiClassDeviceControlDispatch(
3507 PDEVICE_OBJECT DeviceObject
,
3513 Routine Description:
3515 The routine is the common class driver device control dispatch entry point.
3516 This routine is invokes the device-specific drivers DeviceControl routine,
3517 (which may call the Class driver's common DeviceControl routine).
3521 DeviceObject - Supplies a pointer to the device object for this request.
3523 Irp - Supplies the Irp making the request.
3527 Returns the status returned from the device-specific driver.
3533 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3537 // Call the class specific driver DeviceControl routine.
3538 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3541 ASSERT(deviceExtension
->ClassDeviceControl
);
3543 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3549 ScsiClassDeviceControl(
3550 PDEVICE_OBJECT DeviceObject
,
3555 Routine Description:
3557 The routine is the common class driver device control dispatch function.
3558 This routine is called by a class driver when it get an unrecognized
3559 device control request. This routine will perform the correct action for
3560 common requests such as lock media. If the device request is unknown it
3561 passed down to the next level.
3565 DeviceObject - Supplies a pointer to the device object for this request.
3567 Irp - Supplies the Irp making the request.
3571 Returns back a STATUS_PENDING or a completion status.
3576 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3577 PIO_STACK_LOCATION nextStack
;
3578 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3579 PSCSI_REQUEST_BLOCK srb
;
3582 ULONG modifiedIoControlCode
;
3584 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3585 IOCTL_STORAGE_RESET_DEVICE
) {
3587 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3588 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3589 status
= STATUS_UNSUCCESSFUL
;
3590 goto SetStatusAndReturn
;
3594 // If this is a pass through I/O control, set the minor function code
3595 // and device address and pass it to the port driver.
3598 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3599 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3601 PSCSI_PASS_THROUGH scsiPass
;
3603 nextStack
= IoGetNextIrpStackLocation(Irp
);
3606 // Validiate the user buffer.
3609 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3611 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3612 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3613 status
= STATUS_INVALID_PARAMETER
;
3614 goto SetStatusAndReturn
;
3618 // Force the SCSI address to the correct value.
3621 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3622 scsiPass
->PathId
= deviceExtension
->PathId
;
3623 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3624 scsiPass
->Lun
= deviceExtension
->Lun
;
3627 // NOTICE: The SCSI-II specificaiton indicates that this field
3628 // should be zero; however, some target controllers ignore the logical
3629 // unit number in the INDENTIFY message and only look at the logical
3630 // unit number field in the CDB.
3633 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3635 nextStack
->Parameters
= irpStack
->Parameters
;
3636 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3637 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3639 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3640 goto SetStatusAndReturn
;
3643 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3645 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3647 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3648 sizeof(SCSI_ADDRESS
)) {
3651 // Indicate unsuccessful status and no data transferred.
3654 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3655 Irp
->IoStatus
.Information
= 0;
3656 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3657 status
= STATUS_BUFFER_TOO_SMALL
;
3658 goto SetStatusAndReturn
;
3662 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3663 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3664 scsiAddress
->PathId
= deviceExtension
->PathId
;
3665 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3666 scsiAddress
->Lun
= deviceExtension
->Lun
;
3667 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3668 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3669 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3670 status
= STATUS_SUCCESS
;
3671 goto SetStatusAndReturn
;
3674 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3678 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3679 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3680 status
= STATUS_INSUFFICIENT_RESOURCES
;
3681 goto SetStatusAndReturn
;
3685 // Write zeros to Srb.
3688 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3690 cdb
= (PCDB
)srb
->Cdb
;
3693 // Change the device type to disk for the switch statement.
3696 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3697 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3699 switch (modifiedIoControlCode
) {
3701 case IOCTL_DISK_CHECK_VERIFY
: {
3704 PIO_STACK_LOCATION newStack
;
3706 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3709 // If a buffer for a media change count was provided, make sure it's
3710 // big enough to hold the result
3713 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
3716 // If the buffer is too small to hold the media change count
3717 // then return an error to the caller
3720 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3723 DebugPrint((3,"ScsiDeviceIoControl: media count "
3724 "buffer too small\n"));
3726 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3727 Irp
->IoStatus
.Information
= 0;
3729 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3730 status
= STATUS_BUFFER_TOO_SMALL
;
3731 goto SetStatusAndReturn
;
3736 // The caller has provided a valid buffer. Allocate an additional
3737 // irp and stick the CheckVerify completion routine on it. We will
3738 // then send this down to the port driver instead of the irp the
3742 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
3746 // Allocate a new irp to send the TestUnitReady to the port driver
3749 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
3752 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3753 Irp
->IoStatus
.Information
= 0;
3755 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3756 status
= STATUS_INSUFFICIENT_RESOURCES
;
3757 goto SetStatusAndReturn
;
3762 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
3763 IoSetNextIrpStackLocation(irp2
);
3766 // Set the top stack location and shove the master Irp into the
3770 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3771 newStack
->Parameters
.Others
.Argument1
= Irp
;
3772 newStack
->DeviceObject
= DeviceObject
;
3775 // Stick the check verify completion routine onto the stack
3776 // and prepare the irp for the port driver
3779 IoSetCompletionRoutine(irp2
,
3780 ScsiClassCheckVerifyComplete
,
3786 IoSetNextIrpStackLocation(irp2
);
3787 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3788 newStack
->DeviceObject
= DeviceObject
;
3791 // Mark the master irp as pending - whether the lower level
3792 // driver completes it immediately or not this should allow it
3793 // to go all the way back up.
3796 IoMarkIrpPending(Irp
);
3807 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
3810 // Set timeout value.
3813 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3816 // Since this routine will always hand the request to the
3817 // port driver if there isn't a data transfer to be done
3818 // we don't have to worry about completing the request here
3822 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3832 case IOCTL_DISK_MEDIA_REMOVAL
: {
3834 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
3837 // Prevent/Allow media removal.
3840 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
3842 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
3843 sizeof(PREVENT_MEDIA_REMOVAL
)) {
3846 // Indicate unsuccessful status and no data transferred.
3849 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3850 Irp
->IoStatus
.Information
= 0;
3852 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3853 status
= STATUS_BUFFER_TOO_SMALL
;
3854 goto SetStatusAndReturn
;
3858 // Get physical device extension. This is where the
3859 // lock count is stored.
3862 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
3865 // If command succeeded then increment or decrement lock counter.
3868 if (MediaRemoval
->PreventMediaRemoval
) {
3871 // This is a lock command. Reissue the command in case bus or device
3872 // was reset and lock cleared.
3875 InterlockedIncrement(&deviceExtension
->LockCount
);
3878 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
3879 deviceExtension
->LockCount
,
3880 deviceExtension
->DeviceNumber
));
3885 // This is an unlock command.
3888 if (!deviceExtension
->LockCount
||
3889 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
3892 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3893 deviceExtension
->LockCount
,
3894 deviceExtension
->DeviceNumber
));
3897 // Don't unlock because someone still wants it locked.
3900 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3902 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3903 status
= STATUS_SUCCESS
;
3904 goto SetStatusAndReturn
;
3908 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3909 deviceExtension
->LockCount
,
3910 deviceExtension
->DeviceNumber
));
3915 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3918 // TRUE - prevent media removal.
3919 // FALSE - allow media removal.
3922 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
3925 // Set timeout value.
3928 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3929 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3937 // Some devices will not support lock/unlock.
3938 // Pretend that it worked.
3944 case IOCTL_DISK_RESERVE
: {
3947 // Reserve logical unit.
3952 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
3955 // Set timeout value.
3958 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3960 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3970 case IOCTL_DISK_RELEASE
: {
3973 // Release logical unit.
3978 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
3981 // Set timeout value.
3984 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3986 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3996 case IOCTL_DISK_EJECT_MEDIA
: {
4004 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4005 cdb
->START_STOP
.LoadEject
= 1;
4006 cdb
->START_STOP
.Start
= 0;
4009 // Set timeout value.
4012 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4013 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4022 case IOCTL_DISK_LOAD_MEDIA
: {
4028 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4032 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4033 cdb
->START_STOP
.LoadEject
= 1;
4034 cdb
->START_STOP
.Start
= 1;
4037 // Set timeout value.
4040 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4041 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4051 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4054 // Search for devices that have been powered on since the last
4055 // device search or system initialization.
4058 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4059 status
= DriverEntry(DeviceObject
->DriverObject
,
4062 Irp
->IoStatus
.Status
= status
;
4064 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4071 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4074 // Pass the device control to the next driver.
4080 // Copy the Irp stack parameters to the next stack location.
4083 nextStack
= IoGetNextIrpStackLocation(Irp
);
4084 nextStack
->Parameters
= irpStack
->Parameters
;
4085 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4086 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4088 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4092 } // end switch( ...
4102 ScsiClassShutdownFlush(
4103 IN PDEVICE_OBJECT DeviceObject
,
4109 Routine Description:
4111 This routine is called for a shutdown and flush IRPs. These are sent by the
4112 system before it actually shuts down or when the file system does a flush.
4113 If it exists, the device-specific driver's routine will be invoked. If there
4114 wasn't one specified, the Irp will be completed with an Invalid device request.
4118 DriverObject - Pointer to device object to being shutdown by system.
4129 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4131 if (deviceExtension
->ClassShutdownFlush
) {
4134 // Call the device-specific driver's routine.
4137 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4141 // Device-specific driver doesn't support this.
4144 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4145 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4147 return STATUS_INVALID_DEVICE_REQUEST
;
4153 ScsiClassFindUnclaimedDevices(
4154 IN PCLASS_INIT_DATA InitializationData
,
4155 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4159 ULONG scsiBus
,deviceCount
= 0;
4160 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4161 PSCSI_INQUIRY_DATA lunInfo
;
4162 PINQUIRYDATA inquiryData
;
4164 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4167 // Get the SCSI bus scan data for this bus.
4170 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4173 // Search list for unclaimed disk devices.
4176 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4178 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4180 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4182 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4187 if (lunInfo
->NextInquiryDataOffset
== 0) {
4191 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4201 ScsiClassCreateDeviceObject(
4202 IN PDRIVER_OBJECT DriverObject
,
4203 IN PCCHAR ObjectNameBuffer
,
4204 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4205 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4206 IN PCLASS_INIT_DATA InitializationData
4211 Routine Description:
4213 This routine creates an object for the physical device specified and
4214 sets up the deviceExtension's function pointers for each entry point
4215 in the device-specific driver.
4219 DriverObject - Pointer to driver object created by system.
4221 ObjectNameBuffer - Dir. name of the object to create.
4223 PhysicalDeviceObject - Pointer to the physical (class) device object for
4224 this logical unit or NULL if this is it.
4226 DeviceObject - Pointer to the device object pointer we will return.
4228 InitializationData - Pointer to the init data created by the device-specific driver.
4237 STRING ntNameString
;
4238 UNICODE_STRING ntUnicodeString
;
4240 PDEVICE_OBJECT deviceObject
= NULL
;
4242 *DeviceObject
= NULL
;
4245 "ScsiClassCreateDeviceObject: Create device object %s\n",
4248 RtlInitString(&ntNameString
,
4251 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4255 if (!NT_SUCCESS(status
)) {
4258 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4261 ntUnicodeString
.Buffer
= NULL
;
4265 status
= IoCreateDevice(DriverObject
,
4266 InitializationData
->DeviceExtensionSize
,
4268 InitializationData
->DeviceType
,
4269 InitializationData
->DeviceCharacteristics
,
4274 if (!NT_SUCCESS(status
)) {
4277 "CreateDiskDeviceObjects: Can not create device object %s\n",
4282 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4285 // Fill in entry points
4288 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4289 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4290 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4291 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4292 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4293 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4294 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4296 deviceExtension
->MediaChangeCount
= 0;
4299 // If a pointer to the physical device object was passed in then use
4300 // that. If the value was NULL, then this is the physical device so
4301 // use the pointer to the device we just created.
4304 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4305 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4307 deviceExtension
->PhysicalDevice
= deviceObject
;
4311 *DeviceObject
= deviceObject
;
4313 RtlFreeUnicodeString(&ntUnicodeString
);
4316 // Indicate the ntUnicodeString is free.
4319 ntUnicodeString
.Buffer
= NULL
;
4327 ScsiClassClaimDevice(
4328 IN PDEVICE_OBJECT PortDeviceObject
,
4329 IN PSCSI_INQUIRY_DATA LunInfo
,
4331 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4335 Routine Description:
4337 This function claims a device in the port driver. The port driver object
4338 is updated with the correct driver object if the device is successfully
4343 PortDeviceObject - Supplies the base port device object.
4345 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4347 Release - Indicates the logical unit should be released rather than claimed.
4349 NewPortDeviceObject - Returns the updated port device object to be used
4350 for all future accesses.
4354 Returns a status indicating success or failure of the operation.
4359 IO_STATUS_BLOCK ioStatus
;
4361 PIO_STACK_LOCATION irpStack
;
4364 SCSI_REQUEST_BLOCK srb
;
4368 if (NewPortDeviceObject
!= NULL
) {
4369 *NewPortDeviceObject
= NULL
;
4373 // Clear the SRB fields.
4376 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4379 // Write length to SRB.
4382 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4385 // Set SCSI bus address.
4388 srb
.PathId
= LunInfo
->PathId
;
4389 srb
.TargetId
= LunInfo
->TargetId
;
4390 srb
.Lun
= LunInfo
->Lun
;
4392 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4393 SRB_FUNCTION_CLAIM_DEVICE
;
4396 // Set the event object to the unsignaled state.
4397 // It will be used to signal request completion.
4400 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4403 // Build synchronous request with no transfer.
4406 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4418 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4419 return STATUS_INSUFFICIENT_RESOURCES
;
4422 irpStack
= IoGetNextIrpStackLocation(irp
);
4425 // Save SRB address in next stack for port driver.
4428 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4431 // Set up IRP Address.
4434 srb
.OriginalRequest
= irp
;
4437 // Call the port driver with the request and wait for it to complete.
4440 status
= IoCallDriver(PortDeviceObject
, irp
);
4441 if (status
== STATUS_PENDING
) {
4443 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4444 status
= ioStatus
.Status
;
4448 // If this is a release request, then just decrement the reference count
4449 // and return. The status does not matter.
4454 ObDereferenceObject(PortDeviceObject
);
4455 return STATUS_SUCCESS
;
4458 if (!NT_SUCCESS(status
)) {
4462 ASSERT(srb
.DataBuffer
!= NULL
);
4465 // Reference the new port driver object so that it will not go away while
4466 // it is being used.
4469 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4474 if (!NT_SUCCESS(status
)) {
4480 // Return the new port device object pointer.
4483 if (NewPortDeviceObject
!= NULL
) {
4484 *NewPortDeviceObject
= srb
.DataBuffer
;
4493 ScsiClassInternalIoControl (
4494 IN PDEVICE_OBJECT DeviceObject
,
4500 Routine Description:
4502 This routine passes internal device controls to the port driver.
4503 Internal device controls are used by higher level class drivers to
4504 send scsi requests to a device that are not normally sent by a generic
4507 The path ID, target ID and logical unit ID are set in the srb so the
4508 higher level driver does not have to figure out what values are actually
4513 DeviceObject - Supplies a pointer to the device object for this request.
4515 Irp - Supplies the Irp making the request.
4519 Returns back a STATUS_PENDING or a completion status.
4523 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4524 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4525 PSCSI_REQUEST_BLOCK srb
;
4528 // Get a pointer to the SRB.
4531 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4534 // Set SCSI bus address.
4537 srb
->PathId
= deviceExtension
->PathId
;
4538 srb
->TargetId
= deviceExtension
->TargetId
;
4539 srb
->Lun
= deviceExtension
->Lun
;
4542 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4543 // zero; however, some target controllers ignore the logical unit number
4544 // in the INDENTIFY message and only look at the logical unit number field
4548 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4551 // Set the parameters in the next stack location.
4554 irpStack
= IoGetNextIrpStackLocation(Irp
);
4556 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4557 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4558 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4560 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4561 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4567 IN PDEVICE_OBJECT DeviceObject
,
4574 Routine Description:
4576 This routine is called when an internal device control I/O request
4577 has completed. It marks the IRP pending if necessary and returns the
4578 status of the request.
4582 DeviceObject - Target device object.
4584 Irp - Completed request.
4590 Returns the status of the completed request.
4595 UNREFERENCED_PARAMETER(Context
);
4596 UNREFERENCED_PARAMETER(DeviceObject
);
4599 // If pending is returned for this Irp then mark current stack
4603 if (Irp
->PendingReturned
) {
4605 IoMarkIrpPending( Irp
);
4608 return Irp
->IoStatus
.Status
;
4614 ScsiClassInitializeSrbLookasideList(
4615 IN PDEVICE_EXTENSION DeviceExtension
,
4616 IN ULONG NumberElements
4621 Routine Description:
4623 This routine sets up a lookaside listhead for srbs.
4627 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4629 NumberElements - Supplies the maximum depth of the lookaside list.
4639 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4642 NonPagedPoolMustSucceed
,
4643 SCSI_REQUEST_BLOCK_SIZE
,
4645 (USHORT
)NumberElements
);
4652 ScsiClassQueryTimeOutRegistryValue(
4653 IN PUNICODE_STRING RegistryPath
4658 Routine Description:
4660 This routine determines whether a reg key for a user-specified timeout value exists.
4664 RegistryPath - Pointer to the hardware reg. entry describing the key.
4668 New default timeout for a class of devices.
4674 // Find the appropriate reg. key
4677 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4684 if (!RegistryPath
) {
4688 parameters
= ExAllocatePool(NonPagedPool
,
4689 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4695 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4696 path
= ExAllocatePool(NonPagedPool
, size
);
4699 ExFreePool(parameters
);
4703 RtlZeroMemory(path
,size
);
4704 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
4708 // Check for the Timeout value.
4711 RtlZeroMemory(parameters
,
4712 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
4714 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
4715 parameters
[0].Name
= L
"TimeOutValue";
4716 parameters
[0].EntryContext
= &timeOut
;
4717 parameters
[0].DefaultType
= REG_DWORD
;
4718 parameters
[0].DefaultData
= &zero
;
4719 parameters
[0].DefaultLength
= sizeof(ULONG
);
4721 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
4727 if (!(NT_SUCCESS(status
))) {
4731 ExFreePool(parameters
);
4735 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
4745 ScsiClassCheckVerifyComplete(
4746 IN PDEVICE_OBJECT DeviceObject
,
4753 Routine Description:
4755 This routine executes when the port driver has completed a check verify
4756 ioctl. It will set the status of the master Irp, copy the media change
4757 count and complete the request.
4761 DeviceObject - Supplies the device object which represents the logical
4764 Irp - Supplies the Irp which has completed.
4775 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4776 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4777 PDEVICE_EXTENSION physicalExtension
=
4778 deviceExtension
->PhysicalDevice
->DeviceExtension
;
4781 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
4784 // Copy the media change count and status
4787 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
4788 physicalExtension
->MediaChangeCount
;
4790 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
4791 "device %d is %d\n",
4792 physicalExtension
->DeviceNumber
,
4793 physicalExtension
->MediaChangeCount
));
4795 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
4796 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
4798 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
4802 return STATUS_MORE_PROCESSING_REQUIRED
;
4807 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
4811 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
4812 PKEVENT Event
= Irp
->UserEvent
;
4815 *IoStatusBlock
= Irp
->IoStatus
;
4816 Irp
->UserIosb
= NULL
;
4817 Irp
->UserEvent
= NULL
;
4821 Mdl
= Irp
->MdlAddress
;
4823 // if necessary - unlock pages
4824 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
4825 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
4834 // free irp and set event to unsignaled state
4836 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
4838 return STATUS_MORE_PROCESSING_REQUIRED
;