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>
18 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
21 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
22 #pragma alloc_text(PAGE, ScsiClassInitialize)
23 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
24 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
25 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
26 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
30 #define INQUIRY_DATA_SIZE 2048
31 #define START_UNIT_TIMEOUT 30
36 IN PDEVICE_OBJECT DeviceObject
,
43 IN PDEVICE_OBJECT DeviceObject
,
49 ScsiClassDeviceControlDispatch(
50 PDEVICE_OBJECT DeviceObject
,
56 ScsiClassDeviceControl(
57 PDEVICE_OBJECT DeviceObject
,
63 ScsiClassInternalIoControl (
64 IN PDEVICE_OBJECT DeviceObject
,
70 ScsiClassShutdownFlush(
71 IN PDEVICE_OBJECT DeviceObject
,
78 IN PDRIVER_OBJECT DriverObject
,
79 IN PUNICODE_STRING RegistryPath
83 // Class internal routines
90 PDEVICE_OBJECT DeviceObject
,
92 PSCSI_REQUEST_BLOCK Srb
,
99 IN PDEVICE_OBJECT DeviceObject
105 IN PDEVICE_OBJECT DeviceObject
,
112 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
120 IN PDRIVER_OBJECT DriverObject
,
121 IN PUNICODE_STRING RegistryPath
124 return STATUS_SUCCESS
;
133 IN PCLASS_INIT_DATA InitializationData
140 This routine is called by a class driver during its
141 DriverEntry routine to initialize the driver.
145 Argument1 - Driver Object.
146 Argument2 - Registry Path.
147 InitializationData - Device-specific driver's initialization data.
151 A valid return code for a DriverEntry routine.
158 PDRIVER_OBJECT DriverObject
= Argument1
;
159 ULONG portNumber
= 0;
160 PDEVICE_OBJECT portDeviceObject
;
162 STRING deviceNameString
;
163 UNICODE_STRING unicodeDeviceName
;
164 PFILE_OBJECT fileObject
;
165 CCHAR deviceNameBuffer
[256];
166 BOOLEAN deviceFound
= FALSE
;
168 DebugPrint((3,"\n\nSCSI Class Driver\n"));
171 // Validate the length of this structure. This is effectively a
175 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
177 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
178 return (ULONG
) STATUS_REVISION_MISMATCH
;
182 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
183 // are not required entry points.
186 if ((!InitializationData
->ClassFindDevices
) ||
187 (!InitializationData
->ClassDeviceControl
) ||
188 (!((InitializationData
->ClassReadWriteVerification
) ||
189 (InitializationData
->ClassStartIo
)))) {
192 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
194 return (ULONG
) STATUS_REVISION_MISMATCH
;
198 // Update driver object with entry points.
201 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
202 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
203 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
204 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
205 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
206 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
207 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
208 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
210 if (InitializationData
->ClassStartIo
) {
211 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
215 // Open port driver controller device objects by name.
220 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", portNumber
);
222 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
224 RtlInitString(&deviceNameString
, deviceNameBuffer
);
226 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
230 if (!NT_SUCCESS(status
)){
234 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
235 FILE_READ_ATTRIBUTES
,
239 if (NT_SUCCESS(status
)) {
242 // Call the device-specific driver's FindDevice routine.
245 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
246 portDeviceObject
, portNumber
)) {
253 // Check next SCSI adapter.
258 } while(NT_SUCCESS(status
));
260 return deviceFound
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
266 ScsiClassCreateClose(
267 IN PDEVICE_OBJECT DeviceObject
,
275 SCSI class driver create and close routine. This is called by the I/O system
276 when the device is opened or closed.
280 DriverObject - Pointer to driver object created by system.
286 Device-specific drivers return value or STATUS_SUCCESS.
291 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
294 // Invoke the device-specific routine, if one exists. Otherwise complete
298 if (deviceExtension
->ClassCreateClose
) {
300 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
303 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
305 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
306 return(STATUS_SUCCESS
);
315 IN PDEVICE_OBJECT DeviceObject
,
323 This is the system entry point for read and write requests. The device-specific handler is invoked
324 to perform any validation necessary. The number of bytes in the request are
325 checked against the maximum byte counts that the adapter supports and requests are broken up into
326 smaller sizes if necessary.
340 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
341 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
343 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
344 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
347 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
348 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
351 // if DO_VERIFY_VOLUME bit is set
352 // in device object flags, fail request.
355 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
357 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
358 Irp
->IoStatus
.Information
= 0;
360 IoCompleteRequest(Irp
, 0);
361 return STATUS_VERIFY_REQUIRED
;
365 // Invoke the device specific routine to do whatever it needs to verify
369 ASSERT(deviceExtension
->ClassReadWriteVerification
);
371 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
373 if (!NT_SUCCESS(status
)) {
376 // It is up to the device specific driver to set the Irp status.
379 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
381 } else if (status
== STATUS_PENDING
) {
383 IoMarkIrpPending(Irp
);
384 return STATUS_PENDING
;
388 // Check for a zero length IO, as several macros will turn this into
389 // seemingly a 0xffffffff length request.
392 if (transferByteCount
== 0) {
393 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
394 Irp
->IoStatus
.Information
= 0;
395 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
396 return STATUS_SUCCESS
;
400 if (deviceExtension
->ClassStartIo
) {
402 IoMarkIrpPending(Irp
);
404 IoStartPacket(DeviceObject
,
409 return STATUS_PENDING
;
413 // Mark IRP with status pending.
416 IoMarkIrpPending(Irp
);
419 // Add partition byte offset to make starting byte relative to
420 // beginning of disk. In addition, add in skew for DM Driver, if any.
423 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
424 deviceExtension
->DMByteSkew
);
427 // Calculate number of pages in this transfer.
430 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
431 currentIrpStack
->Parameters
.Read
.Length
);
434 // Check if request length is greater than the maximum number of
435 // bytes that the hardware can transfer.
438 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
439 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
441 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
442 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
443 maximumTransferLength
));
444 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
445 currentIrpStack
->Parameters
.Read
.Length
));
448 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
450 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
451 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
455 // Check that maximum transfer size is not zero.
458 if (maximumTransferLength
== 0) {
459 maximumTransferLength
= PAGE_SIZE
;
463 // Mark IRP with status pending.
466 IoMarkIrpPending(Irp
);
469 // Request greater than port driver maximum.
470 // Break up into smaller routines.
473 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
476 return STATUS_PENDING
;
480 // Build SRB and CDB for this IRP.
483 ScsiClassBuildRequest(DeviceObject
, Irp
);
486 // Return the results of the call to the port driver.
489 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
491 } // end ScsiClassReadWrite()
496 ScsiClassGetCapabilities(
497 IN PDEVICE_OBJECT PortDeviceObject
,
498 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
505 This routine builds and sends a request to the port driver to
506 get a pointer to a structure that describes the adapter's
507 capabilities/limitations. This routine is sychronous.
511 PortDeviceObject - Port driver device object representing the HBA.
513 PortCapabilities - Location to store pointer to capabilities structure.
517 Nt status indicating the results of the operation.
521 This routine should only be called at initialization time.
527 IO_STATUS_BLOCK ioStatus
;
534 // Create notification event object to be used to signal the
535 // request completion.
538 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
541 // Build the synchronous request to be sent to the port driver
542 // to perform the request.
545 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
556 return STATUS_INSUFFICIENT_RESOURCES
;
560 // Pass request to port driver and wait for request to complete.
563 status
= IoCallDriver(PortDeviceObject
, irp
);
565 if (status
== STATUS_PENDING
) {
566 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
567 return(ioStatus
.Status
);
572 } // end ScsiClassGetCapabilities()
577 ScsiClassGetInquiryData(
578 IN PDEVICE_OBJECT PortDeviceObject
,
579 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
586 This routine sends a request to a port driver to return
587 configuration information. Space for the information is
588 allocated by this routine. The caller is responsible for
589 freeing the configuration information. This routine is
594 PortDeviceObject - Port driver device object representing the HBA.
596 ConfigInfo - Returns a pointer to the configuration information.
600 Nt status indicating the results of the operation.
604 This routine should be called only at initialization time.
610 IO_STATUS_BLOCK ioStatus
;
613 PSCSI_ADAPTER_BUS_INFO buffer
;
617 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
618 *ConfigInfo
= buffer
;
620 if (buffer
== NULL
) {
621 return(STATUS_INSUFFICIENT_RESOURCES
);
625 // Create notification event object to be used to signal the inquiry
626 // request completion.
629 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
632 // Build the synchronous request to be sent to the port driver
633 // to perform the inquiries.
636 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
647 return(STATUS_INSUFFICIENT_RESOURCES
);
651 // Pass request to port driver and wait for request to complete.
654 status
= IoCallDriver(PortDeviceObject
, irp
);
656 if (status
== STATUS_PENDING
) {
657 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
658 status
= ioStatus
.Status
;
661 if (!NT_SUCCESS(status
)) {
664 // Free the buffer on an error.
674 } // end ScsiClassGetInquiryData()
679 ScsiClassReadDriveCapacity(
680 IN PDEVICE_OBJECT DeviceObject
687 This routine sends a READ CAPACITY to the requested device, updates
688 the geometry information in the device object and returns
689 when it is complete. This routine is synchronous.
693 DeviceObject - Supplies a pointer to the device object that represents
694 the device whose capacity is to be read.
702 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
706 PREAD_CAPACITY_DATA readCapacityBuffer
;
707 SCSI_REQUEST_BLOCK srb
;
711 // Allocate read capacity buffer from nonpaged pool.
714 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
715 sizeof(READ_CAPACITY_DATA
));
717 if (!readCapacityBuffer
) {
718 return(STATUS_INSUFFICIENT_RESOURCES
);
721 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
724 // Build the read capacity CDB.
731 // Set timeout value from device extension.
734 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
736 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
740 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
743 sizeof(READ_CAPACITY_DATA
),
746 if (NT_SUCCESS(status
)) {
749 // Copy sector size from read capacity buffer to device extension
750 // in reverse byte order.
753 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->BytesPerSector
)->Byte0
=
754 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
756 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->BytesPerSector
)->Byte1
=
757 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
759 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->BytesPerSector
)->Byte2
=
760 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
762 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->BytesPerSector
)->Byte3
=
763 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
766 // Copy last sector in reverse byte order.
769 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
770 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
772 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
773 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
775 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
776 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
778 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
779 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
782 // Calculate sector to byte shift.
785 WHICH_BIT(deviceExtension
->DiskGeometry
->BytesPerSector
, deviceExtension
->SectorShift
);
787 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
788 deviceExtension
->DiskGeometry
->BytesPerSector
));
790 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
794 // Calculate media capacity in bytes.
797 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
800 // Calculate number of cylinders.
803 deviceExtension
->DiskGeometry
->Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
805 deviceExtension
->PartitionLength
.QuadPart
=
806 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
808 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
811 // This device supports removable media.
814 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
819 // Assume media type is fixed disk.
822 deviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
826 // Assume sectors per track are 32;
829 deviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
832 // Assume tracks per cylinder (number of heads) is 64.
835 deviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
838 if (status
== STATUS_VERIFY_REQUIRED
) {
841 // Routine ScsiClassSendSrbSynchronous does not retry
842 // requests returned with this status.
843 // Read Capacities should be retried
857 if (!NT_SUCCESS(status
)) {
860 // If the read capacity fails, set the geometry to reasonable parameter
861 // so things don't fail at unexpected places. Zero the geometry
862 // except for the bytes per sector and sector shift.
865 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY
));
866 deviceExtension
->DiskGeometry
->BytesPerSector
= 512;
867 deviceExtension
->SectorShift
= 9;
868 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
870 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
873 // This device supports removable media.
876 deviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
881 // Assume media type is fixed disk.
884 deviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
889 // Deallocate read capacity buffer.
892 ExFreePool(readCapacityBuffer
);
896 } // end ScsiClassReadDriveCapacity()
901 ScsiClassReleaseQueue(
902 IN PDEVICE_OBJECT DeviceObject
909 This routine issues an internal device control command
910 to the port driver to release a frozen queue. The call
911 is issued asynchronously as ScsiClassReleaseQueue will be invoked
912 from the IO completion DPC (and will have no context to
913 wait for a synchronous call to complete).
917 DeviceObject - The device object for the logical unit with
926 PIO_STACK_LOCATION irpStack
;
928 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
929 PCOMPLETION_CONTEXT context
;
930 PSCSI_REQUEST_BLOCK srb
;
934 // Allocate context from nonpaged pool.
937 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
938 sizeof(COMPLETION_CONTEXT
));
941 // Save the device object in the context for use by the completion
945 context
->DeviceObject
= DeviceObject
;
952 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
955 // Write length to SRB.
958 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
961 // Set up SCSI bus address.
964 srb
->PathId
= deviceExtension
->PathId
;
965 srb
->TargetId
= deviceExtension
->TargetId
;
966 srb
->Lun
= deviceExtension
->Lun
;
969 // If this device is removable then flush the queue. This will also
973 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
975 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
979 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
984 // Build the asynchronous request to be sent to the port driver.
987 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
992 // We have no better way of dealing with this at the moment
995 KeBugCheck((ULONG
)0x0000002DL
);
999 IoSetCompletionRoutine(irp
,
1000 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1006 irpStack
= IoGetNextIrpStackLocation(irp
);
1008 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1010 srb
->OriginalRequest
= irp
;
1013 // Store the SRB address in next stack for port driver.
1016 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1019 // Since this routine can cause outstanding requests to be completed, and
1020 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1021 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1022 // issuing the request
1025 currentIrql
= KeGetCurrentIrql();
1027 if(currentIrql
< DISPATCH_LEVEL
) {
1028 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1029 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1030 KeLowerIrql(currentIrql
);
1032 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1037 } // end ScsiClassReleaseQueue()
1043 IN PDEVICE_OBJECT DeviceObject
1048 Routine Description:
1050 Send command to SCSI unit to start or power up.
1051 Because this command is issued asynchronounsly, that is, without
1052 waiting on it to complete, the IMMEDIATE flag is not set. This
1053 means that the CDB will not return until the drive has powered up.
1054 This should keep subsequent requests from being submitted to the
1055 device before it has completely spun up.
1056 This routine is called from the InterpretSense routine, when a
1057 request sense returns data indicating that a drive must be
1062 DeviceObject - The device object for the logical unit with
1071 PIO_STACK_LOCATION irpStack
;
1073 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1074 PSCSI_REQUEST_BLOCK srb
;
1075 PCOMPLETION_CONTEXT context
;
1079 // Allocate Srb from nonpaged pool.
1082 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1083 sizeof(COMPLETION_CONTEXT
));
1086 // Save the device object in the context for use by the completion
1090 context
->DeviceObject
= DeviceObject
;
1091 srb
= &context
->Srb
;
1097 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1100 // Write length to SRB.
1103 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1106 // Set up SCSI bus address.
1109 srb
->PathId
= deviceExtension
->PathId
;
1110 srb
->TargetId
= deviceExtension
->TargetId
;
1111 srb
->Lun
= deviceExtension
->Lun
;
1113 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1116 // Set timeout value large enough for drive to spin up.
1119 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1122 // Set the transfer length.
1125 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1128 // Build the start unit CDB.
1132 cdb
= (PCDB
)srb
->Cdb
;
1134 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1135 cdb
->START_STOP
.Start
= 1;
1136 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1139 // Build the asynchronous request to be sent to the port driver.
1140 // Since this routine is called from a DPC the IRP should always be
1144 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1145 IoSetCompletionRoutine(irp
,
1146 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1152 irpStack
= IoGetNextIrpStackLocation(irp
);
1153 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1154 srb
->OriginalRequest
= irp
;
1157 // Store the SRB address in next stack for port driver.
1160 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1163 // Call the port driver with the IRP.
1166 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1170 } // end StartUnit()
1175 ScsiClassAsynchronousCompletion(
1176 PDEVICE_OBJECT DeviceObject
,
1182 Routine Description:
1184 This routine is called when an asynchronous I/O request
1185 which was issused by the class driver completes. Examples of such requests
1186 are release queue or START UNIT. This routine releases the queue if
1187 necessary. It then frees the context and the IRP.
1191 DeviceObject - The device object for the logical unit; however since this
1192 is the top stack location the value is NULL.
1194 Irp - Supplies a pointer to the Irp to be processed.
1196 Context - Supplies the context to be used to process this request.
1205 PCOMPLETION_CONTEXT context
= Context
;
1206 PSCSI_REQUEST_BLOCK srb
;
1208 srb
= &context
->Srb
;
1211 // If this is an execute srb, then check the return status and make sure.
1212 // the queue is not frozen.
1215 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1218 // Check for a frozen queue.
1221 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1224 // Unfreeze the queue getting the device object from the context.
1227 ScsiClassReleaseQueue(context
->DeviceObject
);
1232 // Free the context and the Irp.
1235 if (Irp
->MdlAddress
!= NULL
) {
1236 MmUnlockPages(Irp
->MdlAddress
);
1237 IoFreeMdl(Irp
->MdlAddress
);
1239 Irp
->MdlAddress
= NULL
;
1242 ExFreePool(context
);
1246 // Indicate the I/O system should stop processing the Irp completion.
1249 return STATUS_MORE_PROCESSING_REQUIRED
;
1251 } // ScsiClassAsynchronousCompletion()
1256 ScsiClassSplitRequest(
1257 IN PDEVICE_OBJECT DeviceObject
,
1259 IN ULONG MaximumBytes
1264 Routine Description:
1266 Break request into smaller requests. Each new request will be the
1267 maximum transfer size that the port driver can handle or if it
1268 is the final request, it may be the residual size.
1270 The number of IRPs required to process this request is written in the
1271 current stack of the original IRP. Then as each new IRP completes
1272 the count in the original IRP is decremented. When the count goes to
1273 zero, the original IRP is completed.
1277 DeviceObject - Pointer to the class device object to be addressed.
1279 Irp - Pointer to Irp the orginal request.
1288 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1289 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1290 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1291 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1292 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1293 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1294 ULONG dataLength
= MaximumBytes
;
1295 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1297 PSCSI_REQUEST_BLOCK srb
;
1299 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1300 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1303 // If all partial transfers complete successfully then the status and
1304 // bytes transferred are already set up. Failing a partial-transfer IRP
1305 // will set status to error and bytes transferred to 0 during
1306 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1307 // asynchronous partial transfers. This is an optimization for the
1311 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1312 Irp
->IoStatus
.Information
= transferByteCount
;
1315 // Save number of IRPs to complete count on current stack
1319 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) irpCount
;
1321 for (i
= 0; i
< irpCount
; i
++) {
1324 PIO_STACK_LOCATION newIrpStack
;
1327 // Allocate new IRP.
1330 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1332 if (newIrp
== NULL
) {
1334 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1337 // If an Irp can't be allocated then the orginal request cannot
1338 // be executed. If this is the first request then just fail the
1339 // orginal request; otherwise just return. When the pending
1340 // requests complete, they will complete the original request.
1341 // In either case set the IRP status to failure.
1344 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1345 Irp
->IoStatus
.Information
= 0;
1348 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1354 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1357 // Write MDL address to new IRP. In the port driver the SRB data
1358 // buffer field is used as an offset into the MDL, so the same MDL
1359 // can be used for each partial transfer. This saves having to build
1360 // a new MDL for each partial transfer.
1363 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1366 // At this point there is no current stack. IoSetNextIrpStackLocation
1367 // will make the first stack location the current stack so that the
1368 // SRB address can be written there.
1371 IoSetNextIrpStackLocation(newIrp
);
1372 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1374 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1375 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1376 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1377 newIrpStack
->DeviceObject
= DeviceObject
;
1380 // Build SRB and CDB.
1383 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1386 // Adjust SRB for this partial transfer.
1389 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1391 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1392 srb
->DataBuffer
= dataBuffer
;
1395 // Write original IRP address to new IRP.
1398 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1401 // Set the completion routine to ScsiClassIoCompleteAssociated.
1404 IoSetCompletionRoutine(newIrp
,
1405 ScsiClassIoCompleteAssociated
,
1412 // Call port driver with new request.
1415 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1418 // Set up for next request.
1421 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1423 transferByteCount
-= MaximumBytes
;
1425 if (transferByteCount
> MaximumBytes
) {
1427 dataLength
= MaximumBytes
;
1431 dataLength
= transferByteCount
;
1435 // Adjust disk byte offset.
1438 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1443 } // end ScsiClassSplitRequest()
1448 ScsiClassIoComplete(
1449 IN PDEVICE_OBJECT DeviceObject
,
1456 Routine Description:
1458 This routine executes when the port driver has completed a request.
1459 It looks at the SRB status in the completing SRB and if not success
1460 it checks for valid request sense buffer information. If valid, the
1461 info is used to update status with more precise message of type of
1462 error. This routine deallocates the SRB.
1466 DeviceObject - Supplies the device object which represents the logical
1469 Irp - Supplies the Irp which has completed.
1471 Context - Supplies a pointer to the SRB.
1480 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1481 PSCSI_REQUEST_BLOCK srb
= Context
;
1482 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1487 // Check SRB status for success of completing request.
1490 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1492 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1495 // Release the queue if it is frozen.
1498 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1499 ScsiClassReleaseQueue(DeviceObject
);
1502 retry
= ScsiClassInterpretSenseInfo(
1505 irpStack
->MajorFunction
,
1506 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1507 MAXIMUM_RETRIES
- ((ULONG
)irpStack
->Parameters
.Others
.Argument4
),
1511 // If the status is verified required and the this request
1512 // should bypass verify required then retry the request.
1515 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1516 status
== STATUS_VERIFY_REQUIRED
) {
1518 status
= STATUS_IO_DEVICE_ERROR
;
1522 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1528 DebugPrint((1, "Retry request %lx\n", Irp
));
1529 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1530 return STATUS_MORE_PROCESSING_REQUIRED
;
1535 // Set status for successful request.
1538 status
= STATUS_SUCCESS
;
1540 } // end if (SRB_STATUS(srb->SrbStatus) ...
1543 // Return SRB to list.
1546 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1550 // Set status in completing IRP.
1553 Irp
->IoStatus
.Status
= status
;
1554 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1555 ASSERT(Irp
->IoStatus
.Information
);
1559 // Set the hard error if necessary.
1562 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1565 // Store DeviceObject for filesystem, and clear
1566 // in IoStatus.Information field.
1569 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1570 Irp
->IoStatus
.Information
= 0;
1574 // If pending has be returned for this irp then mark the current stack as
1578 if (Irp
->PendingReturned
) {
1579 IoMarkIrpPending(Irp
);
1582 if (deviceExtension
->ClassStartIo
) {
1583 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1584 IoStartNextPacket(DeviceObject
, FALSE
);
1590 } // end ScsiClassIoComplete()
1595 ScsiClassIoCompleteAssociated(
1596 IN PDEVICE_OBJECT DeviceObject
,
1603 Routine Description:
1605 This routine executes when the port driver has completed a request.
1606 It looks at the SRB status in the completing SRB and if not success
1607 it checks for valid request sense buffer information. If valid, the
1608 info is used to update status with more precise message of type of
1609 error. This routine deallocates the SRB. This routine is used for
1610 requests which were build by split request. After it has processed
1611 the request it decrements the Irp count in the master Irp. If the
1612 count goes to zero then the master Irp is completed.
1616 DeviceObject - Supplies the device object which represents the logical
1619 Irp - Supplies the Irp which has completed.
1621 Context - Supplies a pointer to the SRB.
1630 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1631 PSCSI_REQUEST_BLOCK srb
= Context
;
1632 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1633 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1639 // Check SRB status for success of completing request.
1642 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1644 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1647 // Release the queue if it is frozen.
1650 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1651 ScsiClassReleaseQueue(DeviceObject
);
1654 retry
= ScsiClassInterpretSenseInfo(
1657 irpStack
->MajorFunction
,
1658 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1659 MAXIMUM_RETRIES
- ((ULONG
)irpStack
->Parameters
.Others
.Argument4
),
1663 // If the status is verified required and the this request
1664 // should bypass verify required then retry the request.
1667 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1668 status
== STATUS_VERIFY_REQUIRED
) {
1670 status
= STATUS_IO_DEVICE_ERROR
;
1674 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1677 // Retry request. If the class driver has supplied a StartIo,
1678 // call it directly for retries.
1681 DebugPrint((1, "Retry request %lx\n", Irp
));
1684 if (!deviceExtension->ClassStartIo) {
1685 RetryRequest(DeviceObject, Irp, srb, TRUE);
1687 deviceExtension->ClassStartIo(DeviceObject, Irp);
1691 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1693 return STATUS_MORE_PROCESSING_REQUIRED
;
1701 // Set status for successful request.
1704 status
= STATUS_SUCCESS
;
1706 } // end if (SRB_STATUS(srb->SrbStatus) ...
1709 // Return SRB to list.
1712 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1716 // Set status in completing IRP.
1719 Irp
->IoStatus
.Status
= status
;
1721 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
1724 // Get next stack location. This original request is unused
1725 // except to keep track of the completing partial IRPs so the
1726 // stack location is valid.
1729 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
1732 // Update status only if error so that if any partial transfer
1733 // completes with error, then the original IRP will return with
1734 // error. If any of the asynchronous partial transfer IRPs fail,
1735 // with an error then the original IRP will return 0 bytes transfered.
1736 // This is an optimization for successful transfers.
1739 if (!NT_SUCCESS(status
)) {
1741 originalIrp
->IoStatus
.Status
= status
;
1742 originalIrp
->IoStatus
.Information
= 0;
1745 // Set the hard error if necessary.
1748 if (IoIsErrorUserInduced(status
)) {
1751 // Store DeviceObject for filesystem.
1754 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
1759 // Decrement and get the count of remaining IRPs.
1762 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
1764 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
1768 // Old bug could cause irp count to negative
1771 ASSERT(irpCount
>= 0);
1773 if (irpCount
== 0) {
1776 // All partial IRPs have completed.
1780 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
1783 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
1786 // If the class driver has supplied a startio, start the
1790 if (deviceExtension
->ClassStartIo
) {
1791 IoStartNextPacket(DeviceObject
, FALSE
);
1796 // Deallocate IRP and indicate the I/O system should not attempt any more
1801 return STATUS_MORE_PROCESSING_REQUIRED
;
1803 } // end ScsiClassIoCompleteAssociated()
1808 ScsiClassSendSrbSynchronous(
1809 PDEVICE_OBJECT DeviceObject
,
1810 PSCSI_REQUEST_BLOCK Srb
,
1811 PVOID BufferAddress
,
1813 BOOLEAN WriteToDevice
1818 Routine Description:
1820 This routine is called by SCSI device controls to complete an
1821 SRB and send it to the port driver synchronously (ie wait for
1822 completion). The CDB is already completed along with the SRB CDB
1823 size and request timeout value.
1827 DeviceObject - Supplies the device object which represents the logical
1830 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
1832 BufferAddress - Supplies the address of the buffer.
1834 BufferLength - Supplies the length in bytes of the buffer.
1836 WriteToDevice - Indicates the data should be transfer to the device.
1840 Nt status indicating the final results of the operation.
1845 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1846 IO_STATUS_BLOCK ioStatus
;
1847 ULONG controlType
, mjFunction
;
1849 PIO_STACK_LOCATION irpStack
;
1851 PUCHAR senseInfoBuffer
;
1852 ULONG retryCount
= MAXIMUM_RETRIES
;
1855 LARGE_INTEGER dummy
;
1862 // Write length to SRB.
1865 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1868 // Set SCSI bus address.
1871 Srb
->PathId
= deviceExtension
->PathId
;
1872 Srb
->TargetId
= deviceExtension
->TargetId
;
1873 Srb
->Lun
= deviceExtension
->Lun
;
1874 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1877 // NOTICE: The SCSI-II specification indicates that this field should be
1878 // zero; however, some target controllers ignore the logical unit number
1879 // in the INDENTIFY message and only look at the logical unit number field
1883 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1886 // Enable auto request sense.
1889 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1892 // Sense buffer is in aligned nonpaged pool.
1895 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1897 if (senseInfoBuffer
== NULL
) {
1900 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
1901 return(STATUS_INSUFFICIENT_RESOURCES
);
1904 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
1905 Srb
->DataBuffer
= BufferAddress
;
1908 // Start retries here.
1914 // Set the event object to the unsignaled state.
1915 // It will be used to signal request completion.
1918 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1921 // Set controlType and Srb direction flags.
1924 if (BufferAddress
!= NULL
) {
1926 if (WriteToDevice
) {
1928 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
1929 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
1930 mjFunction
= IRP_MJ_WRITE
;
1934 controlType
= IOCTL_SCSI_EXECUTE_IN
;
1935 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
1936 mjFunction
= IRP_MJ_READ
;
1942 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
1943 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1944 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
1948 // Build device I/O control request with data transfer.
1950 irp
= IoBuildAsynchronousFsdRequest(
1952 deviceExtension
->DeviceObject
,
1954 (BufferAddress
) ? BufferLength
: 0,
1959 ExFreePool(senseInfoBuffer
);
1960 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
1961 return(STATUS_INSUFFICIENT_RESOURCES
);
1965 irp
->UserEvent
= &event
;
1968 // Disable synchronous transfer for these requests.
1971 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1974 // Set the transfer length.
1977 Srb
->DataTransferLength
= BufferLength
;
1983 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
1986 // Set completion routine
1987 IoSetCompletionRoutine(
1989 ClassCompletionRoutine
,
1996 // Get next stack location.
1999 irpStack
= IoGetNextIrpStackLocation(irp
);
2001 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2002 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2005 // Set up SRB for execute scsi request. Save SRB address in next stack
2006 // for the port driver.
2009 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2012 // Set up IRP Address.
2015 Srb
->OriginalRequest
= irp
;
2018 // Call the port driver with the request and wait for it to complete.
2021 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2023 if (status
== STATUS_PENDING
) {
2024 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2028 // Check that request completed without error.
2031 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2034 // Release the queue if it is frozen.
2037 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2038 ScsiClassReleaseQueue(DeviceObject
);
2042 // Update status and determine if request should be retried.
2045 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2049 MAXIMUM_RETRIES
- retryCount
,
2054 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2055 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2056 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2058 LARGE_INTEGER delay
;
2061 // Delay for 2 seconds.
2064 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2067 // Stall for a while to let the controller spinup.
2070 KeDelayExecutionThread(KernelMode
,
2077 // If retries are not exhausted then retry this operation.
2087 status
= STATUS_SUCCESS
;
2090 ExFreePool(senseInfoBuffer
);
2093 } // end ScsiClassSendSrbSynchronous()
2098 ScsiClassInterpretSenseInfo(
2099 IN PDEVICE_OBJECT DeviceObject
,
2100 IN PSCSI_REQUEST_BLOCK Srb
,
2101 IN UCHAR MajorFunctionCode
,
2102 IN ULONG IoDeviceCode
,
2103 IN ULONG RetryCount
,
2104 OUT NTSTATUS
*Status
2109 Routine Description:
2111 This routine interprets the data returned from the SCSI
2112 request sense. It determines the status to return in the
2113 IRP and whether this request can be retried.
2117 DeviceObject - Supplies the device object associated with this request.
2119 Srb - Supplies the scsi request block which failed.
2121 MajorFunctionCode - Supplies the function code to be used for logging.
2123 IoDeviceCode - Supplies the device code to be used for logging.
2125 Status - Returns the status for the request.
2129 BOOLEAN TRUE: Drivers should retry this request.
2130 FALSE: Drivers should not retry this request.
2135 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2136 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2137 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2138 BOOLEAN retry
= TRUE
;
2139 BOOLEAN logError
= FALSE
;
2140 ULONG badSector
= 0;
2145 PIO_ERROR_LOG_PACKET errorLogEntry
;
2152 // Check that request sense buffer is valid.
2156 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2157 for (i
= 1; i
< 12; i
++) {
2158 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2160 DebugPrint((3,"\n"));
2163 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2164 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2166 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2167 senseBuffer
->ErrorCode
));
2168 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2169 senseBuffer
->SenseKey
));
2170 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2171 senseBuffer
->AdditionalSenseCode
));
2172 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2173 senseBuffer
->AdditionalSenseCodeQualifier
));
2176 // Zero the additional sense code and additional sense code qualifier
2177 // if they were not returned by the device.
2180 readSector
= senseBuffer
->AdditionalSenseLength
+
2181 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2183 if (readSector
> Srb
->SenseInfoBufferLength
) {
2184 readSector
= Srb
->SenseInfoBufferLength
;
2187 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2188 senseBuffer
->AdditionalSenseCode
= 0;
2191 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2192 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2195 switch (senseBuffer
->SenseKey
& 0xf) {
2197 case SCSI_SENSE_NOT_READY
:
2199 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2200 *Status
= STATUS_DEVICE_NOT_READY
;
2202 switch (senseBuffer
->AdditionalSenseCode
) {
2204 case SCSI_ADSENSE_LUN_NOT_READY
:
2206 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2208 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2210 case SCSI_SENSEQ_BECOMING_READY
:
2212 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2213 " In process of becoming ready\n"));
2216 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2218 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2219 " Manual intervention required\n"));
2220 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2224 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2226 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2230 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2234 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2235 " Initializing command required\n"));
2238 // This sense code/additional sense code
2239 // combination may indicate that the device
2240 // needs to be started. Send an start unit if this
2241 // is a disk device.
2244 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2245 StartUnit(DeviceObject
);
2250 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2254 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2257 "ScsiClassInterpretSenseInfo:"
2258 " No Media in device.\n"));
2259 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2263 // signal autorun that there isn't any media in the device
2266 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2267 (!deviceExtension
->MediaChangeNoMedia
)) {
2268 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2271 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2272 "Detected No Media In Device "
2273 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2274 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2278 } // end switch (senseBuffer->AdditionalSenseCode)
2282 case SCSI_SENSE_DATA_PROTECT
:
2284 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2285 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2289 case SCSI_SENSE_MEDIUM_ERROR
:
2291 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2292 *Status
= STATUS_DEVICE_DATA_ERROR
;
2297 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2300 case SCSI_SENSE_HARDWARE_ERROR
:
2302 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2303 *Status
= STATUS_IO_DEVICE_ERROR
;
2307 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2311 case SCSI_SENSE_ILLEGAL_REQUEST
:
2313 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2314 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2316 switch (senseBuffer
->AdditionalSenseCode
) {
2318 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2319 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2323 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2324 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2325 *Status
= STATUS_NONEXISTENT_SECTOR
;
2329 case SCSI_ADSENSE_INVALID_LUN
:
2330 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2331 *Status
= STATUS_NO_SUCH_DEVICE
;
2335 case SCSI_ADSENSE_MUSIC_AREA
:
2336 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2340 case SCSI_ADSENSE_DATA_AREA
:
2341 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2345 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2346 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2350 case SCSI_ADSENSE_INVALID_CDB
:
2351 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2354 // Check if write cache enabled.
2357 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2360 // Assume FUA is not supported.
2363 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2372 } // end switch (senseBuffer->AdditionalSenseCode)
2376 case SCSI_SENSE_UNIT_ATTENTION
:
2378 switch (senseBuffer
->AdditionalSenseCode
) {
2379 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2380 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2382 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2384 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2387 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2388 "New Media Found - Setting MediaChanged event"
2389 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2390 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2395 case SCSI_ADSENSE_BUS_RESET
:
2396 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2400 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2403 } // end switch (senseBuffer->AdditionalSenseCode)
2405 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2406 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2409 // Set bit to indicate that media may have changed
2410 // and volume needs verification.
2413 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2415 *Status
= STATUS_VERIFY_REQUIRED
;
2420 *Status
= STATUS_IO_DEVICE_ERROR
;
2425 // A media change may have occured so increment the change
2426 // count for the physical device
2429 physicalExtension
->MediaChangeCount
++;
2431 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2432 "count for device %d is %d\n",
2433 physicalExtension
->DeviceNumber
,
2434 physicalExtension
->MediaChangeCount
));
2438 case SCSI_SENSE_ABORTED_COMMAND
:
2440 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2441 *Status
= STATUS_IO_DEVICE_ERROR
;
2444 case SCSI_SENSE_RECOVERED_ERROR
:
2446 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2447 *Status
= STATUS_SUCCESS
;
2452 switch(senseBuffer
->AdditionalSenseCode
) {
2453 case SCSI_ADSENSE_SEEK_ERROR
:
2454 case SCSI_ADSENSE_TRACK_ERROR
:
2455 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2458 case SCSI_ADSENSE_REC_DATA_NOECC
:
2459 case SCSI_ADSENSE_REC_DATA_ECC
:
2460 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2464 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2467 } // end switch(senseBuffer->AdditionalSenseCode)
2469 if (senseBuffer
->IncorrectLength
) {
2471 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2472 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2477 case SCSI_SENSE_NO_SENSE
:
2480 // Check other indicators.
2483 if (senseBuffer
->IncorrectLength
) {
2485 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2486 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2491 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2492 *Status
= STATUS_IO_DEVICE_ERROR
;
2500 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2501 *Status
= STATUS_IO_DEVICE_ERROR
;
2504 } // end switch (senseBuffer->SenseKey & 0xf)
2507 // Try to determine the bad sector from the inquiry data.
2510 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2511 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2512 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2514 for (index
= 0; index
< 4; index
++) {
2515 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2519 for (index
= 0; index
< 4; index
++) {
2520 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2523 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2524 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2527 // Make sure the bad sector is within the read sectors.
2530 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2531 badSector
= readSector
;
2538 // Request sense buffer not valid. No sense information
2539 // to pinpoint the error. Return general request fail.
2542 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2543 SRB_STATUS(Srb
->SrbStatus
)));
2546 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2547 case SRB_STATUS_INVALID_LUN
:
2548 case SRB_STATUS_INVALID_TARGET_ID
:
2549 case SRB_STATUS_NO_DEVICE
:
2550 case SRB_STATUS_NO_HBA
:
2551 case SRB_STATUS_INVALID_PATH_ID
:
2552 *Status
= STATUS_NO_SUCH_DEVICE
;
2556 case SRB_STATUS_COMMAND_TIMEOUT
:
2557 case SRB_STATUS_ABORTED
:
2558 case SRB_STATUS_TIMEOUT
:
2561 // Update the error count for the device.
2564 deviceExtension
->ErrorCount
++;
2565 *Status
= STATUS_IO_TIMEOUT
;
2568 case SRB_STATUS_SELECTION_TIMEOUT
:
2570 logStatus
= 0;//IO_ERR_NOT_READY;
2572 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2576 case SRB_STATUS_DATA_OVERRUN
:
2577 *Status
= STATUS_DATA_OVERRUN
;
2581 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2584 // Update the error count for the device.
2587 deviceExtension
->ErrorCount
++;
2588 *Status
= STATUS_IO_DEVICE_ERROR
;
2591 // If there was phase sequence error then limit the number of
2595 if (RetryCount
> 1 ) {
2601 case SRB_STATUS_REQUEST_FLUSHED
:
2604 // If the status needs verification bit is set. Then set
2605 // the status to need verification and no retry; otherwise,
2606 // just retry the request.
2609 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2611 *Status
= STATUS_VERIFY_REQUIRED
;
2614 *Status
= STATUS_IO_DEVICE_ERROR
;
2619 case SRB_STATUS_INVALID_REQUEST
:
2622 // An invalid request was attempted.
2625 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2629 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2630 case SRB_STATUS_PARITY_ERROR
:
2633 // Update the error count for the device.
2636 deviceExtension
->ErrorCount
++;
2639 // Fall through to below.
2642 case SRB_STATUS_BUS_RESET
:
2643 *Status
= STATUS_IO_DEVICE_ERROR
;
2646 case SRB_STATUS_ERROR
:
2648 *Status
= STATUS_IO_DEVICE_ERROR
;
2649 if (Srb
->ScsiStatus
== 0) {
2652 // This is some strange return code. Update the error
2653 // count for the device.
2656 deviceExtension
->ErrorCount
++;
2658 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2660 *Status
= STATUS_DEVICE_NOT_READY
;
2662 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2664 *Status
= STATUS_DEVICE_BUSY
;
2673 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2675 *Status
= STATUS_IO_DEVICE_ERROR
;
2681 // If the error count has exceeded the error limit, then disable
2682 // any tagged queuing, multiple requests per lu queueing
2683 // and sychronous data transfers.
2686 if (deviceExtension
->ErrorCount
== 4) {
2689 // Clearing the no queue freeze flag prevents the port driver
2690 // from sending multiple requests per logical unit.
2693 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2694 SRB_FLAGS_NO_QUEUE_FREEZE
);
2696 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2697 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2699 } else if (deviceExtension
->ErrorCount
== 8) {
2702 // If a second threshold is reached, disable disconnects.
2705 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
2706 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2711 // If there is a class specific error handler call it.
2714 if (deviceExtension
->ClassError
!= NULL
) {
2716 deviceExtension
->ClassError(DeviceObject
,
2723 // Log an error if necessary.
2728 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
2730 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
2732 if (errorLogEntry
== NULL
) {
2735 // Return if no packet could be allocated.
2742 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
2743 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
2745 errorLogEntry
->FinalStatus
= *Status
;
2749 // Calculate the device offset if there is a geometry.
2752 if (deviceExtension
->DiskGeometry
!= NULL
) {
2754 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
2755 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
2756 errorLogEntry
->DeviceOffset
,
2757 deviceExtension
->DiskGeometry
->BytesPerSector
);
2760 errorLogEntry
->ErrorCode
= logStatus
;
2761 errorLogEntry
->SequenceNumber
= 0;
2762 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
2763 errorLogEntry
->IoControlCode
= IoDeviceCode
;
2764 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
2765 errorLogEntry
->UniqueErrorValue
= uniqueId
;
2766 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
2767 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
2768 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
2769 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
2770 errorLogEntry
->DumpData
[3] = 0;
2771 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
2773 if (senseBuffer
!= NULL
) {
2774 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
2775 senseBuffer
->AdditionalSenseCode
<< 8 |
2776 senseBuffer
->AdditionalSenseCodeQualifier
;
2781 // Write the error log packet.
2784 IoWriteErrorLogEntry(errorLogEntry
);
2789 } // end ScsiClassInterpretSenseInfo()
2795 PDEVICE_OBJECT DeviceObject
,
2797 PSCSI_REQUEST_BLOCK Srb
,
2803 Routine Description:
2805 This routine reinitalizes the necessary fields, and sends the request
2810 DeviceObject - Supplies the device object associated with this request.
2812 Irp - Supplies the request to be retried.
2814 Srb - Supplies a Pointer to the SCSI request block to be retied.
2816 Assocaiated - Indicates this is an assocatied Irp created by split request.
2825 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2826 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2827 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2828 ULONG transferByteCount
;
2831 // Determine the transfer count of the request. If this is a read or a
2832 // write then the transfer count is in the Irp stack. Otherwise assume
2833 // the MDL contains the correct length. If there is no MDL then the
2834 // transfer length must be zero.
2837 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
2838 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
2840 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2842 } else if (Irp
->MdlAddress
!= NULL
) {
2845 // Note this assumes that only read and write requests are spilt and
2846 // other request do not need to be. If the data buffer address in
2847 // the MDL and the SRB don't match then transfer length is most
2848 // likely incorrect.
2851 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2852 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
2856 transferByteCount
= 0;
2860 // Reset byte count of transfer in SRB Extension.
2863 Srb
->DataTransferLength
= transferByteCount
;
2866 // Zero SRB statuses.
2869 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
2872 // Set the no disconnect flag, disable synchronous data transfers and
2873 // disable tagged queuing. This fixes some errors.
2876 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
2877 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2879 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
2880 Srb
->QueueTag
= SP_UNTAGGED
;
2883 // Set up major SCSI function.
2886 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2889 // Save SRB address in next stack for port driver.
2892 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
2895 // Set up IoCompletion routine address.
2900 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
2904 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
2908 // Pass the request to the port driver.
2911 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2913 } // end RetryRequest()
2917 ScsiClassBuildRequest(
2918 PDEVICE_OBJECT DeviceObject
,
2924 Routine Description:
2926 This routine allocates and builds an Srb for a read or write request.
2927 The block address and length are supplied by the Irp. The retry count
2928 is stored in the current stack for use by ScsiClassIoComplete which
2929 processes these requests when they complete. The Irp is ready to be
2930 passed to the port driver when this routine returns.
2934 DeviceObject - Supplies the device object associated with this request.
2936 Irp - Supplies the request to be retried.
2940 If the IRP is for a disk transfer, the byteoffset field
2941 will already have been adjusted to make it relative to
2942 the beginning of the disk.
2952 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2953 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2954 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2955 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2956 PSCSI_REQUEST_BLOCK srb
;
2958 ULONG logicalBlockAddress
;
2959 USHORT transferBlocks
;
2962 // Calculate relative sector address.
2965 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
2971 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
2976 // Write length to SRB.
2979 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2982 // Set up IRP Address.
2985 srb
->OriginalRequest
= Irp
;
2988 // Set up target ID and logical unit number.
2991 srb
->PathId
= deviceExtension
->PathId
;
2992 srb
->TargetId
= deviceExtension
->TargetId
;
2993 srb
->Lun
= deviceExtension
->Lun
;
2994 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2995 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2998 // Save byte count of transfer in SRB Extension.
3001 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3004 // Initialize the queue actions field.
3007 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3010 // Queue sort key is Relative Block Address.
3013 srb
->QueueSortKey
= logicalBlockAddress
;
3016 // Indicate auto request sense by specifying buffer and size.
3019 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3020 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3023 // Set timeout value of one unit per 64k bytes of data.
3026 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3027 deviceExtension
->TimeOutValue
;
3033 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3037 // Indicate that 10-byte CDB's will be used.
3040 srb
->CdbLength
= 10;
3043 // Fill in CDB fields.
3046 cdb
= (PCDB
)srb
->Cdb
;
3049 // Zero 12 bytes for Atapi Packets
3052 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3054 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3055 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3058 // Move little endian values into CDB in big endian format.
3061 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3062 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3063 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3064 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3066 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3067 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3070 // Set transfer direction flag and Cdb command.
3073 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3075 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3077 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3078 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3082 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3084 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3085 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3089 // If this is not a write-through request, then allow caching.
3092 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3094 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3099 // If write caching is enable then force media access in the
3103 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3104 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3109 // Or in the default flags from the device object.
3112 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3115 // Set up major SCSI function.
3118 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3121 // Save SRB address in next stack for port driver.
3124 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3127 // Save retry count in current IRP stack.
3130 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3133 // Set up IoCompletion routine address.
3136 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3140 } // end ScsiClassBuildRequest()
3145 IN PDEVICE_OBJECT DeviceObject
,
3146 IN PCHAR ModeSenseBuffer
,
3153 Routine Description:
3155 This routine sends a mode sense command to a target ID and returns
3156 when it is complete.
3160 DeviceObject - Supplies the device object associated with this request.
3162 ModeSenseBuffer - Supplies a buffer to store the sense data.
3164 Length - Supplies the length in bytes of the mode sense buffer.
3166 PageMode - Supplies the page or pages of mode sense data to be retrived.
3170 Length of the transferred data is returned.
3174 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3176 SCSI_REQUEST_BLOCK srb
;
3180 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3183 // Build the MODE SENSE CDB.
3187 cdb
= (PCDB
)srb
.Cdb
;
3190 // Set timeout value from device extension.
3193 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3195 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3196 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3197 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3201 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3208 if (status
== STATUS_VERIFY_REQUIRED
) {
3211 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3212 // this status. MODE SENSE commands should be retried anyway.
3224 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3225 status
= STATUS_SUCCESS
;
3228 if (NT_SUCCESS(status
)) {
3229 return(srb
.DataTransferLength
);
3234 } // end ScsiClassModeSense()
3239 ScsiClassFindModePage(
3240 IN PCHAR ModeSenseBuffer
,
3248 Routine Description:
3250 This routine scans through the mode sense data and finds the requested
3251 mode sense page code.
3254 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3256 Length - Indicates the length of valid data.
3258 PageMode - Supplies the page mode to be searched for.
3260 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3264 A pointer to the the requested mode page. If the mode page was not found
3265 then NULL is return.
3270 ULONG parameterHeaderLength
;
3272 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3273 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3277 // Skip the mode select header and block descriptors.
3280 if (Length
< parameterHeaderLength
) {
3286 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3287 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3290 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3291 // requested page until the limit is reached.
3295 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3297 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3298 return(ModeSenseBuffer
);
3302 // Advance to the next page.
3305 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3313 ScsiClassSendSrbAsynchronous(
3314 PDEVICE_OBJECT DeviceObject
,
3315 PSCSI_REQUEST_BLOCK Srb
,
3317 PVOID BufferAddress
,
3319 BOOLEAN WriteToDevice
3323 Routine Description:
3325 This routine takes a partially built Srb and an Irp and sends it down to
3329 DeviceObject - Supplies the device object for the orginal request.
3331 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3332 CDB and the SRB timeout value must be filled in. The SRB must not be
3333 allocated from zone.
3335 Irp - Supplies the requesting Irp.
3337 BufferAddress - Supplies a pointer to the buffer to be transfered.
3339 BufferLength - Supplies the length of data transfer.
3341 WriteToDevice - Indicates the data transfer will be from system memory to
3346 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3351 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3352 PIO_STACK_LOCATION irpStack
;
3357 // Write length to SRB.
3360 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3363 // Set SCSI bus address.
3366 Srb
->PathId
= deviceExtension
->PathId
;
3367 Srb
->TargetId
= deviceExtension
->TargetId
;
3368 Srb
->Lun
= deviceExtension
->Lun
;
3370 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3373 // This is a violation of the SCSI spec but it is required for
3377 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3380 // Indicate auto request sense by specifying buffer and size.
3383 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3384 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3385 Srb
->DataBuffer
= BufferAddress
;
3387 if (BufferAddress
!= NULL
) {
3390 // Build Mdl if necessary.
3393 if (Irp
->MdlAddress
== NULL
) {
3395 if (IoAllocateMdl(BufferAddress
,
3401 return(STATUS_INSUFFICIENT_RESOURCES
);
3404 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3409 // Make sure the buffer requested matches the MDL.
3412 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3419 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3427 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3431 // Disable synchronous transfer for these requests.
3434 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3437 // Set the transfer length.
3440 Srb
->DataTransferLength
= BufferLength
;
3446 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3451 // Save a few parameters in the current stack location.
3454 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3457 // Save retry count in current Irp stack.
3460 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3463 // Set up IoCompletion routine address.
3466 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3469 // Get next stack location and
3470 // set major function code.
3473 irpStack
= IoGetNextIrpStackLocation(Irp
);
3475 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3478 // Save SRB address in next stack for port driver.
3481 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3484 // Set up Irp Address.
3487 Srb
->OriginalRequest
= Irp
;
3490 // Call the port driver to process the request.
3493 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3500 ScsiClassDeviceControlDispatch(
3501 PDEVICE_OBJECT DeviceObject
,
3507 Routine Description:
3509 The routine is the common class driver device control dispatch entry point.
3510 This routine is invokes the device-specific drivers DeviceControl routine,
3511 (which may call the Class driver's common DeviceControl routine).
3515 DeviceObject - Supplies a pointer to the device object for this request.
3517 Irp - Supplies the Irp making the request.
3521 Returns the status returned from the device-specific driver.
3527 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3531 // Call the class specific driver DeviceControl routine.
3532 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3535 ASSERT(deviceExtension
->ClassDeviceControl
);
3537 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3543 ScsiClassDeviceControl(
3544 PDEVICE_OBJECT DeviceObject
,
3549 Routine Description:
3551 The routine is the common class driver device control dispatch function.
3552 This routine is called by a class driver when it get an unrecognized
3553 device control request. This routine will perform the correct action for
3554 common requests such as lock media. If the device request is unknown it
3555 passed down to the next level.
3559 DeviceObject - Supplies a pointer to the device object for this request.
3561 Irp - Supplies the Irp making the request.
3565 Returns back a STATUS_PENDING or a completion status.
3570 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3571 PIO_STACK_LOCATION nextStack
;
3572 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3573 PSCSI_REQUEST_BLOCK srb
;
3576 ULONG modifiedIoControlCode
;
3578 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3579 IOCTL_STORAGE_RESET_DEVICE
) {
3581 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3582 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3583 status
= STATUS_UNSUCCESSFUL
;
3584 goto SetStatusAndReturn
;
3588 // If this is a pass through I/O control, set the minor function code
3589 // and device address and pass it to the port driver.
3592 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3593 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3595 PSCSI_PASS_THROUGH scsiPass
;
3597 nextStack
= IoGetNextIrpStackLocation(Irp
);
3600 // Validiate the user buffer.
3603 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3605 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3606 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3607 status
= STATUS_INVALID_PARAMETER
;
3608 goto SetStatusAndReturn
;
3612 // Force the SCSI address to the correct value.
3615 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3616 scsiPass
->PathId
= deviceExtension
->PathId
;
3617 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3618 scsiPass
->Lun
= deviceExtension
->Lun
;
3621 // NOTICE: The SCSI-II specificaiton indicates that this field
3622 // should be zero; however, some target controllers ignore the logical
3623 // unit number in the INDENTIFY message and only look at the logical
3624 // unit number field in the CDB.
3627 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3629 nextStack
->Parameters
= irpStack
->Parameters
;
3630 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3631 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3633 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3634 goto SetStatusAndReturn
;
3637 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3639 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3641 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3642 sizeof(SCSI_ADDRESS
)) {
3645 // Indicate unsuccessful status and no data transferred.
3648 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3649 Irp
->IoStatus
.Information
= 0;
3650 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3651 status
= STATUS_BUFFER_TOO_SMALL
;
3652 goto SetStatusAndReturn
;
3656 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3657 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3658 scsiAddress
->PathId
= deviceExtension
->PathId
;
3659 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3660 scsiAddress
->Lun
= deviceExtension
->Lun
;
3661 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3662 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3663 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3664 status
= STATUS_SUCCESS
;
3665 goto SetStatusAndReturn
;
3668 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3672 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3673 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3674 status
= STATUS_INSUFFICIENT_RESOURCES
;
3675 goto SetStatusAndReturn
;
3679 // Write zeros to Srb.
3682 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3684 cdb
= (PCDB
)srb
->Cdb
;
3687 // Change the device type to disk for the switch statement.
3690 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3691 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3693 switch (modifiedIoControlCode
) {
3695 case IOCTL_DISK_CHECK_VERIFY
: {
3698 PIO_STACK_LOCATION newStack
;
3700 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3703 // If a buffer for a media change count was provided, make sure it's
3704 // big enough to hold the result
3707 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
3710 // If the buffer is too small to hold the media change count
3711 // then return an error to the caller
3714 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3717 DebugPrint((3,"ScsiDeviceIoControl: media count "
3718 "buffer too small\n"));
3720 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3721 Irp
->IoStatus
.Information
= 0;
3723 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3724 status
= STATUS_BUFFER_TOO_SMALL
;
3725 goto SetStatusAndReturn
;
3730 // The caller has provided a valid buffer. Allocate an additional
3731 // irp and stick the CheckVerify completion routine on it. We will
3732 // then send this down to the port driver instead of the irp the
3736 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
3740 // Allocate a new irp to send the TestUnitReady to the port driver
3743 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
3746 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3747 Irp
->IoStatus
.Information
= 0;
3749 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3750 status
= STATUS_INSUFFICIENT_RESOURCES
;
3751 goto SetStatusAndReturn
;
3756 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
3757 IoSetNextIrpStackLocation(irp2
);
3760 // Set the top stack location and shove the master Irp into the
3764 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3765 newStack
->Parameters
.Others
.Argument1
= Irp
;
3766 newStack
->DeviceObject
= DeviceObject
;
3769 // Stick the check verify completion routine onto the stack
3770 // and prepare the irp for the port driver
3773 IoSetCompletionRoutine(irp2
,
3774 ScsiClassCheckVerifyComplete
,
3780 IoSetNextIrpStackLocation(irp2
);
3781 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3782 newStack
->DeviceObject
= DeviceObject
;
3785 // Mark the master irp as pending - whether the lower level
3786 // driver completes it immediately or not this should allow it
3787 // to go all the way back up.
3790 IoMarkIrpPending(Irp
);
3801 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
3804 // Set timeout value.
3807 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3810 // Since this routine will always hand the request to the
3811 // port driver if there isn't a data transfer to be done
3812 // we don't have to worry about completing the request here
3816 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3826 case IOCTL_DISK_MEDIA_REMOVAL
: {
3828 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
3831 // Prevent/Allow media removal.
3834 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
3836 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
3837 sizeof(PREVENT_MEDIA_REMOVAL
)) {
3840 // Indicate unsuccessful status and no data transferred.
3843 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3844 Irp
->IoStatus
.Information
= 0;
3846 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3847 status
= STATUS_BUFFER_TOO_SMALL
;
3848 goto SetStatusAndReturn
;
3852 // Get physical device extension. This is where the
3853 // lock count is stored.
3856 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
3859 // If command succeeded then increment or decrement lock counter.
3862 if (MediaRemoval
->PreventMediaRemoval
) {
3865 // This is a lock command. Reissue the command in case bus or device
3866 // was reset and lock cleared.
3869 InterlockedIncrement(&deviceExtension
->LockCount
);
3872 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
3873 deviceExtension
->LockCount
,
3874 deviceExtension
->DeviceNumber
));
3879 // This is an unlock command.
3882 if (!deviceExtension
->LockCount
||
3883 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
3886 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3887 deviceExtension
->LockCount
,
3888 deviceExtension
->DeviceNumber
));
3891 // Don't unlock because someone still wants it locked.
3894 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3896 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3897 status
= STATUS_SUCCESS
;
3898 goto SetStatusAndReturn
;
3902 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3903 deviceExtension
->LockCount
,
3904 deviceExtension
->DeviceNumber
));
3909 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3912 // TRUE - prevent media removal.
3913 // FALSE - allow media removal.
3916 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
3919 // Set timeout value.
3922 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3923 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3931 // Some devices will not support lock/unlock.
3932 // Pretend that it worked.
3938 case IOCTL_DISK_RESERVE
: {
3941 // Reserve logical unit.
3946 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
3949 // Set timeout value.
3952 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3954 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3964 case IOCTL_DISK_RELEASE
: {
3967 // Release logical unit.
3972 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
3975 // Set timeout value.
3978 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3980 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3990 case IOCTL_DISK_EJECT_MEDIA
: {
3998 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
3999 cdb
->START_STOP
.LoadEject
= 1;
4000 cdb
->START_STOP
.Start
= 0;
4003 // Set timeout value.
4006 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4007 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4016 case IOCTL_DISK_LOAD_MEDIA
: {
4022 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4026 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4027 cdb
->START_STOP
.LoadEject
= 1;
4028 cdb
->START_STOP
.Start
= 1;
4031 // Set timeout value.
4034 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4035 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4045 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4048 // Search for devices that have been powered on since the last
4049 // device search or system initialization.
4052 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4053 status
= DriverEntry(DeviceObject
->DriverObject
,
4056 Irp
->IoStatus
.Status
= status
;
4058 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4065 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4068 // Pass the device control to the next driver.
4074 // Copy the Irp stack parameters to the next stack location.
4077 nextStack
= IoGetNextIrpStackLocation(Irp
);
4078 nextStack
->Parameters
= irpStack
->Parameters
;
4079 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4080 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4082 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4086 } // end switch( ...
4096 ScsiClassShutdownFlush(
4097 IN PDEVICE_OBJECT DeviceObject
,
4103 Routine Description:
4105 This routine is called for a shutdown and flush IRPs. These are sent by the
4106 system before it actually shuts down or when the file system does a flush.
4107 If it exists, the device-specific driver's routine will be invoked. If there
4108 wasn't one specified, the Irp will be completed with an Invalid device request.
4112 DriverObject - Pointer to device object to being shutdown by system.
4123 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4125 if (deviceExtension
->ClassShutdownFlush
) {
4128 // Call the device-specific driver's routine.
4131 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4135 // Device-specific driver doesn't support this.
4138 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4139 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4141 return STATUS_INVALID_DEVICE_REQUEST
;
4147 ScsiClassFindUnclaimedDevices(
4148 IN PCLASS_INIT_DATA InitializationData
,
4149 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4153 ULONG scsiBus
,deviceCount
= 0;
4154 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4155 PSCSI_INQUIRY_DATA lunInfo
;
4156 PINQUIRYDATA inquiryData
;
4158 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4161 // Get the SCSI bus scan data for this bus.
4164 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4167 // Search list for unclaimed disk devices.
4170 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4172 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4174 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4176 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4181 if (lunInfo
->NextInquiryDataOffset
== 0) {
4185 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4195 ScsiClassCreateDeviceObject(
4196 IN PDRIVER_OBJECT DriverObject
,
4197 IN PCCHAR ObjectNameBuffer
,
4198 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4199 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4200 IN PCLASS_INIT_DATA InitializationData
4205 Routine Description:
4207 This routine creates an object for the physical device specified and
4208 sets up the deviceExtension's function pointers for each entry point
4209 in the device-specific driver.
4213 DriverObject - Pointer to driver object created by system.
4215 ObjectNameBuffer - Dir. name of the object to create.
4217 PhysicalDeviceObject - Pointer to the physical (class) device object for
4218 this logical unit or NULL if this is it.
4220 DeviceObject - Pointer to the device object pointer we will return.
4222 InitializationData - Pointer to the init data created by the device-specific driver.
4231 STRING ntNameString
;
4232 UNICODE_STRING ntUnicodeString
;
4234 PDEVICE_OBJECT deviceObject
= NULL
;
4236 *DeviceObject
= NULL
;
4239 "ScsiClassCreateDeviceObject: Create device object %s\n",
4242 RtlInitString(&ntNameString
,
4245 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4249 if (!NT_SUCCESS(status
)) {
4252 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4255 ntUnicodeString
.Buffer
= NULL
;
4259 status
= IoCreateDevice(DriverObject
,
4260 InitializationData
->DeviceExtensionSize
,
4262 InitializationData
->DeviceType
,
4263 InitializationData
->DeviceCharacteristics
,
4268 if (!NT_SUCCESS(status
)) {
4271 "CreateDiskDeviceObjects: Can not create device object %s\n",
4276 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4279 // Fill in entry points
4282 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4283 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4284 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4285 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4286 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4287 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4288 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4290 deviceExtension
->MediaChangeCount
= 0;
4293 // If a pointer to the physical device object was passed in then use
4294 // that. If the value was NULL, then this is the physical device so
4295 // use the pointer to the device we just created.
4298 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4299 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4301 deviceExtension
->PhysicalDevice
= deviceObject
;
4305 *DeviceObject
= deviceObject
;
4307 RtlFreeUnicodeString(&ntUnicodeString
);
4310 // Indicate the ntUnicodeString is free.
4313 ntUnicodeString
.Buffer
= NULL
;
4321 ScsiClassClaimDevice(
4322 IN PDEVICE_OBJECT PortDeviceObject
,
4323 IN PSCSI_INQUIRY_DATA LunInfo
,
4325 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4329 Routine Description:
4331 This function claims a device in the port driver. The port driver object
4332 is updated with the correct driver object if the device is successfully
4337 PortDeviceObject - Supplies the base port device object.
4339 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4341 Release - Indicates the logical unit should be released rather than claimed.
4343 NewPortDeviceObject - Returns the updated port device object to be used
4344 for all future accesses.
4348 Returns a status indicating success or failure of the operation.
4353 IO_STATUS_BLOCK ioStatus
;
4355 PIO_STACK_LOCATION irpStack
;
4358 SCSI_REQUEST_BLOCK srb
;
4362 if (NewPortDeviceObject
!= NULL
) {
4363 *NewPortDeviceObject
= NULL
;
4367 // Clear the SRB fields.
4370 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4373 // Write length to SRB.
4376 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4379 // Set SCSI bus address.
4382 srb
.PathId
= LunInfo
->PathId
;
4383 srb
.TargetId
= LunInfo
->TargetId
;
4384 srb
.Lun
= LunInfo
->Lun
;
4386 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4387 SRB_FUNCTION_CLAIM_DEVICE
;
4390 // Set the event object to the unsignaled state.
4391 // It will be used to signal request completion.
4394 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4397 // Build synchronous request with no transfer.
4400 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4412 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4413 return STATUS_INSUFFICIENT_RESOURCES
;
4416 irpStack
= IoGetNextIrpStackLocation(irp
);
4419 // Save SRB address in next stack for port driver.
4422 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4425 // Set up IRP Address.
4428 srb
.OriginalRequest
= irp
;
4431 // Call the port driver with the request and wait for it to complete.
4434 status
= IoCallDriver(PortDeviceObject
, irp
);
4435 if (status
== STATUS_PENDING
) {
4437 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4438 status
= ioStatus
.Status
;
4442 // If this is a release request, then just decrement the reference count
4443 // and return. The status does not matter.
4448 ObDereferenceObject(PortDeviceObject
);
4449 return STATUS_SUCCESS
;
4452 if (!NT_SUCCESS(status
)) {
4456 ASSERT(srb
.DataBuffer
!= NULL
);
4459 // Reference the new port driver object so that it will not go away while
4460 // it is being used.
4463 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4468 if (!NT_SUCCESS(status
)) {
4474 // Return the new port device object pointer.
4477 if (NewPortDeviceObject
!= NULL
) {
4478 *NewPortDeviceObject
= srb
.DataBuffer
;
4487 ScsiClassInternalIoControl (
4488 IN PDEVICE_OBJECT DeviceObject
,
4494 Routine Description:
4496 This routine passes internal device controls to the port driver.
4497 Internal device controls are used by higher level class drivers to
4498 send scsi requests to a device that are not normally sent by a generic
4501 The path ID, target ID and logical unit ID are set in the srb so the
4502 higher level driver does not have to figure out what values are actually
4507 DeviceObject - Supplies a pointer to the device object for this request.
4509 Irp - Supplies the Irp making the request.
4513 Returns back a STATUS_PENDING or a completion status.
4517 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4518 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4519 PSCSI_REQUEST_BLOCK srb
;
4522 // Get a pointer to the SRB.
4525 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4528 // Set SCSI bus address.
4531 srb
->PathId
= deviceExtension
->PathId
;
4532 srb
->TargetId
= deviceExtension
->TargetId
;
4533 srb
->Lun
= deviceExtension
->Lun
;
4536 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4537 // zero; however, some target controllers ignore the logical unit number
4538 // in the INDENTIFY message and only look at the logical unit number field
4542 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4545 // Set the parameters in the next stack location.
4548 irpStack
= IoGetNextIrpStackLocation(Irp
);
4550 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4551 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4552 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4554 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4555 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4561 IN PDEVICE_OBJECT DeviceObject
,
4568 Routine Description:
4570 This routine is called when an internal device control I/O request
4571 has completed. It marks the IRP pending if necessary and returns the
4572 status of the request.
4576 DeviceObject - Target device object.
4578 Irp - Completed request.
4584 Returns the status of the completed request.
4589 UNREFERENCED_PARAMETER(Context
);
4590 UNREFERENCED_PARAMETER(DeviceObject
);
4593 // If pending is returned for this Irp then mark current stack
4597 if (Irp
->PendingReturned
) {
4599 IoMarkIrpPending( Irp
);
4602 return Irp
->IoStatus
.Status
;
4608 ScsiClassInitializeSrbLookasideList(
4609 IN PDEVICE_EXTENSION DeviceExtension
,
4610 IN ULONG NumberElements
4615 Routine Description:
4617 This routine sets up a lookaside listhead for srbs.
4621 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4623 NumberElements - Supplies the maximum depth of the lookaside list.
4633 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4636 NonPagedPoolMustSucceed
,
4637 SCSI_REQUEST_BLOCK_SIZE
,
4638 TAG('H','s','c','S'),
4639 (USHORT
)NumberElements
);
4646 ScsiClassQueryTimeOutRegistryValue(
4647 IN PUNICODE_STRING RegistryPath
4652 Routine Description:
4654 This routine determines whether a reg key for a user-specified timeout value exists.
4658 RegistryPath - Pointer to the hardware reg. entry describing the key.
4662 New default timeout for a class of devices.
4668 // Find the appropriate reg. key
4671 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4678 if (!RegistryPath
) {
4682 parameters
= ExAllocatePool(NonPagedPool
,
4683 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4689 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4690 path
= ExAllocatePool(NonPagedPool
, size
);
4693 ExFreePool(parameters
);
4697 RtlZeroMemory(path
,size
);
4698 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
4702 // Check for the Timeout value.
4705 RtlZeroMemory(parameters
,
4706 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
4708 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
4709 parameters
[0].Name
= L
"TimeOutValue";
4710 parameters
[0].EntryContext
= &timeOut
;
4711 parameters
[0].DefaultType
= REG_DWORD
;
4712 parameters
[0].DefaultData
= &zero
;
4713 parameters
[0].DefaultLength
= sizeof(ULONG
);
4715 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
4721 if (!(NT_SUCCESS(status
))) {
4725 ExFreePool(parameters
);
4729 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
4739 ScsiClassCheckVerifyComplete(
4740 IN PDEVICE_OBJECT DeviceObject
,
4747 Routine Description:
4749 This routine executes when the port driver has completed a check verify
4750 ioctl. It will set the status of the master Irp, copy the media change
4751 count and complete the request.
4755 DeviceObject - Supplies the device object which represents the logical
4758 Irp - Supplies the Irp which has completed.
4769 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4770 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4771 PDEVICE_EXTENSION physicalExtension
=
4772 deviceExtension
->PhysicalDevice
->DeviceExtension
;
4775 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
4778 // Copy the media change count and status
4781 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
4782 physicalExtension
->MediaChangeCount
;
4784 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
4785 "device %d is %d\n",
4786 physicalExtension
->DeviceNumber
,
4787 physicalExtension
->MediaChangeCount
));
4789 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
4790 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
4792 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
4796 return STATUS_MORE_PROCESSING_REQUIRED
;
4801 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
4805 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
4806 PKEVENT Event
= Irp
->UserEvent
;
4809 *IoStatusBlock
= Irp
->IoStatus
;
4810 Irp
->UserIosb
= NULL
;
4811 Irp
->UserEvent
= NULL
;
4815 Mdl
= Irp
->MdlAddress
;
4817 // if necessary - unlock pages
4818 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
4819 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
4828 // free irp and set event to unsignaled state
4830 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
4832 return STATUS_MORE_PROCESSING_REQUIRED
;