2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/class2/class2.c
5 * PURPOSE: SCSI Class driver routines
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
12 #include <include/class2.h>
19 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
20 #pragma alloc_text(PAGE, ScsiClassInitialize)
21 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
22 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
23 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
24 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
28 #define INQUIRY_DATA_SIZE 2048
29 #define START_UNIT_TIMEOUT 30
34 IN PDEVICE_OBJECT DeviceObject
,
41 IN PDEVICE_OBJECT DeviceObject
,
47 ScsiClassDeviceControlDispatch(
48 PDEVICE_OBJECT DeviceObject
,
54 ScsiClassDeviceControl(
55 PDEVICE_OBJECT DeviceObject
,
61 ScsiClassInternalIoControl (
62 IN PDEVICE_OBJECT DeviceObject
,
68 ScsiClassShutdownFlush(
69 IN PDEVICE_OBJECT DeviceObject
,
76 IN PDRIVER_OBJECT DriverObject
,
77 IN PUNICODE_STRING RegistryPath
81 // Class internal routines
88 PDEVICE_OBJECT DeviceObject
,
90 PSCSI_REQUEST_BLOCK Srb
,
97 IN PDEVICE_OBJECT DeviceObject
103 IN PDEVICE_OBJECT DeviceObject
,
110 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
118 IN PDRIVER_OBJECT DriverObject
,
119 IN PUNICODE_STRING RegistryPath
122 return STATUS_SUCCESS
;
131 IN PCLASS_INIT_DATA InitializationData
138 This routine is called by a class driver during its
139 DriverEntry routine to initialize the driver.
143 Argument1 - Driver Object.
144 Argument2 - Registry Path.
145 InitializationData - Device-specific driver's initialization data.
149 A valid return code for a DriverEntry routine.
156 PDRIVER_OBJECT DriverObject
= Argument1
;
157 ULONG portNumber
= 0;
158 PDEVICE_OBJECT portDeviceObject
;
160 STRING deviceNameString
;
161 UNICODE_STRING unicodeDeviceName
;
162 PFILE_OBJECT fileObject
;
163 CCHAR deviceNameBuffer
[256];
164 BOOLEAN deviceFound
= FALSE
;
166 DebugPrint((3,"\n\nSCSI Class Driver\n"));
169 // Validate the length of this structure. This is effectively a
173 if (InitializationData
->InitializationDataSize
> sizeof(CLASS_INIT_DATA
)) {
175 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
176 return (ULONG
) STATUS_REVISION_MISMATCH
;
180 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
181 // are not required entry points.
184 if ((!InitializationData
->ClassFindDevices
) ||
185 (!InitializationData
->ClassDeviceControl
) ||
186 (!((InitializationData
->ClassReadWriteVerification
) ||
187 (InitializationData
->ClassStartIo
)))) {
190 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
192 return (ULONG
) STATUS_REVISION_MISMATCH
;
196 // Update driver object with entry points.
199 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiClassCreateClose
;
200 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiClassCreateClose
;
201 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScsiClassReadWrite
;
202 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScsiClassReadWrite
;
203 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiClassInternalIoControl
;
204 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiClassDeviceControlDispatch
;
205 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = ScsiClassShutdownFlush
;
206 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = ScsiClassShutdownFlush
;
208 if (InitializationData
->ClassStartIo
) {
209 DriverObject
->DriverStartIo
= InitializationData
->ClassStartIo
;
213 // Open port driver controller device objects by name.
218 sprintf(deviceNameBuffer
, "\\Device\\ScsiPort%lu", portNumber
);
220 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer
));
222 RtlInitString(&deviceNameString
, deviceNameBuffer
);
224 status
= RtlAnsiStringToUnicodeString(&unicodeDeviceName
,
228 if (!NT_SUCCESS(status
)){
232 status
= IoGetDeviceObjectPointer(&unicodeDeviceName
,
233 FILE_READ_ATTRIBUTES
,
237 if (NT_SUCCESS(status
)) {
240 // Call the device-specific driver's FindDevice routine.
243 if (InitializationData
->ClassFindDevices(DriverObject
, Argument2
, InitializationData
,
244 portDeviceObject
, portNumber
)) {
251 // Check next SCSI adapter.
256 } while(NT_SUCCESS(status
));
258 return deviceFound
? STATUS_SUCCESS
: STATUS_NO_SUCH_DEVICE
;
264 ScsiClassCreateClose(
265 IN PDEVICE_OBJECT DeviceObject
,
273 SCSI class driver create and close routine. This is called by the I/O system
274 when the device is opened or closed.
278 DriverObject - Pointer to driver object created by system.
284 Device-specific drivers return value or STATUS_SUCCESS.
289 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
292 // Invoke the device-specific routine, if one exists. Otherwise complete
296 if (deviceExtension
->ClassCreateClose
) {
298 return deviceExtension
->ClassCreateClose(DeviceObject
, Irp
);
301 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
303 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
304 return(STATUS_SUCCESS
);
313 IN PDEVICE_OBJECT DeviceObject
,
321 This is the system entry point for read and write requests. The device-specific handler is invoked
322 to perform any validation necessary. The number of bytes in the request are
323 checked against the maximum byte counts that the adapter supports and requests are broken up into
324 smaller sizes if necessary.
338 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
339 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
341 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
342 ULONG maximumTransferLength
= deviceExtension
->PortCapabilities
->MaximumTransferLength
;
345 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
&&
346 !(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
349 // if DO_VERIFY_VOLUME bit is set
350 // in device object flags, fail request.
353 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
355 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
356 Irp
->IoStatus
.Information
= 0;
358 IoCompleteRequest(Irp
, 0);
359 return STATUS_VERIFY_REQUIRED
;
363 // Invoke the device specific routine to do whatever it needs to verify
367 ASSERT(deviceExtension
->ClassReadWriteVerification
);
369 status
= deviceExtension
->ClassReadWriteVerification(DeviceObject
,Irp
);
371 if (!NT_SUCCESS(status
)) {
374 // It is up to the device specific driver to set the Irp status.
377 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
379 } else if (status
== STATUS_PENDING
) {
381 IoMarkIrpPending(Irp
);
382 return STATUS_PENDING
;
386 // Check for a zero length IO, as several macros will turn this into
387 // seemingly a 0xffffffff length request.
390 if (transferByteCount
== 0) {
391 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
392 Irp
->IoStatus
.Information
= 0;
393 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
394 return STATUS_SUCCESS
;
398 if (deviceExtension
->ClassStartIo
) {
400 IoMarkIrpPending(Irp
);
402 IoStartPacket(DeviceObject
,
407 return STATUS_PENDING
;
411 // Mark IRP with status pending.
414 IoMarkIrpPending(Irp
);
417 // Add partition byte offset to make starting byte relative to
418 // beginning of disk. In addition, add in skew for DM Driver, if any.
421 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+= (deviceExtension
->StartingOffset
.QuadPart
+
422 deviceExtension
->DMByteSkew
);
425 // Calculate number of pages in this transfer.
428 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
429 currentIrpStack
->Parameters
.Read
.Length
);
432 // Check if request length is greater than the maximum number of
433 // bytes that the hardware can transfer.
436 if (currentIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
||
437 transferPages
> deviceExtension
->PortCapabilities
->MaximumPhysicalPages
) {
439 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
440 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
441 maximumTransferLength
));
442 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
443 currentIrpStack
->Parameters
.Read
.Length
));
446 deviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
448 if (maximumTransferLength
> transferPages
<< PAGE_SHIFT
) {
449 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
453 // Check that maximum transfer size is not zero.
456 if (maximumTransferLength
== 0) {
457 maximumTransferLength
= PAGE_SIZE
;
461 // Mark IRP with status pending.
464 IoMarkIrpPending(Irp
);
467 // Request greater than port driver maximum.
468 // Break up into smaller routines.
471 ScsiClassSplitRequest(DeviceObject
, Irp
, maximumTransferLength
);
474 return STATUS_PENDING
;
478 // Build SRB and CDB for this IRP.
481 ScsiClassBuildRequest(DeviceObject
, Irp
);
484 // Return the results of the call to the port driver.
487 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
489 } // end ScsiClassReadWrite()
494 ScsiClassGetCapabilities(
495 IN PDEVICE_OBJECT PortDeviceObject
,
496 OUT PIO_SCSI_CAPABILITIES
*PortCapabilities
503 This routine builds and sends a request to the port driver to
504 get a pointer to a structure that describes the adapter's
505 capabilities/limitations. This routine is sychronous.
509 PortDeviceObject - Port driver device object representing the HBA.
511 PortCapabilities - Location to store pointer to capabilities structure.
515 Nt status indicating the results of the operation.
519 This routine should only be called at initialization time.
525 IO_STATUS_BLOCK ioStatus
;
532 // Create notification event object to be used to signal the
533 // request completion.
536 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
539 // Build the synchronous request to be sent to the port driver
540 // to perform the request.
543 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES
,
554 return STATUS_INSUFFICIENT_RESOURCES
;
558 // Pass request to port driver and wait for request to complete.
561 status
= IoCallDriver(PortDeviceObject
, irp
);
563 if (status
== STATUS_PENDING
) {
564 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
565 return(ioStatus
.Status
);
570 } // end ScsiClassGetCapabilities()
575 ScsiClassGetInquiryData(
576 IN PDEVICE_OBJECT PortDeviceObject
,
577 OUT PSCSI_ADAPTER_BUS_INFO
*ConfigInfo
584 This routine sends a request to a port driver to return
585 configuration information. Space for the information is
586 allocated by this routine. The caller is responsible for
587 freeing the configuration information. This routine is
592 PortDeviceObject - Port driver device object representing the HBA.
594 ConfigInfo - Returns a pointer to the configuration information.
598 Nt status indicating the results of the operation.
602 This routine should be called only at initialization time.
608 IO_STATUS_BLOCK ioStatus
;
611 PSCSI_ADAPTER_BUS_INFO buffer
;
615 buffer
= ExAllocatePool(PagedPool
, INQUIRY_DATA_SIZE
);
616 *ConfigInfo
= buffer
;
618 if (buffer
== NULL
) {
619 return(STATUS_INSUFFICIENT_RESOURCES
);
623 // Create notification event object to be used to signal the inquiry
624 // request completion.
627 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
630 // Build the synchronous request to be sent to the port driver
631 // to perform the inquiries.
634 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA
,
645 return(STATUS_INSUFFICIENT_RESOURCES
);
649 // Pass request to port driver and wait for request to complete.
652 status
= IoCallDriver(PortDeviceObject
, irp
);
654 if (status
== STATUS_PENDING
) {
655 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
656 status
= ioStatus
.Status
;
659 if (!NT_SUCCESS(status
)) {
662 // Free the buffer on an error.
672 } // end ScsiClassGetInquiryData()
677 ScsiClassReadDriveCapacity(
678 IN PDEVICE_OBJECT DeviceObject
685 This routine sends a READ CAPACITY to the requested device, updates
686 the geometry information in the device object and returns
687 when it is complete. This routine is synchronous.
691 DeviceObject - Supplies a pointer to the device object that represents
692 the device whose capacity is to be read.
700 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
704 PREAD_CAPACITY_DATA readCapacityBuffer
;
705 SCSI_REQUEST_BLOCK srb
;
709 // Allocate read capacity buffer from nonpaged pool.
712 readCapacityBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
,
713 sizeof(READ_CAPACITY_DATA
));
715 if (!readCapacityBuffer
) {
716 return(STATUS_INSUFFICIENT_RESOURCES
);
719 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
722 // Build the read capacity CDB.
729 // Set timeout value from device extension.
732 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
734 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
738 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
741 sizeof(READ_CAPACITY_DATA
),
744 if (NT_SUCCESS(status
)) {
747 // Copy sector size from read capacity buffer to device extension
748 // in reverse byte order.
751 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte0
=
752 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte3
;
754 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte1
=
755 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte2
;
757 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte2
=
758 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte1
;
760 ((PFOUR_BYTE
)&deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
)->Byte3
=
761 ((PFOUR_BYTE
)&readCapacityBuffer
->BytesPerBlock
)->Byte0
;
764 // Copy last sector in reverse byte order.
767 ((PFOUR_BYTE
)&lastSector
)->Byte0
=
768 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte3
;
770 ((PFOUR_BYTE
)&lastSector
)->Byte1
=
771 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte2
;
773 ((PFOUR_BYTE
)&lastSector
)->Byte2
=
774 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte1
;
776 ((PFOUR_BYTE
)&lastSector
)->Byte3
=
777 ((PFOUR_BYTE
)&readCapacityBuffer
->LogicalBlockAddress
)->Byte0
;
780 // Calculate sector to byte shift.
783 WHICH_BIT(deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
, deviceExtension
->SectorShift
);
785 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
786 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
));
788 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
792 // Calculate media capacity in bytes.
795 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
798 // Calculate number of cylinders.
801 deviceExtension
->DiskGeometry
->Geometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1)/(32 * 64));
803 deviceExtension
->PartitionLength
.QuadPart
=
804 (deviceExtension
->PartitionLength
.QuadPart
<< deviceExtension
->SectorShift
);
806 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
809 // This device supports removable media.
812 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
817 // Assume media type is fixed disk.
820 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
824 // Assume sectors per track are 32;
827 deviceExtension
->DiskGeometry
->Geometry
.SectorsPerTrack
= 32;
830 // Assume tracks per cylinder (number of heads) is 64.
833 deviceExtension
->DiskGeometry
->Geometry
.TracksPerCylinder
= 64;
836 if (status
== STATUS_VERIFY_REQUIRED
) {
839 // Routine ScsiClassSendSrbSynchronous does not retry
840 // requests returned with this status.
841 // Read Capacities should be retried
855 if (!NT_SUCCESS(status
)) {
858 // If the read capacity fails, set the geometry to reasonable parameter
859 // so things don't fail at unexpected places. Zero the geometry
860 // except for the bytes per sector and sector shift.
863 RtlZeroMemory(deviceExtension
->DiskGeometry
, sizeof(DISK_GEOMETRY_EX
));
864 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
= 512;
865 deviceExtension
->SectorShift
= 9;
866 deviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
) 0;
868 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
871 // This device supports removable media.
874 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= RemovableMedia
;
879 // Assume media type is fixed disk.
882 deviceExtension
->DiskGeometry
->Geometry
.MediaType
= FixedMedia
;
887 // Deallocate read capacity buffer.
890 ExFreePool(readCapacityBuffer
);
894 } // end ScsiClassReadDriveCapacity()
899 ScsiClassReleaseQueue(
900 IN PDEVICE_OBJECT DeviceObject
907 This routine issues an internal device control command
908 to the port driver to release a frozen queue. The call
909 is issued asynchronously as ScsiClassReleaseQueue will be invoked
910 from the IO completion DPC (and will have no context to
911 wait for a synchronous call to complete).
915 DeviceObject - The device object for the logical unit with
924 PIO_STACK_LOCATION irpStack
;
926 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
927 PCOMPLETION_CONTEXT context
;
928 PSCSI_REQUEST_BLOCK srb
;
932 // Allocate context from nonpaged pool.
935 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
936 sizeof(COMPLETION_CONTEXT
));
939 // Save the device object in the context for use by the completion
943 context
->DeviceObject
= DeviceObject
;
950 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
953 // Write length to SRB.
956 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
959 // Set up SCSI bus address.
962 srb
->PathId
= deviceExtension
->PathId
;
963 srb
->TargetId
= deviceExtension
->TargetId
;
964 srb
->Lun
= deviceExtension
->Lun
;
967 // If this device is removable then flush the queue. This will also
971 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
973 srb
->Function
= SRB_FUNCTION_FLUSH_QUEUE
;
977 srb
->Function
= SRB_FUNCTION_RELEASE_QUEUE
;
982 // Build the asynchronous request to be sent to the port driver.
985 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
990 // We have no better way of dealing with this at the moment
993 KeBugCheck((ULONG
)0x0000002DL
);
997 IoSetCompletionRoutine(irp
,
998 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1004 irpStack
= IoGetNextIrpStackLocation(irp
);
1006 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1008 srb
->OriginalRequest
= irp
;
1011 // Store the SRB address in next stack for port driver.
1014 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1017 // Since this routine can cause outstanding requests to be completed, and
1018 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1019 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1020 // issuing the request
1023 currentIrql
= KeGetCurrentIrql();
1025 if(currentIrql
< DISPATCH_LEVEL
) {
1026 KeRaiseIrql(DISPATCH_LEVEL
, ¤tIrql
);
1027 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1028 KeLowerIrql(currentIrql
);
1030 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1035 } // end ScsiClassReleaseQueue()
1041 IN PDEVICE_OBJECT DeviceObject
1046 Routine Description:
1048 Send command to SCSI unit to start or power up.
1049 Because this command is issued asynchronounsly, that is, without
1050 waiting on it to complete, the IMMEDIATE flag is not set. This
1051 means that the CDB will not return until the drive has powered up.
1052 This should keep subsequent requests from being submitted to the
1053 device before it has completely spun up.
1054 This routine is called from the InterpretSense routine, when a
1055 request sense returns data indicating that a drive must be
1060 DeviceObject - The device object for the logical unit with
1069 PIO_STACK_LOCATION irpStack
;
1071 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1072 PSCSI_REQUEST_BLOCK srb
;
1073 PCOMPLETION_CONTEXT context
;
1077 // Allocate Srb from nonpaged pool.
1080 context
= ExAllocatePool(NonPagedPoolMustSucceed
,
1081 sizeof(COMPLETION_CONTEXT
));
1084 // Save the device object in the context for use by the completion
1088 context
->DeviceObject
= DeviceObject
;
1089 srb
= &context
->Srb
;
1095 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
1098 // Write length to SRB.
1101 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1104 // Set up SCSI bus address.
1107 srb
->PathId
= deviceExtension
->PathId
;
1108 srb
->TargetId
= deviceExtension
->TargetId
;
1109 srb
->Lun
= deviceExtension
->Lun
;
1111 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1114 // Set timeout value large enough for drive to spin up.
1117 srb
->TimeOutValue
= START_UNIT_TIMEOUT
;
1120 // Set the transfer length.
1123 srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
| SRB_FLAGS_DISABLE_AUTOSENSE
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1126 // Build the start unit CDB.
1130 cdb
= (PCDB
)srb
->Cdb
;
1132 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1133 cdb
->START_STOP
.Start
= 1;
1134 cdb
->START_STOP
.LogicalUnitNumber
= srb
->Lun
;
1137 // Build the asynchronous request to be sent to the port driver.
1138 // Since this routine is called from a DPC the IRP should always be
1142 irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1143 IoSetCompletionRoutine(irp
,
1144 (PIO_COMPLETION_ROUTINE
)ScsiClassAsynchronousCompletion
,
1150 irpStack
= IoGetNextIrpStackLocation(irp
);
1151 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
1152 srb
->OriginalRequest
= irp
;
1155 // Store the SRB address in next stack for port driver.
1158 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1161 // Call the port driver with the IRP.
1164 IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
1168 } // end StartUnit()
1173 ScsiClassAsynchronousCompletion(
1174 PDEVICE_OBJECT DeviceObject
,
1180 Routine Description:
1182 This routine is called when an asynchronous I/O request
1183 which was issused by the class driver completes. Examples of such requests
1184 are release queue or START UNIT. This routine releases the queue if
1185 necessary. It then frees the context and the IRP.
1189 DeviceObject - The device object for the logical unit; however since this
1190 is the top stack location the value is NULL.
1192 Irp - Supplies a pointer to the Irp to be processed.
1194 Context - Supplies the context to be used to process this request.
1203 PCOMPLETION_CONTEXT context
= Context
;
1204 PSCSI_REQUEST_BLOCK srb
;
1206 srb
= &context
->Srb
;
1209 // If this is an execute srb, then check the return status and make sure.
1210 // the queue is not frozen.
1213 if (srb
->Function
== SRB_FUNCTION_EXECUTE_SCSI
) {
1216 // Check for a frozen queue.
1219 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1222 // Unfreeze the queue getting the device object from the context.
1225 ScsiClassReleaseQueue(context
->DeviceObject
);
1230 // Free the context and the Irp.
1233 if (Irp
->MdlAddress
!= NULL
) {
1234 MmUnlockPages(Irp
->MdlAddress
);
1235 IoFreeMdl(Irp
->MdlAddress
);
1237 Irp
->MdlAddress
= NULL
;
1240 ExFreePool(context
);
1244 // Indicate the I/O system should stop processing the Irp completion.
1247 return STATUS_MORE_PROCESSING_REQUIRED
;
1249 } // ScsiClassAsynchronousCompletion()
1254 ScsiClassSplitRequest(
1255 IN PDEVICE_OBJECT DeviceObject
,
1257 IN ULONG MaximumBytes
1262 Routine Description:
1264 Break request into smaller requests. Each new request will be the
1265 maximum transfer size that the port driver can handle or if it
1266 is the final request, it may be the residual size.
1268 The number of IRPs required to process this request is written in the
1269 current stack of the original IRP. Then as each new IRP completes
1270 the count in the original IRP is decremented. When the count goes to
1271 zero, the original IRP is completed.
1275 DeviceObject - Pointer to the class device object to be addressed.
1277 Irp - Pointer to Irp the orginal request.
1286 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1287 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1288 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1289 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1290 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1291 PVOID dataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1292 ULONG dataLength
= MaximumBytes
;
1293 ULONG irpCount
= (transferByteCount
+ MaximumBytes
- 1) / MaximumBytes
;
1295 PSCSI_REQUEST_BLOCK srb
;
1297 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount
));
1298 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp
));
1301 // If all partial transfers complete successfully then the status and
1302 // bytes transferred are already set up. Failing a partial-transfer IRP
1303 // will set status to error and bytes transferred to 0 during
1304 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1305 // asynchronous partial transfers. This is an optimization for the
1309 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1310 Irp
->IoStatus
.Information
= transferByteCount
;
1313 // Save number of IRPs to complete count on current stack
1317 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)(ULONG_PTR
) irpCount
;
1319 for (i
= 0; i
< irpCount
; i
++) {
1322 PIO_STACK_LOCATION newIrpStack
;
1325 // Allocate new IRP.
1328 newIrp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1330 if (newIrp
== NULL
) {
1332 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1335 // If an Irp can't be allocated then the orginal request cannot
1336 // be executed. If this is the first request then just fail the
1337 // orginal request; otherwise just return. When the pending
1338 // requests complete, they will complete the original request.
1339 // In either case set the IRP status to failure.
1342 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1343 Irp
->IoStatus
.Information
= 0;
1346 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1352 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp
));
1355 // Write MDL address to new IRP. In the port driver the SRB data
1356 // buffer field is used as an offset into the MDL, so the same MDL
1357 // can be used for each partial transfer. This saves having to build
1358 // a new MDL for each partial transfer.
1361 newIrp
->MdlAddress
= Irp
->MdlAddress
;
1364 // At this point there is no current stack. IoSetNextIrpStackLocation
1365 // will make the first stack location the current stack so that the
1366 // SRB address can be written there.
1369 IoSetNextIrpStackLocation(newIrp
);
1370 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
1372 newIrpStack
->MajorFunction
= currentIrpStack
->MajorFunction
;
1373 newIrpStack
->Parameters
.Read
.Length
= dataLength
;
1374 newIrpStack
->Parameters
.Read
.ByteOffset
= startingOffset
;
1375 newIrpStack
->DeviceObject
= DeviceObject
;
1378 // Build SRB and CDB.
1381 ScsiClassBuildRequest(DeviceObject
, newIrp
);
1384 // Adjust SRB for this partial transfer.
1387 newIrpStack
= IoGetNextIrpStackLocation(newIrp
);
1389 srb
= newIrpStack
->Parameters
.Others
.Argument1
;
1390 srb
->DataBuffer
= dataBuffer
;
1393 // Write original IRP address to new IRP.
1396 newIrp
->AssociatedIrp
.MasterIrp
= Irp
;
1399 // Set the completion routine to ScsiClassIoCompleteAssociated.
1402 IoSetCompletionRoutine(newIrp
,
1403 ScsiClassIoCompleteAssociated
,
1410 // Call port driver with new request.
1413 IoCallDriver(deviceExtension
->PortDeviceObject
, newIrp
);
1416 // Set up for next request.
1419 dataBuffer
= (PCHAR
)dataBuffer
+ MaximumBytes
;
1421 transferByteCount
-= MaximumBytes
;
1423 if (transferByteCount
> MaximumBytes
) {
1425 dataLength
= MaximumBytes
;
1429 dataLength
= transferByteCount
;
1433 // Adjust disk byte offset.
1436 startingOffset
.QuadPart
= startingOffset
.QuadPart
+ MaximumBytes
;
1441 } // end ScsiClassSplitRequest()
1446 ScsiClassIoComplete(
1447 IN PDEVICE_OBJECT DeviceObject
,
1454 Routine Description:
1456 This routine executes when the port driver has completed a request.
1457 It looks at the SRB status in the completing SRB and if not success
1458 it checks for valid request sense buffer information. If valid, the
1459 info is used to update status with more precise message of type of
1460 error. This routine deallocates the SRB.
1464 DeviceObject - Supplies the device object which represents the logical
1467 Irp - Supplies the Irp which has completed.
1469 Context - Supplies a pointer to the SRB.
1478 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1479 PSCSI_REQUEST_BLOCK srb
= Context
;
1480 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1485 // Check SRB status for success of completing request.
1488 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1490 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp
, srb
));
1493 // Release the queue if it is frozen.
1496 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1497 ScsiClassReleaseQueue(DeviceObject
);
1500 retry
= ScsiClassInterpretSenseInfo(
1503 irpStack
->MajorFunction
,
1504 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1505 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1509 // If the status is verified required and the this request
1510 // should bypass verify required then retry the request.
1513 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1514 status
== STATUS_VERIFY_REQUIRED
) {
1516 status
= STATUS_IO_DEVICE_ERROR
;
1520 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1526 DebugPrint((1, "Retry request %lx\n", Irp
));
1527 RetryRequest(DeviceObject
, Irp
, srb
, FALSE
);
1528 return STATUS_MORE_PROCESSING_REQUIRED
;
1533 // Set status for successful request.
1536 status
= STATUS_SUCCESS
;
1538 } // end if (SRB_STATUS(srb->SrbStatus) ...
1541 // Return SRB to list.
1544 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1548 // Set status in completing IRP.
1551 Irp
->IoStatus
.Status
= status
;
1552 if ((NT_SUCCESS(status
)) && (Irp
->Flags
& IRP_PAGING_IO
)) {
1553 ASSERT(Irp
->IoStatus
.Information
);
1557 // Set the hard error if necessary.
1560 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
1563 // Store DeviceObject for filesystem, and clear
1564 // in IoStatus.Information field.
1567 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1568 Irp
->IoStatus
.Information
= 0;
1572 // If pending has be returned for this irp then mark the current stack as
1576 if (Irp
->PendingReturned
) {
1577 IoMarkIrpPending(Irp
);
1580 if (deviceExtension
->ClassStartIo
) {
1581 if (irpStack
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
) {
1582 IoStartNextPacket(DeviceObject
, FALSE
);
1588 } // end ScsiClassIoComplete()
1593 ScsiClassIoCompleteAssociated(
1594 IN PDEVICE_OBJECT DeviceObject
,
1601 Routine Description:
1603 This routine executes when the port driver has completed a request.
1604 It looks at the SRB status in the completing SRB and if not success
1605 it checks for valid request sense buffer information. If valid, the
1606 info is used to update status with more precise message of type of
1607 error. This routine deallocates the SRB. This routine is used for
1608 requests which were build by split request. After it has processed
1609 the request it decrements the Irp count in the master Irp. If the
1610 count goes to zero then the master Irp is completed.
1614 DeviceObject - Supplies the device object which represents the logical
1617 Irp - Supplies the Irp which has completed.
1619 Context - Supplies a pointer to the SRB.
1628 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
1629 PSCSI_REQUEST_BLOCK srb
= Context
;
1630 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1631 PIRP originalIrp
= Irp
->AssociatedIrp
.MasterIrp
;
1637 // Check SRB status for success of completing request.
1640 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
1642 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp
, srb
));
1645 // Release the queue if it is frozen.
1648 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
1649 ScsiClassReleaseQueue(DeviceObject
);
1652 retry
= ScsiClassInterpretSenseInfo(
1655 irpStack
->MajorFunction
,
1656 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
1657 MAXIMUM_RETRIES
- ((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
1661 // If the status is verified required and the this request
1662 // should bypass verify required then retry the request.
1665 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
1666 status
== STATUS_VERIFY_REQUIRED
) {
1668 status
= STATUS_IO_DEVICE_ERROR
;
1672 if (retry
&& (irpStack
->Parameters
.Others
.Argument4
= (PVOID
)((ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
-1))) {
1675 // Retry request. If the class driver has supplied a StartIo,
1676 // call it directly for retries.
1679 DebugPrint((1, "Retry request %lx\n", Irp
));
1682 if (!deviceExtension->ClassStartIo) {
1683 RetryRequest(DeviceObject, Irp, srb, TRUE);
1685 deviceExtension->ClassStartIo(DeviceObject, Irp);
1689 RetryRequest(DeviceObject
, Irp
, srb
, TRUE
);
1691 return STATUS_MORE_PROCESSING_REQUIRED
;
1699 // Set status for successful request.
1702 status
= STATUS_SUCCESS
;
1704 } // end if (SRB_STATUS(srb->SrbStatus) ...
1707 // Return SRB to list.
1710 ExFreeToNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
,
1714 // Set status in completing IRP.
1717 Irp
->IoStatus
.Status
= status
;
1719 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp
));
1722 // Get next stack location. This original request is unused
1723 // except to keep track of the completing partial IRPs so the
1724 // stack location is valid.
1727 irpStack
= IoGetNextIrpStackLocation(originalIrp
);
1730 // Update status only if error so that if any partial transfer
1731 // completes with error, then the original IRP will return with
1732 // error. If any of the asynchronous partial transfer IRPs fail,
1733 // with an error then the original IRP will return 0 bytes transfered.
1734 // This is an optimization for successful transfers.
1737 if (!NT_SUCCESS(status
)) {
1739 originalIrp
->IoStatus
.Status
= status
;
1740 originalIrp
->IoStatus
.Information
= 0;
1743 // Set the hard error if necessary.
1746 if (IoIsErrorUserInduced(status
)) {
1749 // Store DeviceObject for filesystem.
1752 IoSetHardErrorOrVerifyDevice(originalIrp
, DeviceObject
);
1757 // Decrement and get the count of remaining IRPs.
1760 irpCount
= InterlockedDecrement((PLONG
)&irpStack
->Parameters
.Others
.Argument1
);
1762 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
1766 // Old bug could cause irp count to negative
1769 ASSERT(irpCount
>= 0);
1771 if (irpCount
== 0) {
1774 // All partial IRPs have completed.
1778 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
1781 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
1784 // If the class driver has supplied a startio, start the
1788 if (deviceExtension
->ClassStartIo
) {
1789 IoStartNextPacket(DeviceObject
, FALSE
);
1794 // Deallocate IRP and indicate the I/O system should not attempt any more
1799 return STATUS_MORE_PROCESSING_REQUIRED
;
1801 } // end ScsiClassIoCompleteAssociated()
1806 ScsiClassSendSrbSynchronous(
1807 PDEVICE_OBJECT DeviceObject
,
1808 PSCSI_REQUEST_BLOCK Srb
,
1809 PVOID BufferAddress
,
1811 BOOLEAN WriteToDevice
1816 Routine Description:
1818 This routine is called by SCSI device controls to complete an
1819 SRB and send it to the port driver synchronously (ie wait for
1820 completion). The CDB is already completed along with the SRB CDB
1821 size and request timeout value.
1825 DeviceObject - Supplies the device object which represents the logical
1828 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
1830 BufferAddress - Supplies the address of the buffer.
1832 BufferLength - Supplies the length in bytes of the buffer.
1834 WriteToDevice - Indicates the data should be transfer to the device.
1838 Nt status indicating the final results of the operation.
1843 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
1844 IO_STATUS_BLOCK ioStatus
;
1845 ULONG controlType
, mjFunction
;
1847 PIO_STACK_LOCATION irpStack
;
1849 PUCHAR senseInfoBuffer
;
1850 ULONG retryCount
= MAXIMUM_RETRIES
;
1853 LARGE_INTEGER dummy
;
1860 // Write length to SRB.
1863 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1866 // Set SCSI bus address.
1869 Srb
->PathId
= deviceExtension
->PathId
;
1870 Srb
->TargetId
= deviceExtension
->TargetId
;
1871 Srb
->Lun
= deviceExtension
->Lun
;
1872 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1875 // NOTICE: The SCSI-II specification indicates that this field should be
1876 // zero; however, some target controllers ignore the logical unit number
1877 // in the INDENTIFY message and only look at the logical unit number field
1881 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
1884 // Enable auto request sense.
1887 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1890 // Sense buffer is in aligned nonpaged pool.
1893 senseInfoBuffer
= ExAllocatePool(NonPagedPoolCacheAligned
, SENSE_BUFFER_SIZE
);
1895 if (senseInfoBuffer
== NULL
) {
1898 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
1899 return(STATUS_INSUFFICIENT_RESOURCES
);
1902 Srb
->SenseInfoBuffer
= senseInfoBuffer
;
1903 Srb
->DataBuffer
= BufferAddress
;
1906 // Start retries here.
1912 // Set the event object to the unsignaled state.
1913 // It will be used to signal request completion.
1916 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
1919 // Set controlType and Srb direction flags.
1922 if (BufferAddress
!= NULL
) {
1924 if (WriteToDevice
) {
1926 controlType
= IOCTL_SCSI_EXECUTE_OUT
;
1927 Srb
->SrbFlags
= SRB_FLAGS_DATA_OUT
;
1928 mjFunction
= IRP_MJ_WRITE
;
1932 controlType
= IOCTL_SCSI_EXECUTE_IN
;
1933 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
;
1934 mjFunction
= IRP_MJ_READ
;
1940 controlType
= IOCTL_SCSI_EXECUTE_NONE
;
1941 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1942 mjFunction
= IRP_MJ_FLUSH_BUFFERS
;
1946 // Build device I/O control request with data transfer.
1948 irp
= IoBuildAsynchronousFsdRequest(
1950 deviceExtension
->DeviceObject
,
1952 (BufferAddress
) ? BufferLength
: 0,
1957 ExFreePool(senseInfoBuffer
);
1958 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
1959 return(STATUS_INSUFFICIENT_RESOURCES
);
1963 irp
->UserEvent
= &event
;
1966 // Disable synchronous transfer for these requests.
1969 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1972 // Set the transfer length.
1975 Srb
->DataTransferLength
= BufferLength
;
1981 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
1984 // Set completion routine
1985 IoSetCompletionRoutine(
1987 ClassCompletionRoutine
,
1994 // Get next stack location.
1997 irpStack
= IoGetNextIrpStackLocation(irp
);
1999 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
2000 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= controlType
;
2003 // Set up SRB for execute scsi request. Save SRB address in next stack
2004 // for the port driver.
2007 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
2010 // Set up IRP Address.
2013 Srb
->OriginalRequest
= irp
;
2016 // Call the port driver with the request and wait for it to complete.
2019 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, irp
);
2021 if (status
== STATUS_PENDING
) {
2022 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
2026 // Check that request completed without error.
2029 if (SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2032 // Release the queue if it is frozen.
2035 if (Srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2036 ScsiClassReleaseQueue(DeviceObject
);
2040 // Update status and determine if request should be retried.
2043 retry
= ScsiClassInterpretSenseInfo(DeviceObject
,
2047 MAXIMUM_RETRIES
- retryCount
,
2052 if ((status
== STATUS_DEVICE_NOT_READY
&& ((PSENSE_DATA
) senseInfoBuffer
)
2053 ->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) ||
2054 SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SELECTION_TIMEOUT
) {
2056 LARGE_INTEGER delay
;
2059 // Delay for 2 seconds.
2062 delay
.QuadPart
= (LONGLONG
)( - 10 * 1000 * 1000 * 2 );
2065 // Stall for a while to let the controller spinup.
2068 KeDelayExecutionThread(KernelMode
,
2075 // If retries are not exhausted then retry this operation.
2085 status
= STATUS_SUCCESS
;
2088 ExFreePool(senseInfoBuffer
);
2091 } // end ScsiClassSendSrbSynchronous()
2096 ScsiClassInterpretSenseInfo(
2097 IN PDEVICE_OBJECT DeviceObject
,
2098 IN PSCSI_REQUEST_BLOCK Srb
,
2099 IN UCHAR MajorFunctionCode
,
2100 IN ULONG IoDeviceCode
,
2101 IN ULONG RetryCount
,
2102 OUT NTSTATUS
*Status
2107 Routine Description:
2109 This routine interprets the data returned from the SCSI
2110 request sense. It determines the status to return in the
2111 IRP and whether this request can be retried.
2115 DeviceObject - Supplies the device object associated with this request.
2117 Srb - Supplies the scsi request block which failed.
2119 MajorFunctionCode - Supplies the function code to be used for logging.
2121 IoDeviceCode - Supplies the device code to be used for logging.
2123 Status - Returns the status for the request.
2127 BOOLEAN TRUE: Drivers should retry this request.
2128 FALSE: Drivers should not retry this request.
2133 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2134 PDEVICE_EXTENSION physicalExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
2135 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
2136 BOOLEAN retry
= TRUE
;
2137 BOOLEAN logError
= FALSE
;
2138 ULONG badSector
= 0;
2143 PIO_ERROR_LOG_PACKET errorLogEntry
;
2150 // Check that request sense buffer is valid.
2154 DebugPrint((3, "Opcode %x\nParameters: ",Srb
->Cdb
[0]));
2155 for (i
= 1; i
< 12; i
++) {
2156 DebugPrint((3,"%x ",Srb
->Cdb
[i
]));
2158 DebugPrint((3,"\n"));
2161 if (Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
&&
2162 Srb
->SenseInfoBufferLength
>= FIELD_OFFSET(SENSE_DATA
, CommandSpecificInformation
)) {
2164 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2165 senseBuffer
->ErrorCode
));
2166 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2167 senseBuffer
->SenseKey
));
2168 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2169 senseBuffer
->AdditionalSenseCode
));
2170 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2171 senseBuffer
->AdditionalSenseCodeQualifier
));
2174 // Zero the additional sense code and additional sense code qualifier
2175 // if they were not returned by the device.
2178 readSector
= senseBuffer
->AdditionalSenseLength
+
2179 FIELD_OFFSET(SENSE_DATA
, AdditionalSenseLength
);
2181 if (readSector
> Srb
->SenseInfoBufferLength
) {
2182 readSector
= Srb
->SenseInfoBufferLength
;
2185 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCode
)) {
2186 senseBuffer
->AdditionalSenseCode
= 0;
2189 if (readSector
<= FIELD_OFFSET(SENSE_DATA
, AdditionalSenseCodeQualifier
)) {
2190 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
2193 switch (senseBuffer
->SenseKey
& 0xf) {
2195 case SCSI_SENSE_NOT_READY
:
2197 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2198 *Status
= STATUS_DEVICE_NOT_READY
;
2200 switch (senseBuffer
->AdditionalSenseCode
) {
2202 case SCSI_ADSENSE_LUN_NOT_READY
:
2204 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2206 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
2208 case SCSI_SENSEQ_BECOMING_READY
:
2210 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2211 " In process of becoming ready\n"));
2214 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED
:
2216 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2217 " Manual intervention required\n"));
2218 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2222 case SCSI_SENSEQ_FORMAT_IN_PROGRESS
:
2224 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2228 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED
:
2232 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2233 " Initializing command required\n"));
2236 // This sense code/additional sense code
2237 // combination may indicate that the device
2238 // needs to be started. Send an start unit if this
2239 // is a disk device.
2242 if (deviceExtension
->DeviceFlags
& DEV_SAFE_START_UNIT
) {
2243 StartUnit(DeviceObject
);
2248 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2252 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
:
2255 "ScsiClassInterpretSenseInfo:"
2256 " No Media in device.\n"));
2257 *Status
= STATUS_NO_MEDIA_IN_DEVICE
;
2261 // signal autorun that there isn't any media in the device
2264 if((deviceExtension
->MediaChangeEvent
!= NULL
)&&
2265 (!deviceExtension
->MediaChangeNoMedia
)) {
2266 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2269 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2270 "Detected No Media In Device "
2271 "[irp = 0x%lx]\n", Srb
->OriginalRequest
));
2272 deviceExtension
->MediaChangeNoMedia
= TRUE
;
2276 } // end switch (senseBuffer->AdditionalSenseCode)
2280 case SCSI_SENSE_DATA_PROTECT
:
2282 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2283 *Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2287 case SCSI_SENSE_MEDIUM_ERROR
:
2289 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2290 *Status
= STATUS_DEVICE_DATA_ERROR
;
2295 logStatus
= 0;//IO_ERR_BAD_BLOCK;
2298 case SCSI_SENSE_HARDWARE_ERROR
:
2300 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2301 *Status
= STATUS_IO_DEVICE_ERROR
;
2305 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2309 case SCSI_SENSE_ILLEGAL_REQUEST
:
2311 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2312 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2314 switch (senseBuffer
->AdditionalSenseCode
) {
2316 case SCSI_ADSENSE_ILLEGAL_COMMAND
:
2317 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2321 case SCSI_ADSENSE_ILLEGAL_BLOCK
:
2322 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2323 *Status
= STATUS_NONEXISTENT_SECTOR
;
2327 case SCSI_ADSENSE_INVALID_LUN
:
2328 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2329 *Status
= STATUS_NO_SUCH_DEVICE
;
2333 case SCSI_ADSENSE_MUSIC_AREA
:
2334 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2338 case SCSI_ADSENSE_DATA_AREA
:
2339 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2343 case SCSI_ADSENSE_VOLUME_OVERFLOW
:
2344 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2348 case SCSI_ADSENSE_INVALID_CDB
:
2349 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2352 // Check if write cache enabled.
2355 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
2358 // Assume FUA is not supported.
2361 deviceExtension
->DeviceFlags
&= ~DEV_WRITE_CACHE
;
2370 } // end switch (senseBuffer->AdditionalSenseCode)
2374 case SCSI_SENSE_UNIT_ATTENTION
:
2376 switch (senseBuffer
->AdditionalSenseCode
) {
2377 case SCSI_ADSENSE_MEDIUM_CHANGED
:
2378 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2380 if(deviceExtension
->MediaChangeEvent
!= NULL
) {
2382 KeSetEvent(deviceExtension
->MediaChangeEvent
,
2385 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2386 "New Media Found - Setting MediaChanged event"
2387 " [irp = 0x%lx]\n", Srb
->OriginalRequest
));
2388 deviceExtension
->MediaChangeNoMedia
= FALSE
;
2393 case SCSI_ADSENSE_BUS_RESET
:
2394 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2398 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2401 } // end switch (senseBuffer->AdditionalSenseCode)
2403 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
&&
2404 DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
) {
2407 // Set bit to indicate that media may have changed
2408 // and volume needs verification.
2411 DeviceObject
->Flags
|= DO_VERIFY_VOLUME
;
2413 *Status
= STATUS_VERIFY_REQUIRED
;
2418 *Status
= STATUS_IO_DEVICE_ERROR
;
2423 // A media change may have occured so increment the change
2424 // count for the physical device
2427 physicalExtension
->MediaChangeCount
++;
2429 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2430 "count for device %d is %d\n",
2431 physicalExtension
->DeviceNumber
,
2432 physicalExtension
->MediaChangeCount
));
2436 case SCSI_SENSE_ABORTED_COMMAND
:
2438 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2439 *Status
= STATUS_IO_DEVICE_ERROR
;
2442 case SCSI_SENSE_RECOVERED_ERROR
:
2444 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2445 *Status
= STATUS_SUCCESS
;
2450 switch(senseBuffer
->AdditionalSenseCode
) {
2451 case SCSI_ADSENSE_SEEK_ERROR
:
2452 case SCSI_ADSENSE_TRACK_ERROR
:
2453 logStatus
= 0;//IO_ERR_SEEK_ERROR;
2456 case SCSI_ADSENSE_REC_DATA_NOECC
:
2457 case SCSI_ADSENSE_REC_DATA_ECC
:
2458 logStatus
= 0;//IO_RECOVERED_VIA_ECC;
2462 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2465 } // end switch(senseBuffer->AdditionalSenseCode)
2467 if (senseBuffer
->IncorrectLength
) {
2469 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2470 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2475 case SCSI_SENSE_NO_SENSE
:
2478 // Check other indicators.
2481 if (senseBuffer
->IncorrectLength
) {
2483 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2484 *Status
= STATUS_INVALID_BLOCK_LENGTH
;
2489 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2490 *Status
= STATUS_IO_DEVICE_ERROR
;
2498 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2499 *Status
= STATUS_IO_DEVICE_ERROR
;
2502 } // end switch (senseBuffer->SenseKey & 0xf)
2505 // Try to determine the bad sector from the inquiry data.
2508 if ((((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_READ
||
2509 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_VERIFY
||
2510 ((PCDB
)Srb
->Cdb
)->CDB10
.OperationCode
== SCSIOP_WRITE
)) {
2512 for (index
= 0; index
< 4; index
++) {
2513 badSector
= (badSector
<< 8) | senseBuffer
->Information
[index
];
2517 for (index
= 0; index
< 4; index
++) {
2518 readSector
= (readSector
<< 8) | Srb
->Cdb
[index
+2];
2521 index
= (((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8) |
2522 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
;
2525 // Make sure the bad sector is within the read sectors.
2528 if (!(badSector
>= readSector
&& badSector
< readSector
+ index
)) {
2529 badSector
= readSector
;
2536 // Request sense buffer not valid. No sense information
2537 // to pinpoint the error. Return general request fail.
2540 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2541 SRB_STATUS(Srb
->SrbStatus
)));
2544 switch (SRB_STATUS(Srb
->SrbStatus
)) {
2545 case SRB_STATUS_INVALID_LUN
:
2546 case SRB_STATUS_INVALID_TARGET_ID
:
2547 case SRB_STATUS_NO_DEVICE
:
2548 case SRB_STATUS_NO_HBA
:
2549 case SRB_STATUS_INVALID_PATH_ID
:
2550 *Status
= STATUS_NO_SUCH_DEVICE
;
2554 case SRB_STATUS_COMMAND_TIMEOUT
:
2555 case SRB_STATUS_ABORTED
:
2556 case SRB_STATUS_TIMEOUT
:
2559 // Update the error count for the device.
2562 deviceExtension
->ErrorCount
++;
2563 *Status
= STATUS_IO_TIMEOUT
;
2566 case SRB_STATUS_SELECTION_TIMEOUT
:
2568 logStatus
= 0;//IO_ERR_NOT_READY;
2570 *Status
= STATUS_DEVICE_NOT_CONNECTED
;
2574 case SRB_STATUS_DATA_OVERRUN
:
2575 *Status
= STATUS_DATA_OVERRUN
;
2579 case SRB_STATUS_PHASE_SEQUENCE_FAILURE
:
2582 // Update the error count for the device.
2585 deviceExtension
->ErrorCount
++;
2586 *Status
= STATUS_IO_DEVICE_ERROR
;
2589 // If there was phase sequence error then limit the number of
2593 if (RetryCount
> 1 ) {
2599 case SRB_STATUS_REQUEST_FLUSHED
:
2602 // If the status needs verification bit is set. Then set
2603 // the status to need verification and no retry; otherwise,
2604 // just retry the request.
2607 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
) {
2609 *Status
= STATUS_VERIFY_REQUIRED
;
2612 *Status
= STATUS_IO_DEVICE_ERROR
;
2617 case SRB_STATUS_INVALID_REQUEST
:
2620 // An invalid request was attempted.
2623 *Status
= STATUS_INVALID_DEVICE_REQUEST
;
2627 case SRB_STATUS_UNEXPECTED_BUS_FREE
:
2628 case SRB_STATUS_PARITY_ERROR
:
2631 // Update the error count for the device.
2634 deviceExtension
->ErrorCount
++;
2637 // Fall through to below.
2640 case SRB_STATUS_BUS_RESET
:
2641 *Status
= STATUS_IO_DEVICE_ERROR
;
2644 case SRB_STATUS_ERROR
:
2646 *Status
= STATUS_IO_DEVICE_ERROR
;
2647 if (Srb
->ScsiStatus
== 0) {
2650 // This is some strange return code. Update the error
2651 // count for the device.
2654 deviceExtension
->ErrorCount
++;
2656 } if (Srb
->ScsiStatus
== SCSISTAT_BUSY
) {
2658 *Status
= STATUS_DEVICE_NOT_READY
;
2660 } if (Srb
->ScsiStatus
== SCSISTAT_RESERVATION_CONFLICT
) {
2662 *Status
= STATUS_DEVICE_BUSY
;
2671 logStatus
= 0;//IO_ERR_CONTROLLER_ERROR;
2673 *Status
= STATUS_IO_DEVICE_ERROR
;
2679 // If the error count has exceeded the error limit, then disable
2680 // any tagged queuing, multiple requests per lu queueing
2681 // and sychronous data transfers.
2684 if (deviceExtension
->ErrorCount
== 4) {
2687 // Clearing the no queue freeze flag prevents the port driver
2688 // from sending multiple requests per logical unit.
2691 deviceExtension
->SrbFlags
&= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE
|
2692 SRB_FLAGS_NO_QUEUE_FREEZE
);
2694 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2695 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2697 } else if (deviceExtension
->ErrorCount
== 8) {
2700 // If a second threshold is reached, disable disconnects.
2703 deviceExtension
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
;
2704 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2709 // If there is a class specific error handler call it.
2712 if (deviceExtension
->ClassError
!= NULL
) {
2714 deviceExtension
->ClassError(DeviceObject
,
2721 // Log an error if necessary.
2726 errorLogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
2728 sizeof(IO_ERROR_LOG_PACKET
) + 5 * sizeof(ULONG
));
2730 if (errorLogEntry
== NULL
) {
2733 // Return if no packet could be allocated.
2740 if (retry
&& RetryCount
< MAXIMUM_RETRIES
) {
2741 errorLogEntry
->FinalStatus
= STATUS_SUCCESS
;
2743 errorLogEntry
->FinalStatus
= *Status
;
2747 // Calculate the device offset if there is a geometry.
2750 if (deviceExtension
->DiskGeometry
!= NULL
) {
2752 errorLogEntry
->DeviceOffset
.QuadPart
= (LONGLONG
) badSector
;
2753 errorLogEntry
->DeviceOffset
= RtlExtendedIntegerMultiply(
2754 errorLogEntry
->DeviceOffset
,
2755 deviceExtension
->DiskGeometry
->Geometry
.BytesPerSector
);
2758 errorLogEntry
->ErrorCode
= logStatus
;
2759 errorLogEntry
->SequenceNumber
= 0;
2760 errorLogEntry
->MajorFunctionCode
= MajorFunctionCode
;
2761 errorLogEntry
->IoControlCode
= IoDeviceCode
;
2762 errorLogEntry
->RetryCount
= (UCHAR
) RetryCount
;
2763 errorLogEntry
->UniqueErrorValue
= uniqueId
;
2764 errorLogEntry
->DumpDataSize
= 6 * sizeof(ULONG
);
2765 errorLogEntry
->DumpData
[0] = Srb
->PathId
;
2766 errorLogEntry
->DumpData
[1] = Srb
->TargetId
;
2767 errorLogEntry
->DumpData
[2] = Srb
->Lun
;
2768 errorLogEntry
->DumpData
[3] = 0;
2769 errorLogEntry
->DumpData
[4] = Srb
->SrbStatus
<< 8 | Srb
->ScsiStatus
;
2771 if (senseBuffer
!= NULL
) {
2772 errorLogEntry
->DumpData
[5] = senseBuffer
->SenseKey
<< 16 |
2773 senseBuffer
->AdditionalSenseCode
<< 8 |
2774 senseBuffer
->AdditionalSenseCodeQualifier
;
2779 // Write the error log packet.
2782 IoWriteErrorLogEntry(errorLogEntry
);
2787 } // end ScsiClassInterpretSenseInfo()
2793 PDEVICE_OBJECT DeviceObject
,
2795 PSCSI_REQUEST_BLOCK Srb
,
2801 Routine Description:
2803 This routine reinitalizes the necessary fields, and sends the request
2808 DeviceObject - Supplies the device object associated with this request.
2810 Irp - Supplies the request to be retried.
2812 Srb - Supplies a Pointer to the SCSI request block to be retied.
2814 Assocaiated - Indicates this is an assocatied Irp created by split request.
2823 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2824 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2825 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2826 ULONG transferByteCount
;
2829 // Determine the transfer count of the request. If this is a read or a
2830 // write then the transfer count is in the Irp stack. Otherwise assume
2831 // the MDL contains the correct length. If there is no MDL then the
2832 // transfer length must be zero.
2835 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
2836 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
2838 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2840 } else if (Irp
->MdlAddress
!= NULL
) {
2843 // Note this assumes that only read and write requests are spilt and
2844 // other request do not need to be. If the data buffer address in
2845 // the MDL and the SRB don't match then transfer length is most
2846 // likely incorrect.
2849 ASSERT(Srb
->DataBuffer
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
2850 transferByteCount
= Irp
->MdlAddress
->ByteCount
;
2854 transferByteCount
= 0;
2858 // Reset byte count of transfer in SRB Extension.
2861 Srb
->DataTransferLength
= transferByteCount
;
2864 // Zero SRB statuses.
2867 Srb
->SrbStatus
= Srb
->ScsiStatus
= 0;
2870 // Set the no disconnect flag, disable synchronous data transfers and
2871 // disable tagged queuing. This fixes some errors.
2874 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_DISCONNECT
|
2875 SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
2877 Srb
->SrbFlags
&= ~SRB_FLAGS_QUEUE_ACTION_ENABLE
;
2878 Srb
->QueueTag
= SP_UNTAGGED
;
2881 // Set up major SCSI function.
2884 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2887 // Save SRB address in next stack for port driver.
2890 nextIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
2893 // Set up IoCompletion routine address.
2898 IoSetCompletionRoutine(Irp
, ScsiClassIoCompleteAssociated
, Srb
, TRUE
, TRUE
, TRUE
);
2902 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
2906 // Pass the request to the port driver.
2909 (VOID
)IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
2911 } // end RetryRequest()
2915 ScsiClassBuildRequest(
2916 PDEVICE_OBJECT DeviceObject
,
2922 Routine Description:
2924 This routine allocates and builds an Srb for a read or write request.
2925 The block address and length are supplied by the Irp. The retry count
2926 is stored in the current stack for use by ScsiClassIoComplete which
2927 processes these requests when they complete. The Irp is ready to be
2928 passed to the port driver when this routine returns.
2932 DeviceObject - Supplies the device object associated with this request.
2934 Irp - Supplies the request to be retried.
2938 If the IRP is for a disk transfer, the byteoffset field
2939 will already have been adjusted to make it relative to
2940 the beginning of the disk.
2950 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2951 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
2952 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
2953 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
2954 PSCSI_REQUEST_BLOCK srb
;
2956 ULONG logicalBlockAddress
;
2957 USHORT transferBlocks
;
2960 // Calculate relative sector address.
2963 logicalBlockAddress
= (ULONG
)(Int64ShrlMod32(startingOffset
.QuadPart
, deviceExtension
->SectorShift
));
2969 srb
= ExAllocateFromNPagedLookasideList(&deviceExtension
->SrbLookasideListHead
);
2974 // Write length to SRB.
2977 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
2980 // Set up IRP Address.
2983 srb
->OriginalRequest
= Irp
;
2986 // Set up target ID and logical unit number.
2989 srb
->PathId
= deviceExtension
->PathId
;
2990 srb
->TargetId
= deviceExtension
->TargetId
;
2991 srb
->Lun
= deviceExtension
->Lun
;
2992 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
2993 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2996 // Save byte count of transfer in SRB Extension.
2999 srb
->DataTransferLength
= currentIrpStack
->Parameters
.Read
.Length
;
3002 // Initialize the queue actions field.
3005 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
3008 // Queue sort key is Relative Block Address.
3011 srb
->QueueSortKey
= logicalBlockAddress
;
3014 // Indicate auto request sense by specifying buffer and size.
3017 srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3018 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3021 // Set timeout value of one unit per 64k bytes of data.
3024 srb
->TimeOutValue
= ((srb
->DataTransferLength
+ 0xFFFF) >> 16) *
3025 deviceExtension
->TimeOutValue
;
3031 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3035 // Indicate that 10-byte CDB's will be used.
3038 srb
->CdbLength
= 10;
3041 // Fill in CDB fields.
3044 cdb
= (PCDB
)srb
->Cdb
;
3047 // Zero 12 bytes for Atapi Packets
3050 RtlZeroMemory(cdb
, MAXIMUM_CDB_SIZE
);
3052 cdb
->CDB10
.LogicalUnitNumber
= deviceExtension
->Lun
;
3053 transferBlocks
= (USHORT
)(currentIrpStack
->Parameters
.Read
.Length
>> deviceExtension
->SectorShift
);
3056 // Move little endian values into CDB in big endian format.
3059 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
3060 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
3061 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
3062 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
3064 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte1
;
3065 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&transferBlocks
)->Byte0
;
3068 // Set transfer direction flag and Cdb command.
3071 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
) {
3073 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3075 srb
->SrbFlags
|= SRB_FLAGS_DATA_IN
;
3076 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3080 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3082 srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
3083 cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
3087 // If this is not a write-through request, then allow caching.
3090 if (!(currentIrpStack
->Flags
& SL_WRITE_THROUGH
)) {
3092 srb
->SrbFlags
|= SRB_FLAGS_ADAPTER_CACHE_ENABLE
;
3097 // If write caching is enable then force media access in the
3101 if (deviceExtension
->DeviceFlags
& DEV_WRITE_CACHE
) {
3102 cdb
->CDB10
.ForceUnitAccess
= TRUE
;
3107 // Or in the default flags from the device object.
3110 srb
->SrbFlags
|= deviceExtension
->SrbFlags
;
3113 // Set up major SCSI function.
3116 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
3119 // Save SRB address in next stack for port driver.
3122 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
3125 // Save retry count in current IRP stack.
3128 currentIrpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3131 // Set up IoCompletion routine address.
3134 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, srb
, TRUE
, TRUE
, TRUE
);
3138 } // end ScsiClassBuildRequest()
3143 IN PDEVICE_OBJECT DeviceObject
,
3144 IN PCHAR ModeSenseBuffer
,
3151 Routine Description:
3153 This routine sends a mode sense command to a target ID and returns
3154 when it is complete.
3158 DeviceObject - Supplies the device object associated with this request.
3160 ModeSenseBuffer - Supplies a buffer to store the sense data.
3162 Length - Supplies the length in bytes of the mode sense buffer.
3164 PageMode - Supplies the page or pages of mode sense data to be retrived.
3168 Length of the transferred data is returned.
3172 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3174 SCSI_REQUEST_BLOCK srb
;
3178 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
3181 // Build the MODE SENSE CDB.
3185 cdb
= (PCDB
)srb
.Cdb
;
3188 // Set timeout value from device extension.
3191 srb
.TimeOutValue
= deviceExtension
->TimeOutValue
;
3193 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3194 cdb
->MODE_SENSE
.PageCode
= PageMode
;
3195 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
3199 status
= ScsiClassSendSrbSynchronous(DeviceObject
,
3206 if (status
== STATUS_VERIFY_REQUIRED
) {
3209 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3210 // this status. MODE SENSE commands should be retried anyway.
3222 } else if (SRB_STATUS(srb
.SrbStatus
) == SRB_STATUS_DATA_OVERRUN
) {
3223 status
= STATUS_SUCCESS
;
3226 if (NT_SUCCESS(status
)) {
3227 return(srb
.DataTransferLength
);
3232 } // end ScsiClassModeSense()
3237 ScsiClassFindModePage(
3238 IN PCHAR ModeSenseBuffer
,
3246 Routine Description:
3248 This routine scans through the mode sense data and finds the requested
3249 mode sense page code.
3252 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3254 Length - Indicates the length of valid data.
3256 PageMode - Supplies the page mode to be searched for.
3258 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3262 A pointer to the the requested mode page. If the mode page was not found
3263 then NULL is return.
3268 ULONG parameterHeaderLength
;
3270 limit
= (PUCHAR
)ModeSenseBuffer
+ Length
;
3271 parameterHeaderLength
= (Use6Byte
) ? sizeof(MODE_PARAMETER_HEADER
) : sizeof(MODE_PARAMETER_HEADER10
);
3275 // Skip the mode select header and block descriptors.
3278 if (Length
< parameterHeaderLength
) {
3284 ModeSenseBuffer
+= parameterHeaderLength
+ ((Use6Byte
) ? ((PMODE_PARAMETER_HEADER
) ModeSenseBuffer
)->BlockDescriptorLength
:
3285 ((PMODE_PARAMETER_HEADER10
) ModeSenseBuffer
)->BlockDescriptorLength
[1]);
3288 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3289 // requested page until the limit is reached.
3293 while ((PUCHAR
)ModeSenseBuffer
< limit
) {
3295 if (((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageCode
== PageMode
) {
3296 return(ModeSenseBuffer
);
3300 // Advance to the next page.
3303 ModeSenseBuffer
+= ((PMODE_DISCONNECT_PAGE
) ModeSenseBuffer
)->PageLength
+ 2;
3311 ScsiClassSendSrbAsynchronous(
3312 PDEVICE_OBJECT DeviceObject
,
3313 PSCSI_REQUEST_BLOCK Srb
,
3315 PVOID BufferAddress
,
3317 BOOLEAN WriteToDevice
3321 Routine Description:
3323 This routine takes a partially built Srb and an Irp and sends it down to
3327 DeviceObject - Supplies the device object for the orginal request.
3329 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3330 CDB and the SRB timeout value must be filled in. The SRB must not be
3331 allocated from zone.
3333 Irp - Supplies the requesting Irp.
3335 BufferAddress - Supplies a pointer to the buffer to be transfered.
3337 BufferLength - Supplies the length of data transfer.
3339 WriteToDevice - Indicates the data transfer will be from system memory to
3344 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3349 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3350 PIO_STACK_LOCATION irpStack
;
3355 // Write length to SRB.
3358 Srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
3361 // Set SCSI bus address.
3364 Srb
->PathId
= deviceExtension
->PathId
;
3365 Srb
->TargetId
= deviceExtension
->TargetId
;
3366 Srb
->Lun
= deviceExtension
->Lun
;
3368 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
3371 // This is a violation of the SCSI spec but it is required for
3375 Srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3378 // Indicate auto request sense by specifying buffer and size.
3381 Srb
->SenseInfoBuffer
= deviceExtension
->SenseData
;
3382 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
3383 Srb
->DataBuffer
= BufferAddress
;
3385 if (BufferAddress
!= NULL
) {
3388 // Build Mdl if necessary.
3391 if (Irp
->MdlAddress
== NULL
) {
3393 if (IoAllocateMdl(BufferAddress
,
3399 return(STATUS_INSUFFICIENT_RESOURCES
);
3402 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3407 // Make sure the buffer requested matches the MDL.
3410 ASSERT(BufferAddress
== MmGetMdlVirtualAddress(Irp
->MdlAddress
));
3417 Srb
->SrbFlags
= WriteToDevice
? SRB_FLAGS_DATA_OUT
: SRB_FLAGS_DATA_IN
;
3425 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
3429 // Disable synchronous transfer for these requests.
3432 Srb
->SrbFlags
|= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
3435 // Set the transfer length.
3438 Srb
->DataTransferLength
= BufferLength
;
3444 Srb
->ScsiStatus
= Srb
->SrbStatus
= 0;
3449 // Save a few parameters in the current stack location.
3452 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3455 // Save retry count in current Irp stack.
3458 irpStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
3461 // Set up IoCompletion routine address.
3464 IoSetCompletionRoutine(Irp
, ScsiClassIoComplete
, Srb
, TRUE
, TRUE
, TRUE
);
3467 // Get next stack location and
3468 // set major function code.
3471 irpStack
= IoGetNextIrpStackLocation(Irp
);
3473 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3476 // Save SRB address in next stack for port driver.
3479 irpStack
->Parameters
.Scsi
.Srb
= Srb
;
3482 // Set up Irp Address.
3485 Srb
->OriginalRequest
= Irp
;
3488 // Call the port driver to process the request.
3491 return(IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
));
3498 ScsiClassDeviceControlDispatch(
3499 PDEVICE_OBJECT DeviceObject
,
3505 Routine Description:
3507 The routine is the common class driver device control dispatch entry point.
3508 This routine is invokes the device-specific drivers DeviceControl routine,
3509 (which may call the Class driver's common DeviceControl routine).
3513 DeviceObject - Supplies a pointer to the device object for this request.
3515 Irp - Supplies the Irp making the request.
3519 Returns the status returned from the device-specific driver.
3525 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3529 // Call the class specific driver DeviceControl routine.
3530 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3533 ASSERT(deviceExtension
->ClassDeviceControl
);
3535 return deviceExtension
->ClassDeviceControl(DeviceObject
,Irp
);
3541 ScsiClassDeviceControl(
3542 PDEVICE_OBJECT DeviceObject
,
3547 Routine Description:
3549 The routine is the common class driver device control dispatch function.
3550 This routine is called by a class driver when it get an unrecognized
3551 device control request. This routine will perform the correct action for
3552 common requests such as lock media. If the device request is unknown it
3553 passed down to the next level.
3557 DeviceObject - Supplies a pointer to the device object for this request.
3559 Irp - Supplies the Irp making the request.
3563 Returns back a STATUS_PENDING or a completion status.
3568 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3569 PIO_STACK_LOCATION nextStack
;
3570 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3571 PSCSI_REQUEST_BLOCK srb
;
3574 ULONG modifiedIoControlCode
;
3576 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3577 IOCTL_STORAGE_RESET_DEVICE
) {
3579 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
3580 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3581 status
= STATUS_UNSUCCESSFUL
;
3582 goto SetStatusAndReturn
;
3586 // If this is a pass through I/O control, set the minor function code
3587 // and device address and pass it to the port driver.
3590 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
3591 || irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
3593 PSCSI_PASS_THROUGH scsiPass
;
3595 nextStack
= IoGetNextIrpStackLocation(Irp
);
3598 // Validiate the user buffer.
3601 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
)){
3603 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3604 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3605 status
= STATUS_INVALID_PARAMETER
;
3606 goto SetStatusAndReturn
;
3610 // Force the SCSI address to the correct value.
3613 scsiPass
= Irp
->AssociatedIrp
.SystemBuffer
;
3614 scsiPass
->PathId
= deviceExtension
->PathId
;
3615 scsiPass
->TargetId
= deviceExtension
->TargetId
;
3616 scsiPass
->Lun
= deviceExtension
->Lun
;
3619 // NOTICE: The SCSI-II specificaiton indicates that this field
3620 // should be zero; however, some target controllers ignore the logical
3621 // unit number in the INDENTIFY message and only look at the logical
3622 // unit number field in the CDB.
3625 scsiPass
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
3627 nextStack
->Parameters
= irpStack
->Parameters
;
3628 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
3629 nextStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
3631 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
3632 goto SetStatusAndReturn
;
3635 if (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
) {
3637 PSCSI_ADDRESS scsiAddress
= Irp
->AssociatedIrp
.SystemBuffer
;
3639 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3640 sizeof(SCSI_ADDRESS
)) {
3643 // Indicate unsuccessful status and no data transferred.
3646 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3647 Irp
->IoStatus
.Information
= 0;
3648 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3649 status
= STATUS_BUFFER_TOO_SMALL
;
3650 goto SetStatusAndReturn
;
3654 scsiAddress
->Length
= sizeof(SCSI_ADDRESS
);
3655 scsiAddress
->PortNumber
= deviceExtension
->PortNumber
;
3656 scsiAddress
->PathId
= deviceExtension
->PathId
;
3657 scsiAddress
->TargetId
= deviceExtension
->TargetId
;
3658 scsiAddress
->Lun
= deviceExtension
->Lun
;
3659 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
3660 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3661 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3662 status
= STATUS_SUCCESS
;
3663 goto SetStatusAndReturn
;
3666 srb
= ExAllocatePool(NonPagedPool
, SCSI_REQUEST_BLOCK_SIZE
);
3670 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3671 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3672 status
= STATUS_INSUFFICIENT_RESOURCES
;
3673 goto SetStatusAndReturn
;
3677 // Write zeros to Srb.
3680 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
3682 cdb
= (PCDB
)srb
->Cdb
;
3685 // Change the device type to disk for the switch statement.
3688 modifiedIoControlCode
= (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
3689 & ~0xffff0000) | (IOCTL_DISK_BASE
<< 16);
3691 switch (modifiedIoControlCode
) {
3693 case IOCTL_DISK_CHECK_VERIFY
: {
3696 PIO_STACK_LOCATION newStack
;
3698 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3701 // If a buffer for a media change count was provided, make sure it's
3702 // big enough to hold the result
3705 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
3708 // If the buffer is too small to hold the media change count
3709 // then return an error to the caller
3712 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
3715 DebugPrint((3,"ScsiDeviceIoControl: media count "
3716 "buffer too small\n"));
3718 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3719 Irp
->IoStatus
.Information
= 0;
3721 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3722 status
= STATUS_BUFFER_TOO_SMALL
;
3723 goto SetStatusAndReturn
;
3728 // The caller has provided a valid buffer. Allocate an additional
3729 // irp and stick the CheckVerify completion routine on it. We will
3730 // then send this down to the port driver instead of the irp the
3734 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
3738 // Allocate a new irp to send the TestUnitReady to the port driver
3741 irp2
= IoAllocateIrp((CCHAR
) (DeviceObject
->StackSize
+ 3), FALSE
);
3744 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3745 Irp
->IoStatus
.Information
= 0;
3747 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3748 status
= STATUS_INSUFFICIENT_RESOURCES
;
3749 goto SetStatusAndReturn
;
3754 irp2
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
3755 IoSetNextIrpStackLocation(irp2
);
3758 // Set the top stack location and shove the master Irp into the
3762 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3763 newStack
->Parameters
.Others
.Argument1
= Irp
;
3764 newStack
->DeviceObject
= DeviceObject
;
3767 // Stick the check verify completion routine onto the stack
3768 // and prepare the irp for the port driver
3771 IoSetCompletionRoutine(irp2
,
3772 ScsiClassCheckVerifyComplete
,
3778 IoSetNextIrpStackLocation(irp2
);
3779 newStack
= IoGetCurrentIrpStackLocation(irp2
);
3780 newStack
->DeviceObject
= DeviceObject
;
3783 // Mark the master irp as pending - whether the lower level
3784 // driver completes it immediately or not this should allow it
3785 // to go all the way back up.
3788 IoMarkIrpPending(Irp
);
3799 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
3802 // Set timeout value.
3805 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3808 // Since this routine will always hand the request to the
3809 // port driver if there isn't a data transfer to be done
3810 // we don't have to worry about completing the request here
3814 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3824 case IOCTL_DISK_MEDIA_REMOVAL
: {
3826 PPREVENT_MEDIA_REMOVAL MediaRemoval
= Irp
->AssociatedIrp
.SystemBuffer
;
3829 // Prevent/Allow media removal.
3832 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
3834 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
3835 sizeof(PREVENT_MEDIA_REMOVAL
)) {
3838 // Indicate unsuccessful status and no data transferred.
3841 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
3842 Irp
->IoStatus
.Information
= 0;
3844 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3845 status
= STATUS_BUFFER_TOO_SMALL
;
3846 goto SetStatusAndReturn
;
3850 // Get physical device extension. This is where the
3851 // lock count is stored.
3854 deviceExtension
= deviceExtension
->PhysicalDevice
->DeviceExtension
;
3857 // If command succeeded then increment or decrement lock counter.
3860 if (MediaRemoval
->PreventMediaRemoval
) {
3863 // This is a lock command. Reissue the command in case bus or device
3864 // was reset and lock cleared.
3867 InterlockedIncrement(&deviceExtension
->LockCount
);
3870 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
3871 deviceExtension
->LockCount
,
3872 deviceExtension
->DeviceNumber
));
3877 // This is an unlock command.
3880 if (!deviceExtension
->LockCount
||
3881 (InterlockedDecrement(&deviceExtension
->LockCount
) != 0)) {
3884 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3885 deviceExtension
->LockCount
,
3886 deviceExtension
->DeviceNumber
));
3889 // Don't unlock because someone still wants it locked.
3892 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3894 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3895 status
= STATUS_SUCCESS
;
3896 goto SetStatusAndReturn
;
3900 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3901 deviceExtension
->LockCount
,
3902 deviceExtension
->DeviceNumber
));
3907 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
3910 // TRUE - prevent media removal.
3911 // FALSE - allow media removal.
3914 cdb
->MEDIA_REMOVAL
.Prevent
= MediaRemoval
->PreventMediaRemoval
;
3917 // Set timeout value.
3920 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3921 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3929 // Some devices will not support lock/unlock.
3930 // Pretend that it worked.
3936 case IOCTL_DISK_RESERVE
: {
3939 // Reserve logical unit.
3944 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RESERVE_UNIT
;
3947 // Set timeout value.
3950 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3952 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3962 case IOCTL_DISK_RELEASE
: {
3965 // Release logical unit.
3970 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_RELEASE_UNIT
;
3973 // Set timeout value.
3976 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
3978 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
3988 case IOCTL_DISK_EJECT_MEDIA
: {
3996 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
3997 cdb
->START_STOP
.LoadEject
= 1;
3998 cdb
->START_STOP
.Start
= 0;
4001 // Set timeout value.
4004 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4005 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4014 case IOCTL_DISK_LOAD_MEDIA
: {
4020 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4024 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
4025 cdb
->START_STOP
.LoadEject
= 1;
4026 cdb
->START_STOP
.Start
= 1;
4029 // Set timeout value.
4032 srb
->TimeOutValue
= deviceExtension
->TimeOutValue
;
4033 status
= ScsiClassSendSrbAsynchronous(DeviceObject
,
4043 case IOCTL_DISK_FIND_NEW_DEVICES
: {
4046 // Search for devices that have been powered on since the last
4047 // device search or system initialization.
4050 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4051 status
= DriverEntry(DeviceObject
->DriverObject
,
4054 Irp
->IoStatus
.Status
= status
;
4056 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4063 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4066 // Pass the device control to the next driver.
4072 // Copy the Irp stack parameters to the next stack location.
4075 nextStack
= IoGetNextIrpStackLocation(Irp
);
4076 nextStack
->Parameters
= irpStack
->Parameters
;
4077 nextStack
->MajorFunction
= irpStack
->MajorFunction
;
4078 nextStack
->MinorFunction
= irpStack
->MinorFunction
;
4080 status
= IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4084 } // end switch( ...
4094 ScsiClassShutdownFlush(
4095 IN PDEVICE_OBJECT DeviceObject
,
4101 Routine Description:
4103 This routine is called for a shutdown and flush IRPs. These are sent by the
4104 system before it actually shuts down or when the file system does a flush.
4105 If it exists, the device-specific driver's routine will be invoked. If there
4106 wasn't one specified, the Irp will be completed with an Invalid device request.
4110 DriverObject - Pointer to device object to being shutdown by system.
4121 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4123 if (deviceExtension
->ClassShutdownFlush
) {
4126 // Call the device-specific driver's routine.
4129 return deviceExtension
->ClassShutdownFlush(DeviceObject
, Irp
);
4133 // Device-specific driver doesn't support this.
4136 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
4137 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4139 return STATUS_INVALID_DEVICE_REQUEST
;
4145 ScsiClassFindUnclaimedDevices(
4146 IN PCLASS_INIT_DATA InitializationData
,
4147 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4151 ULONG scsiBus
,deviceCount
= 0;
4152 PCHAR buffer
= (PCHAR
)AdapterInformation
;
4153 PSCSI_INQUIRY_DATA lunInfo
;
4154 PINQUIRYDATA inquiryData
;
4156 for (scsiBus
=0; scsiBus
< (ULONG
)AdapterInformation
->NumberOfBuses
; scsiBus
++) {
4159 // Get the SCSI bus scan data for this bus.
4162 lunInfo
= (PVOID
) (buffer
+ AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
);
4165 // Search list for unclaimed disk devices.
4168 while (AdapterInformation
->BusData
[scsiBus
].InquiryDataOffset
) {
4170 inquiryData
= (PVOID
)lunInfo
->InquiryData
;
4172 ASSERT(InitializationData
->ClassFindDeviceCallBack
);
4174 if ((InitializationData
->ClassFindDeviceCallBack(inquiryData
)) && (!lunInfo
->DeviceClaimed
)) {
4179 if (lunInfo
->NextInquiryDataOffset
== 0) {
4183 lunInfo
= (PVOID
) (buffer
+ lunInfo
->NextInquiryDataOffset
);
4193 ScsiClassCreateDeviceObject(
4194 IN PDRIVER_OBJECT DriverObject
,
4195 IN PCCHAR ObjectNameBuffer
,
4196 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject
,
4197 IN OUT PDEVICE_OBJECT
*DeviceObject
,
4198 IN PCLASS_INIT_DATA InitializationData
4203 Routine Description:
4205 This routine creates an object for the physical device specified and
4206 sets up the deviceExtension's function pointers for each entry point
4207 in the device-specific driver.
4211 DriverObject - Pointer to driver object created by system.
4213 ObjectNameBuffer - Dir. name of the object to create.
4215 PhysicalDeviceObject - Pointer to the physical (class) device object for
4216 this logical unit or NULL if this is it.
4218 DeviceObject - Pointer to the device object pointer we will return.
4220 InitializationData - Pointer to the init data created by the device-specific driver.
4229 STRING ntNameString
;
4230 UNICODE_STRING ntUnicodeString
;
4232 PDEVICE_OBJECT deviceObject
= NULL
;
4234 *DeviceObject
= NULL
;
4237 "ScsiClassCreateDeviceObject: Create device object %s\n",
4240 RtlInitString(&ntNameString
,
4243 status
= RtlAnsiStringToUnicodeString(&ntUnicodeString
,
4247 if (!NT_SUCCESS(status
)) {
4250 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4253 ntUnicodeString
.Buffer
= NULL
;
4257 status
= IoCreateDevice(DriverObject
,
4258 InitializationData
->DeviceExtensionSize
,
4260 InitializationData
->DeviceType
,
4261 InitializationData
->DeviceCharacteristics
,
4266 if (!NT_SUCCESS(status
)) {
4269 "CreateDiskDeviceObjects: Can not create device object %s\n",
4274 PDEVICE_EXTENSION deviceExtension
= deviceObject
->DeviceExtension
;
4277 // Fill in entry points
4280 deviceExtension
->ClassError
= InitializationData
->ClassError
;
4281 deviceExtension
->ClassReadWriteVerification
= InitializationData
->ClassReadWriteVerification
;
4282 deviceExtension
->ClassFindDevices
= InitializationData
->ClassFindDevices
;
4283 deviceExtension
->ClassDeviceControl
= InitializationData
->ClassDeviceControl
;
4284 deviceExtension
->ClassShutdownFlush
= InitializationData
->ClassShutdownFlush
;
4285 deviceExtension
->ClassCreateClose
= InitializationData
->ClassCreateClose
;
4286 deviceExtension
->ClassStartIo
= InitializationData
->ClassStartIo
;
4288 deviceExtension
->MediaChangeCount
= 0;
4291 // If a pointer to the physical device object was passed in then use
4292 // that. If the value was NULL, then this is the physical device so
4293 // use the pointer to the device we just created.
4296 if(ARGUMENT_PRESENT(PhysicalDeviceObject
)) {
4297 deviceExtension
->PhysicalDevice
= PhysicalDeviceObject
;
4299 deviceExtension
->PhysicalDevice
= deviceObject
;
4303 *DeviceObject
= deviceObject
;
4305 RtlFreeUnicodeString(&ntUnicodeString
);
4308 // Indicate the ntUnicodeString is free.
4311 ntUnicodeString
.Buffer
= NULL
;
4319 ScsiClassClaimDevice(
4320 IN PDEVICE_OBJECT PortDeviceObject
,
4321 IN PSCSI_INQUIRY_DATA LunInfo
,
4323 OUT PDEVICE_OBJECT
*NewPortDeviceObject OPTIONAL
4327 Routine Description:
4329 This function claims a device in the port driver. The port driver object
4330 is updated with the correct driver object if the device is successfully
4335 PortDeviceObject - Supplies the base port device object.
4337 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4339 Release - Indicates the logical unit should be released rather than claimed.
4341 NewPortDeviceObject - Returns the updated port device object to be used
4342 for all future accesses.
4346 Returns a status indicating success or failure of the operation.
4351 IO_STATUS_BLOCK ioStatus
;
4353 PIO_STACK_LOCATION irpStack
;
4356 SCSI_REQUEST_BLOCK srb
;
4360 if (NewPortDeviceObject
!= NULL
) {
4361 *NewPortDeviceObject
= NULL
;
4365 // Clear the SRB fields.
4368 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4371 // Write length to SRB.
4374 srb
.Length
= SCSI_REQUEST_BLOCK_SIZE
;
4377 // Set SCSI bus address.
4380 srb
.PathId
= LunInfo
->PathId
;
4381 srb
.TargetId
= LunInfo
->TargetId
;
4382 srb
.Lun
= LunInfo
->Lun
;
4384 srb
.Function
= Release
? SRB_FUNCTION_RELEASE_DEVICE
:
4385 SRB_FUNCTION_CLAIM_DEVICE
;
4388 // Set the event object to the unsignaled state.
4389 // It will be used to signal request completion.
4392 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
4395 // Build synchronous request with no transfer.
4398 irp
= IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE
,
4410 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4411 return STATUS_INSUFFICIENT_RESOURCES
;
4414 irpStack
= IoGetNextIrpStackLocation(irp
);
4417 // Save SRB address in next stack for port driver.
4420 irpStack
->Parameters
.Scsi
.Srb
= &srb
;
4423 // Set up IRP Address.
4426 srb
.OriginalRequest
= irp
;
4429 // Call the port driver with the request and wait for it to complete.
4432 status
= IoCallDriver(PortDeviceObject
, irp
);
4433 if (status
== STATUS_PENDING
) {
4435 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
4436 status
= ioStatus
.Status
;
4440 // If this is a release request, then just decrement the reference count
4441 // and return. The status does not matter.
4446 ObDereferenceObject(PortDeviceObject
);
4447 return STATUS_SUCCESS
;
4450 if (!NT_SUCCESS(status
)) {
4454 ASSERT(srb
.DataBuffer
!= NULL
);
4457 // Reference the new port driver object so that it will not go away while
4458 // it is being used.
4461 status
= ObReferenceObjectByPointer(srb
.DataBuffer
,
4466 if (!NT_SUCCESS(status
)) {
4472 // Return the new port device object pointer.
4475 if (NewPortDeviceObject
!= NULL
) {
4476 *NewPortDeviceObject
= srb
.DataBuffer
;
4485 ScsiClassInternalIoControl (
4486 IN PDEVICE_OBJECT DeviceObject
,
4492 Routine Description:
4494 This routine passes internal device controls to the port driver.
4495 Internal device controls are used by higher level class drivers to
4496 send scsi requests to a device that are not normally sent by a generic
4499 The path ID, target ID and logical unit ID are set in the srb so the
4500 higher level driver does not have to figure out what values are actually
4505 DeviceObject - Supplies a pointer to the device object for this request.
4507 Irp - Supplies the Irp making the request.
4511 Returns back a STATUS_PENDING or a completion status.
4515 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4516 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4517 PSCSI_REQUEST_BLOCK srb
;
4520 // Get a pointer to the SRB.
4523 srb
= irpStack
->Parameters
.Scsi
.Srb
;
4526 // Set SCSI bus address.
4529 srb
->PathId
= deviceExtension
->PathId
;
4530 srb
->TargetId
= deviceExtension
->TargetId
;
4531 srb
->Lun
= deviceExtension
->Lun
;
4534 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4535 // zero; however, some target controllers ignore the logical unit number
4536 // in the INDENTIFY message and only look at the logical unit number field
4540 srb
->Cdb
[1] |= deviceExtension
->Lun
<< 5;
4543 // Set the parameters in the next stack location.
4546 irpStack
= IoGetNextIrpStackLocation(Irp
);
4548 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4549 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4550 irpStack
->MinorFunction
= IRP_MN_SCSI_CLASS
;
4552 IoSetCompletionRoutine(Irp
, ClassIoCompletion
, NULL
, TRUE
, TRUE
, TRUE
);
4553 return IoCallDriver(deviceExtension
->PortDeviceObject
, Irp
);
4559 IN PDEVICE_OBJECT DeviceObject
,
4566 Routine Description:
4568 This routine is called when an internal device control I/O request
4569 has completed. It marks the IRP pending if necessary and returns the
4570 status of the request.
4574 DeviceObject - Target device object.
4576 Irp - Completed request.
4582 Returns the status of the completed request.
4587 UNREFERENCED_PARAMETER(Context
);
4588 UNREFERENCED_PARAMETER(DeviceObject
);
4591 // If pending is returned for this Irp then mark current stack
4595 if (Irp
->PendingReturned
) {
4597 IoMarkIrpPending( Irp
);
4600 return Irp
->IoStatus
.Status
;
4606 ScsiClassInitializeSrbLookasideList(
4607 IN PDEVICE_EXTENSION DeviceExtension
,
4608 IN ULONG NumberElements
4613 Routine Description:
4615 This routine sets up a lookaside listhead for srbs.
4619 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4621 NumberElements - Supplies the maximum depth of the lookaside list.
4631 ExInitializeNPagedLookasideList(&DeviceExtension
->SrbLookasideListHead
,
4634 NonPagedPoolMustSucceed
,
4635 SCSI_REQUEST_BLOCK_SIZE
,
4637 (USHORT
)NumberElements
);
4644 ScsiClassQueryTimeOutRegistryValue(
4645 IN PUNICODE_STRING RegistryPath
4650 Routine Description:
4652 This routine determines whether a reg key for a user-specified timeout value exists.
4656 RegistryPath - Pointer to the hardware reg. entry describing the key.
4660 New default timeout for a class of devices.
4666 // Find the appropriate reg. key
4669 PRTL_QUERY_REGISTRY_TABLE parameters
= NULL
;
4676 if (!RegistryPath
) {
4680 parameters
= ExAllocatePool(NonPagedPool
,
4681 sizeof(RTL_QUERY_REGISTRY_TABLE
)*2);
4687 size
= RegistryPath
->MaximumLength
+ sizeof(WCHAR
);
4688 path
= ExAllocatePool(NonPagedPool
, size
);
4691 ExFreePool(parameters
);
4695 RtlZeroMemory(path
,size
);
4696 RtlCopyMemory(path
, RegistryPath
->Buffer
, size
- sizeof(WCHAR
));
4700 // Check for the Timeout value.
4703 RtlZeroMemory(parameters
,
4704 (sizeof(RTL_QUERY_REGISTRY_TABLE
)*2));
4706 parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
4707 parameters
[0].Name
= L
"TimeOutValue";
4708 parameters
[0].EntryContext
= &timeOut
;
4709 parameters
[0].DefaultType
= REG_DWORD
;
4710 parameters
[0].DefaultData
= &zero
;
4711 parameters
[0].DefaultLength
= sizeof(ULONG
);
4713 status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
4719 if (!(NT_SUCCESS(status
))) {
4723 ExFreePool(parameters
);
4727 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
4737 ScsiClassCheckVerifyComplete(
4738 IN PDEVICE_OBJECT DeviceObject
,
4745 Routine Description:
4747 This routine executes when the port driver has completed a check verify
4748 ioctl. It will set the status of the master Irp, copy the media change
4749 count and complete the request.
4753 DeviceObject - Supplies the device object which represents the logical
4756 Irp - Supplies the Irp which has completed.
4767 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4768 PDEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
4769 PDEVICE_EXTENSION physicalExtension
=
4770 deviceExtension
->PhysicalDevice
->DeviceExtension
;
4773 originalIrp
= irpStack
->Parameters
.Others
.Argument1
;
4776 // Copy the media change count and status
4779 *((PULONG
) (originalIrp
->AssociatedIrp
.SystemBuffer
)) =
4780 physicalExtension
->MediaChangeCount
;
4782 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
4783 "device %d is %d\n",
4784 physicalExtension
->DeviceNumber
,
4785 physicalExtension
->MediaChangeCount
));
4787 originalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
4788 originalIrp
->IoStatus
.Information
= sizeof(ULONG
);
4790 IoCompleteRequest(originalIrp
, IO_DISK_INCREMENT
);
4794 return STATUS_MORE_PROCESSING_REQUIRED
;
4799 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject
,
4803 PIO_STATUS_BLOCK IoStatusBlock
= Irp
->UserIosb
;
4804 PKEVENT Event
= Irp
->UserEvent
;
4807 *IoStatusBlock
= Irp
->IoStatus
;
4808 Irp
->UserIosb
= NULL
;
4809 Irp
->UserEvent
= NULL
;
4813 Mdl
= Irp
->MdlAddress
;
4815 // if necessary - unlock pages
4816 if ((Mdl
->MdlFlags
& MDL_PAGES_LOCKED
) &&
4817 !(Mdl
->MdlFlags
& MDL_PARTIAL_HAS_BEEN_MAPPED
))
4826 // free irp and set event to unsignaled state
4828 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
4830 return STATUS_MORE_PROCESSING_REQUIRED
;