+++ /dev/null
-/*
- * PROJECT: ReactOS Storage Stack
- * LICENSE: DDK - see license.txt in the root dir
- * FILE: drivers/storage/class2/class2.c
- * PURPOSE: SCSI Class driver routines
- * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
- */
-
-#include <ntddk.h>
-#include <ntdddisk.h>
-#include <scsi.h>
-#include <include/class2.h>
-#include <stdio.h>
-
-//#define NDEBUG
-#include <debug.h>
-
-#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, ScsiClassGetInquiryData)
-#pragma alloc_text(PAGE, ScsiClassInitialize)
-#pragma alloc_text(PAGE, ScsiClassGetCapabilities)
-#pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
-#pragma alloc_text(PAGE, ScsiClassClaimDevice)
-#pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
-#endif
-
-
-#define INQUIRY_DATA_SIZE 2048
-#define START_UNIT_TIMEOUT 30
-
-NTSTATUS
-STDCALL
-ScsiClassCreateClose(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-ScsiClassReadWrite(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-ScsiClassDeviceControlDispatch(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-ScsiClassDeviceControl(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-ScsiClassInternalIoControl (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-ScsiClassShutdownFlush(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- );
-
-NTSTATUS
-STDCALL
-DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- );
-
-//
-// Class internal routines
-//
-
-
-VOID
-STDCALL
-RetryRequest(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PSCSI_REQUEST_BLOCK Srb,
- BOOLEAN Associated
- );
-
-VOID
-STDCALL
-StartUnit(
- IN PDEVICE_OBJECT DeviceObject
- );
-
-NTSTATUS
-STDCALL
-ClassIoCompletion(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- );
-
-NTSTATUS
-STDCALL
-DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- )
-{
- return STATUS_SUCCESS;
-}
-
-\f
-ULONG
-STDCALL
-ScsiClassInitialize(
- IN PVOID Argument1,
- IN PVOID Argument2,
- IN PCLASS_INIT_DATA InitializationData
- )
-
-/*++
-
-Routine Description:
-
- This routine is called by a class driver during its
- DriverEntry routine to initialize the driver.
-
-Arguments:
-
- Argument1 - Driver Object.
- Argument2 - Registry Path.
- InitializationData - Device-specific driver's initialization data.
-
-Return Value:
-
- A valid return code for a DriverEntry routine.
-
---*/
-
-{
-
-
- PDRIVER_OBJECT DriverObject = Argument1;
- ULONG portNumber = 0;
- PDEVICE_OBJECT portDeviceObject;
- NTSTATUS status;
- STRING deviceNameString;
- UNICODE_STRING unicodeDeviceName;
- PFILE_OBJECT fileObject;
- CCHAR deviceNameBuffer[256];
- BOOLEAN deviceFound = FALSE;
-
- DebugPrint((3,"\n\nSCSI Class Driver\n"));
-
- //
- // Validate the length of this structure. This is effectively a
- // version check.
- //
-
- if (InitializationData->InitializationDataSize > sizeof(CLASS_INIT_DATA)) {
-
- DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
- return (ULONG) STATUS_REVISION_MISMATCH;
- }
-
- //
- // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
- // are not required entry points.
- //
-
- if ((!InitializationData->ClassFindDevices) ||
- (!InitializationData->ClassDeviceControl) ||
- (!((InitializationData->ClassReadWriteVerification) ||
- (InitializationData->ClassStartIo)))) {
-
- DebugPrint((0,
- "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
-
- return (ULONG) STATUS_REVISION_MISMATCH;
- }
-
- //
- // Update driver object with entry points.
- //
-
- DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
- DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
- DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
- DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch;
- DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
- DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
-
- if (InitializationData->ClassStartIo) {
- DriverObject->DriverStartIo = InitializationData->ClassStartIo;
- }
-
- //
- // Open port driver controller device objects by name.
- //
-
- do {
-
- sprintf(deviceNameBuffer, "\\Device\\ScsiPort%d", portNumber);
-
- DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer));
-
- RtlInitString(&deviceNameString, deviceNameBuffer);
-
- status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
- &deviceNameString,
- TRUE);
-
- if (!NT_SUCCESS(status)){
- break;
- }
-
- status = IoGetDeviceObjectPointer(&unicodeDeviceName,
- FILE_READ_ATTRIBUTES,
- &fileObject,
- &portDeviceObject);
-
- if (NT_SUCCESS(status)) {
-
- //
- // Call the device-specific driver's FindDevice routine.
- //
-
- if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData,
- portDeviceObject, portNumber)) {
-
- deviceFound = TRUE;
- }
- }
-
- //
- // Check next SCSI adapter.
- //
-
- portNumber++;
-
- } while(NT_SUCCESS(status));
-
- return deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;
-}
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassCreateClose(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
-
-/*++
-
-Routine Description:
-
- SCSI class driver create and close routine. This is called by the I/O system
- when the device is opened or closed.
-
-Arguments:
-
- DriverObject - Pointer to driver object created by system.
-
- Irp - IRP involved.
-
-Return Value:
-
- Device-specific drivers return value or STATUS_SUCCESS.
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
-
- //
- // Invoke the device-specific routine, if one exists. Otherwise complete
- // with SUCCESS
- //
-
- if (deviceExtension->ClassCreateClose) {
-
- return deviceExtension->ClassCreateClose(DeviceObject, Irp);
-
- } else {
- Irp->IoStatus.Status = STATUS_SUCCESS;
-
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return(STATUS_SUCCESS);
- }
-}
-
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassReadWrite(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
-
-/*++
-
-Routine Description:
-
- This is the system entry point for read and write requests. The device-specific handler is invoked
- to perform any validation necessary. The number of bytes in the request are
- checked against the maximum byte counts that the adapter supports and requests are broken up into
- smaller sizes if necessary.
-
-Arguments:
-
- DeviceObject
- Irp - IO request
-
-Return Value:
-
- NT Status
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
- ULONG transferPages;
- ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
- LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
- ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
- NTSTATUS status;
-
- if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
- !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
-
- //
- // if DO_VERIFY_VOLUME bit is set
- // in device object flags, fail request.
- //
-
- IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
-
- Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
- Irp->IoStatus.Information = 0;
-
- IoCompleteRequest(Irp, 0);
- return STATUS_VERIFY_REQUIRED;
- }
-
- //
- // Invoke the device specific routine to do whatever it needs to verify
- // this request.
- //
-
- ASSERT(deviceExtension->ClassReadWriteVerification);
-
- status = deviceExtension->ClassReadWriteVerification(DeviceObject,Irp);
-
- if (!NT_SUCCESS(status)) {
-
- //
- // It is up to the device specific driver to set the Irp status.
- //
-
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
- return status;
- } else if (status == STATUS_PENDING) {
-
- IoMarkIrpPending(Irp);
- return STATUS_PENDING;
- }
-
- //
- // Check for a zero length IO, as several macros will turn this into
- // seemingly a 0xffffffff length request.
- //
-
- if (transferByteCount == 0) {
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
-
- }
-
- if (deviceExtension->ClassStartIo) {
-
- IoMarkIrpPending(Irp);
-
- IoStartPacket(DeviceObject,
- Irp,
- NULL,
- NULL);
-
- return STATUS_PENDING;
- }
-
- //
- // Mark IRP with status pending.
- //
-
- IoMarkIrpPending(Irp);
-
- //
- // Add partition byte offset to make starting byte relative to
- // beginning of disk. In addition, add in skew for DM Driver, if any.
- //
-
- currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart +
- deviceExtension->DMByteSkew);
-
- //
- // Calculate number of pages in this transfer.
- //
-
- transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
- currentIrpStack->Parameters.Read.Length);
-
- //
- // Check if request length is greater than the maximum number of
- // bytes that the hardware can transfer.
- //
-
- if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
- transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
-
- DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
- DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
- maximumTransferLength));
- DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
- currentIrpStack->Parameters.Read.Length));
-
- transferPages =
- deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
-
- if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
- maximumTransferLength = transferPages << PAGE_SHIFT;
- }
-
- //
- // Check that maximum transfer size is not zero.
- //
-
- if (maximumTransferLength == 0) {
- maximumTransferLength = PAGE_SIZE;
- }
-
- //
- // Mark IRP with status pending.
- //
-
- IoMarkIrpPending(Irp);
-
- //
- // Request greater than port driver maximum.
- // Break up into smaller routines.
- //
-
- ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
-
-
- return STATUS_PENDING;
- }
-
- //
- // Build SRB and CDB for this IRP.
- //
-
- ScsiClassBuildRequest(DeviceObject, Irp);
-
- //
- // Return the results of the call to the port driver.
- //
-
- return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
-
-} // end ScsiClassReadWrite()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassGetCapabilities(
- IN PDEVICE_OBJECT PortDeviceObject,
- OUT PIO_SCSI_CAPABILITIES *PortCapabilities
- )
-
-/*++
-
-Routine Description:
-
- This routine builds and sends a request to the port driver to
- get a pointer to a structure that describes the adapter's
- capabilities/limitations. This routine is sychronous.
-
-Arguments:
-
- PortDeviceObject - Port driver device object representing the HBA.
-
- PortCapabilities - Location to store pointer to capabilities structure.
-
-Return Value:
-
- Nt status indicating the results of the operation.
-
-Notes:
-
- This routine should only be called at initialization time.
-
---*/
-
-{
- PIRP irp;
- IO_STATUS_BLOCK ioStatus;
- KEVENT event;
- NTSTATUS status;
-
- PAGED_CODE();
-
- //
- // Create notification event object to be used to signal the
- // request completion.
- //
-
- KeInitializeEvent(&event, NotificationEvent, FALSE);
-
- //
- // Build the synchronous request to be sent to the port driver
- // to perform the request.
- //
-
- irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
- PortDeviceObject,
- NULL,
- 0,
- PortCapabilities,
- sizeof(PVOID),
- FALSE,
- &event,
- &ioStatus);
-
- if (irp == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- //
- // Pass request to port driver and wait for request to complete.
- //
-
- status = IoCallDriver(PortDeviceObject, irp);
-
- if (status == STATUS_PENDING) {
- KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
- return(ioStatus.Status);
- }
-
- return status;
-
-} // end ScsiClassGetCapabilities()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassGetInquiryData(
- IN PDEVICE_OBJECT PortDeviceObject,
- OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo
- )
-
-/*++
-
-Routine Description:
-
- This routine sends a request to a port driver to return
- configuration information. Space for the information is
- allocated by this routine. The caller is responsible for
- freeing the configuration information. This routine is
- synchronous.
-
-Arguments:
-
- PortDeviceObject - Port driver device object representing the HBA.
-
- ConfigInfo - Returns a pointer to the configuration information.
-
-Return Value:
-
- Nt status indicating the results of the operation.
-
-Notes:
-
- This routine should be called only at initialization time.
-
---*/
-
-{
- PIRP irp;
- IO_STATUS_BLOCK ioStatus;
- KEVENT event;
- NTSTATUS status;
- PSCSI_ADAPTER_BUS_INFO buffer;
-
- PAGED_CODE();
-
- buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE);
- *ConfigInfo = buffer;
-
- if (buffer == NULL) {
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- //
- // Create notification event object to be used to signal the inquiry
- // request completion.
- //
-
- KeInitializeEvent(&event, NotificationEvent, FALSE);
-
- //
- // Build the synchronous request to be sent to the port driver
- // to perform the inquiries.
- //
-
- irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
- PortDeviceObject,
- NULL,
- 0,
- buffer,
- INQUIRY_DATA_SIZE,
- FALSE,
- &event,
- &ioStatus);
-
- if (irp == NULL) {
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- //
- // Pass request to port driver and wait for request to complete.
- //
-
- status = IoCallDriver(PortDeviceObject, irp);
-
- if (status == STATUS_PENDING) {
- KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
- status = ioStatus.Status;
- }
-
- if (!NT_SUCCESS(status)) {
-
- //
- // Free the buffer on an error.
- //
-
- ExFreePool(buffer);
- *ConfigInfo = NULL;
-
- }
-
- return status;
-
-} // end ScsiClassGetInquiryData()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassReadDriveCapacity(
- IN PDEVICE_OBJECT DeviceObject
- )
-
-/*++
-
-Routine Description:
-
- This routine sends a READ CAPACITY to the requested device, updates
- the geometry information in the device object and returns
- when it is complete. This routine is synchronous.
-
-Arguments:
-
- DeviceObject - Supplies a pointer to the device object that represents
- the device whose capacity is to be read.
-
-Return Value:
-
- Status is returned.
-
---*/
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- ULONG retries = 1;
- ULONG lastSector;
- PCDB cdb;
- PREAD_CAPACITY_DATA readCapacityBuffer;
- SCSI_REQUEST_BLOCK srb;
- NTSTATUS status;
-
- //
- // Allocate read capacity buffer from nonpaged pool.
- //
-
- readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
- sizeof(READ_CAPACITY_DATA));
-
- if (!readCapacityBuffer) {
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
-
- //
- // Build the read capacity CDB.
- //
-
- srb.CdbLength = 10;
- cdb = (PCDB)srb.Cdb;
-
- //
- // Set timeout value from device extension.
- //
-
- srb.TimeOutValue = deviceExtension->TimeOutValue;
-
- cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
-
-Retry:
-
- status = ScsiClassSendSrbSynchronous(DeviceObject,
- &srb,
- readCapacityBuffer,
- sizeof(READ_CAPACITY_DATA),
- FALSE);
-
- if (NT_SUCCESS(status)) {
-
- //
- // Copy sector size from read capacity buffer to device extension
- // in reverse byte order.
- //
-
- ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
- ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3;
-
- ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
- ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2;
-
- ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte2 =
- ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte1;
-
- ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte3 =
- ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte0;
-
- //
- // Copy last sector in reverse byte order.
- //
-
- ((PFOUR_BYTE)&lastSector)->Byte0 =
- ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3;
-
- ((PFOUR_BYTE)&lastSector)->Byte1 =
- ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2;
-
- ((PFOUR_BYTE)&lastSector)->Byte2 =
- ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1;
-
- ((PFOUR_BYTE)&lastSector)->Byte3 =
- ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0;
-
- //
- // Calculate sector to byte shift.
- //
-
- WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
-
- DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
- deviceExtension->DiskGeometry->BytesPerSector));
-
- DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
- lastSector + 1));
-
- //
- // Calculate media capacity in bytes.
- //
-
- deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
-
- //
- // Calculate number of cylinders.
- //
-
- deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
-
- deviceExtension->PartitionLength.QuadPart =
- (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
-
- if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
-
- //
- // This device supports removable media.
- //
-
- deviceExtension->DiskGeometry->MediaType = RemovableMedia;
-
- } else {
-
- //
- // Assume media type is fixed disk.
- //
-
- deviceExtension->DiskGeometry->MediaType = FixedMedia;
- }
-
- //
- // Assume sectors per track are 32;
- //
-
- deviceExtension->DiskGeometry->SectorsPerTrack = 32;
-
- //
- // Assume tracks per cylinder (number of heads) is 64.
- //
-
- deviceExtension->DiskGeometry->TracksPerCylinder = 64;
- }
-
- if (status == STATUS_VERIFY_REQUIRED) {
-
- //
- // Routine ScsiClassSendSrbSynchronous does not retry
- // requests returned with this status.
- // Read Capacities should be retried
- // anyway.
- //
-
- if (retries--) {
-
- //
- // Retry request.
- //
-
- goto Retry;
- }
- }
-
- if (!NT_SUCCESS(status)) {
-
- //
- // If the read capacity fails, set the geometry to reasonable parameter
- // so things don't fail at unexpected places. Zero the geometry
- // except for the bytes per sector and sector shift.
- //
-
- RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
- deviceExtension->DiskGeometry->BytesPerSector = 512;
- deviceExtension->SectorShift = 9;
- deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
-
- if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
-
- //
- // This device supports removable media.
- //
-
- deviceExtension->DiskGeometry->MediaType = RemovableMedia;
-
- } else {
-
- //
- // Assume media type is fixed disk.
- //
-
- deviceExtension->DiskGeometry->MediaType = FixedMedia;
- }
- }
-
- //
- // Deallocate read capacity buffer.
- //
-
- ExFreePool(readCapacityBuffer);
-
- return status;
-
-} // end ScsiClassReadDriveCapacity()
-
-\f
-VOID
-STDCALL
-ScsiClassReleaseQueue(
- IN PDEVICE_OBJECT DeviceObject
- )
-
-/*++
-
-Routine Description:
-
- This routine issues an internal device control command
- to the port driver to release a frozen queue. The call
- is issued asynchronously as ScsiClassReleaseQueue will be invoked
- from the IO completion DPC (and will have no context to
- wait for a synchronous call to complete).
-
-Arguments:
-
- DeviceObject - The device object for the logical unit with
- the frozen queue.
-
-Return Value:
-
- None.
-
---*/
-{
- PIO_STACK_LOCATION irpStack;
- PIRP irp;
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PCOMPLETION_CONTEXT context;
- PSCSI_REQUEST_BLOCK srb;
- KIRQL currentIrql;
-
- //
- // Allocate context from nonpaged pool.
- //
-
- context = ExAllocatePool(NonPagedPoolMustSucceed,
- sizeof(COMPLETION_CONTEXT));
-
- //
- // Save the device object in the context for use by the completion
- // routine.
- //
-
- context->DeviceObject = DeviceObject;
- srb = &context->Srb;
-
- //
- // Zero out srb.
- //
-
- RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
-
- //
- // Write length to SRB.
- //
-
- srb->Length = SCSI_REQUEST_BLOCK_SIZE;
-
- //
- // Set up SCSI bus address.
- //
-
- srb->PathId = deviceExtension->PathId;
- srb->TargetId = deviceExtension->TargetId;
- srb->Lun = deviceExtension->Lun;
-
- //
- // If this device is removable then flush the queue. This will also
- // release it.
- //
-
- if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
-
- srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
-
- } else {
-
- srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
-
- }
-
- //
- // Build the asynchronous request to be sent to the port driver.
- //
-
- irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-
- if(irp == NULL) {
-
- //
- // We have no better way of dealing with this at the moment
- //
-
- KeBugCheck((ULONG)0x0000002DL);
-
- }
-
- IoSetCompletionRoutine(irp,
- (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
- context,
- TRUE,
- TRUE,
- TRUE);
-
- irpStack = IoGetNextIrpStackLocation(irp);
-
- irpStack->MajorFunction = IRP_MJ_SCSI;
-
- srb->OriginalRequest = irp;
-
- //
- // Store the SRB address in next stack for port driver.
- //
-
- irpStack->Parameters.Scsi.Srb = srb;
-
- //
- // Since this routine can cause outstanding requests to be completed, and
- // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
- // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
- // issuing the request
- //
-
- currentIrql = KeGetCurrentIrql();
-
- if(currentIrql < DISPATCH_LEVEL) {
- KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
- IoCallDriver(deviceExtension->PortDeviceObject, irp);
- KeLowerIrql(currentIrql);
- } else {
- IoCallDriver(deviceExtension->PortDeviceObject, irp);
- }
-
- return;
-
-} // end ScsiClassReleaseQueue()
-
-\f
-VOID
-STDCALL
-StartUnit(
- IN PDEVICE_OBJECT DeviceObject
- )
-
-/*++
-
-Routine Description:
-
- Send command to SCSI unit to start or power up.
- Because this command is issued asynchronounsly, that is, without
- waiting on it to complete, the IMMEDIATE flag is not set. This
- means that the CDB will not return until the drive has powered up.
- This should keep subsequent requests from being submitted to the
- device before it has completely spun up.
- This routine is called from the InterpretSense routine, when a
- request sense returns data indicating that a drive must be
- powered up.
-
-Arguments:
-
- DeviceObject - The device object for the logical unit with
- the frozen queue.
-
-Return Value:
-
- None.
-
---*/
-{
- PIO_STACK_LOCATION irpStack;
- PIRP irp;
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PSCSI_REQUEST_BLOCK srb;
- PCOMPLETION_CONTEXT context;
- PCDB cdb;
-
- //
- // Allocate Srb from nonpaged pool.
- //
-
- context = ExAllocatePool(NonPagedPoolMustSucceed,
- sizeof(COMPLETION_CONTEXT));
-
- //
- // Save the device object in the context for use by the completion
- // routine.
- //
-
- context->DeviceObject = DeviceObject;
- srb = &context->Srb;
-
- //
- // Zero out srb.
- //
-
- RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
-
- //
- // Write length to SRB.
- //
-
- srb->Length = SCSI_REQUEST_BLOCK_SIZE;
-
- //
- // Set up SCSI bus address.
- //
-
- srb->PathId = deviceExtension->PathId;
- srb->TargetId = deviceExtension->TargetId;
- srb->Lun = deviceExtension->Lun;
-
- srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
-
- //
- // Set timeout value large enough for drive to spin up.
- //
-
- srb->TimeOutValue = START_UNIT_TIMEOUT;
-
- //
- // Set the transfer length.
- //
-
- srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
-
- //
- // Build the start unit CDB.
- //
-
- srb->CdbLength = 6;
- cdb = (PCDB)srb->Cdb;
-
- cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
- cdb->START_STOP.Start = 1;
- cdb->START_STOP.LogicalUnitNumber = srb->Lun;
-
- //
- // Build the asynchronous request to be sent to the port driver.
- // Since this routine is called from a DPC the IRP should always be
- // available.
- //
-
- irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- IoSetCompletionRoutine(irp,
- (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
- context,
- TRUE,
- TRUE,
- TRUE);
-
- irpStack = IoGetNextIrpStackLocation(irp);
- irpStack->MajorFunction = IRP_MJ_SCSI;
- srb->OriginalRequest = irp;
-
- //
- // Store the SRB address in next stack for port driver.
- //
-
- irpStack->Parameters.Scsi.Srb = srb;
-
- //
- // Call the port driver with the IRP.
- //
-
- IoCallDriver(deviceExtension->PortDeviceObject, irp);
-
- return;
-
-} // end StartUnit()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassAsynchronousCompletion(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PVOID Context
- )
-/*++
-
-Routine Description:
-
- This routine is called when an asynchronous I/O request
- which was issused by the class driver completes. Examples of such requests
- are release queue or START UNIT. This routine releases the queue if
- necessary. It then frees the context and the IRP.
-
-Arguments:
-
- DeviceObject - The device object for the logical unit; however since this
- is the top stack location the value is NULL.
-
- Irp - Supplies a pointer to the Irp to be processed.
-
- Context - Supplies the context to be used to process this request.
-
-Return Value:
-
- None.
-
---*/
-
-{
- PCOMPLETION_CONTEXT context = Context;
- PSCSI_REQUEST_BLOCK srb;
-
- srb = &context->Srb;
-
- //
- // If this is an execute srb, then check the return status and make sure.
- // the queue is not frozen.
- //
-
- if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
-
- //
- // Check for a frozen queue.
- //
-
- if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
-
- //
- // Unfreeze the queue getting the device object from the context.
- //
-
- ScsiClassReleaseQueue(context->DeviceObject);
- }
- }
-
- //
- // Free the context and the Irp.
- //
-
- if (Irp->MdlAddress != NULL) {
- MmUnlockPages(Irp->MdlAddress);
- IoFreeMdl(Irp->MdlAddress);
-
- Irp->MdlAddress = NULL;
- }
-
- ExFreePool(context);
- IoFreeIrp(Irp);
-
- //
- // Indicate the I/O system should stop processing the Irp completion.
- //
-
- return STATUS_MORE_PROCESSING_REQUIRED;
-
-} // ScsiClassAsynchronousCompletion()
-
-\f
-VOID
-STDCALL
-ScsiClassSplitRequest(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN ULONG MaximumBytes
- )
-
-/*++
-
-Routine Description:
-
- Break request into smaller requests. Each new request will be the
- maximum transfer size that the port driver can handle or if it
- is the final request, it may be the residual size.
-
- The number of IRPs required to process this request is written in the
- current stack of the original IRP. Then as each new IRP completes
- the count in the original IRP is decremented. When the count goes to
- zero, the original IRP is completed.
-
-Arguments:
-
- DeviceObject - Pointer to the class device object to be addressed.
-
- Irp - Pointer to Irp the orginal request.
-
-Return Value:
-
- None.
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
- PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
- ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
- LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
- PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
- ULONG dataLength = MaximumBytes;
- ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
- ULONG i;
- PSCSI_REQUEST_BLOCK srb;
-
- DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount));
- DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp));
-
- //
- // If all partial transfers complete successfully then the status and
- // bytes transferred are already set up. Failing a partial-transfer IRP
- // will set status to error and bytes transferred to 0 during
- // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
- // asynchronous partial transfers. This is an optimization for the
- // successful case.
- //
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = transferByteCount;
-
- //
- // Save number of IRPs to complete count on current stack
- // of original IRP.
- //
-
- nextIrpStack->Parameters.Others.Argument1 = (PVOID) irpCount;
-
- for (i = 0; i < irpCount; i++) {
-
- PIRP newIrp;
- PIO_STACK_LOCATION newIrpStack;
-
- //
- // Allocate new IRP.
- //
-
- newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-
- if (newIrp == NULL) {
-
- DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
-
- //
- // If an Irp can't be allocated then the orginal request cannot
- // be executed. If this is the first request then just fail the
- // orginal request; otherwise just return. When the pending
- // requests complete, they will complete the original request.
- // In either case set the IRP status to failure.
- //
-
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- Irp->IoStatus.Information = 0;
-
- if (i == 0) {
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- }
-
- return;
- }
-
- DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp));
-
- //
- // Write MDL address to new IRP. In the port driver the SRB data
- // buffer field is used as an offset into the MDL, so the same MDL
- // can be used for each partial transfer. This saves having to build
- // a new MDL for each partial transfer.
- //
-
- newIrp->MdlAddress = Irp->MdlAddress;
-
- //
- // At this point there is no current stack. IoSetNextIrpStackLocation
- // will make the first stack location the current stack so that the
- // SRB address can be written there.
- //
-
- IoSetNextIrpStackLocation(newIrp);
- newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
-
- newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
- newIrpStack->Parameters.Read.Length = dataLength;
- newIrpStack->Parameters.Read.ByteOffset = startingOffset;
- newIrpStack->DeviceObject = DeviceObject;
-
- //
- // Build SRB and CDB.
- //
-
- ScsiClassBuildRequest(DeviceObject, newIrp);
-
- //
- // Adjust SRB for this partial transfer.
- //
-
- newIrpStack = IoGetNextIrpStackLocation(newIrp);
-
- srb = newIrpStack->Parameters.Others.Argument1;
- srb->DataBuffer = dataBuffer;
-
- //
- // Write original IRP address to new IRP.
- //
-
- newIrp->AssociatedIrp.MasterIrp = Irp;
-
- //
- // Set the completion routine to ScsiClassIoCompleteAssociated.
- //
-
- IoSetCompletionRoutine(newIrp,
- ScsiClassIoCompleteAssociated,
- srb,
- TRUE,
- TRUE,
- TRUE);
-
- //
- // Call port driver with new request.
- //
-
- IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
-
- //
- // Set up for next request.
- //
-
- dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
-
- transferByteCount -= MaximumBytes;
-
- if (transferByteCount > MaximumBytes) {
-
- dataLength = MaximumBytes;
-
- } else {
-
- dataLength = transferByteCount;
- }
-
- //
- // Adjust disk byte offset.
- //
-
- startingOffset.QuadPart = startingOffset.QuadPart + MaximumBytes;
- }
-
- return;
-
-} // end ScsiClassSplitRequest()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassIoComplete(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
-
-/*++
-
-Routine Description:
-
- This routine executes when the port driver has completed a request.
- It looks at the SRB status in the completing SRB and if not success
- it checks for valid request sense buffer information. If valid, the
- info is used to update status with more precise message of type of
- error. This routine deallocates the SRB.
-
-Arguments:
-
- DeviceObject - Supplies the device object which represents the logical
- unit.
-
- Irp - Supplies the Irp which has completed.
-
- Context - Supplies a pointer to the SRB.
-
-Return Value:
-
- NT status
-
---*/
-
-{
- PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
- PSCSI_REQUEST_BLOCK srb = Context;
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- NTSTATUS status;
- BOOLEAN retry;
-
- //
- // Check SRB status for success of completing request.
- //
-
- if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
-
- DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
-
- //
- // Release the queue if it is frozen.
- //
-
- if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
- ScsiClassReleaseQueue(DeviceObject);
- }
-
- retry = ScsiClassInterpretSenseInfo(
- DeviceObject,
- srb,
- irpStack->MajorFunction,
- irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
- MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4),
- &status);
-
- //
- // If the status is verified required and the this request
- // should bypass verify required then retry the request.
- //
-
- if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
- status == STATUS_VERIFY_REQUIRED) {
-
- status = STATUS_IO_DEVICE_ERROR;
- retry = TRUE;
- }
-
- if (retry && (irpStack->Parameters.Others.Argument4 = (ULONG)irpStack->Parameters.Others.Argument4-1)) {
-
- //
- // Retry request.
- //
-
- DebugPrint((1, "Retry request %lx\n", Irp));
- RetryRequest(DeviceObject, Irp, srb, FALSE);
- return STATUS_MORE_PROCESSING_REQUIRED;
- }
- } else {
-
- //
- // Set status for successful request.
- //
-
- status = STATUS_SUCCESS;
-
- } // end if (SRB_STATUS(srb->SrbStatus) ...
-
- //
- // Return SRB to list.
- //
-
- ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
- srb);
-
- //
- // Set status in completing IRP.
- //
-
- Irp->IoStatus.Status = status;
- if ((NT_SUCCESS(status)) && (Irp->Flags & IRP_PAGING_IO)) {
- ASSERT(Irp->IoStatus.Information);
- }
-
- //
- // Set the hard error if necessary.
- //
-
- if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
-
- //
- // Store DeviceObject for filesystem, and clear
- // in IoStatus.Information field.
- //
-
- IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
- Irp->IoStatus.Information = 0;
- }
-
- //
- // If pending has be returned for this irp then mark the current stack as
- // pending.
- //
-
- if (Irp->PendingReturned) {
- IoMarkIrpPending(Irp);
- }
-
- if (deviceExtension->ClassStartIo) {
- if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
- IoStartNextPacket(DeviceObject, FALSE);
- }
- }
-
- return status;
-
-} // end ScsiClassIoComplete()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassIoCompleteAssociated(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
-
-/*++
-
-Routine Description:
-
- This routine executes when the port driver has completed a request.
- It looks at the SRB status in the completing SRB and if not success
- it checks for valid request sense buffer information. If valid, the
- info is used to update status with more precise message of type of
- error. This routine deallocates the SRB. This routine is used for
- requests which were build by split request. After it has processed
- the request it decrements the Irp count in the master Irp. If the
- count goes to zero then the master Irp is completed.
-
-Arguments:
-
- DeviceObject - Supplies the device object which represents the logical
- unit.
-
- Irp - Supplies the Irp which has completed.
-
- Context - Supplies a pointer to the SRB.
-
-Return Value:
-
- NT status
-
---*/
-
-{
- PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
- PSCSI_REQUEST_BLOCK srb = Context;
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
- LONG irpCount;
- NTSTATUS status;
- BOOLEAN retry;
-
- //
- // Check SRB status for success of completing request.
- //
-
- if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
-
- DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
-
- //
- // Release the queue if it is frozen.
- //
-
- if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
- ScsiClassReleaseQueue(DeviceObject);
- }
-
- retry = ScsiClassInterpretSenseInfo(
- DeviceObject,
- srb,
- irpStack->MajorFunction,
- irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
- MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4),
- &status);
-
- //
- // If the status is verified required and the this request
- // should bypass verify required then retry the request.
- //
-
- if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
- status == STATUS_VERIFY_REQUIRED) {
-
- status = STATUS_IO_DEVICE_ERROR;
- retry = TRUE;
- }
-
- if (retry && (irpStack->Parameters.Others.Argument4 = (ULONG)irpStack->Parameters.Others.Argument4-1)) {
-
- //
- // Retry request. If the class driver has supplied a StartIo,
- // call it directly for retries.
- //
-
- DebugPrint((1, "Retry request %lx\n", Irp));
-
- /*
- if (!deviceExtension->ClassStartIo) {
- RetryRequest(DeviceObject, Irp, srb, TRUE);
- } else {
- deviceExtension->ClassStartIo(DeviceObject, Irp);
- }
- */
-
- RetryRequest(DeviceObject, Irp, srb, TRUE);
-
- return STATUS_MORE_PROCESSING_REQUIRED;
- }
-
-
-
- } else {
-
- //
- // Set status for successful request.
- //
-
- status = STATUS_SUCCESS;
-
- } // end if (SRB_STATUS(srb->SrbStatus) ...
-
- //
- // Return SRB to list.
- //
-
- ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
- srb);
-
- //
- // Set status in completing IRP.
- //
-
- Irp->IoStatus.Status = status;
-
- DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
-
- //
- // Get next stack location. This original request is unused
- // except to keep track of the completing partial IRPs so the
- // stack location is valid.
- //
-
- irpStack = IoGetNextIrpStackLocation(originalIrp);
-
- //
- // Update status only if error so that if any partial transfer
- // completes with error, then the original IRP will return with
- // error. If any of the asynchronous partial transfer IRPs fail,
- // with an error then the original IRP will return 0 bytes transfered.
- // This is an optimization for successful transfers.
- //
-
- if (!NT_SUCCESS(status)) {
-
- originalIrp->IoStatus.Status = status;
- originalIrp->IoStatus.Information = 0;
-
- //
- // Set the hard error if necessary.
- //
-
- if (IoIsErrorUserInduced(status)) {
-
- //
- // Store DeviceObject for filesystem.
- //
-
- IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
- }
- }
-
- //
- // Decrement and get the count of remaining IRPs.
- //
-
- irpCount = InterlockedDecrement((PLONG)&irpStack->Parameters.Others.Argument1);
-
- DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
- irpCount));
-
- //
- // Old bug could cause irp count to negative
- //
-
- ASSERT(irpCount >= 0);
-
- if (irpCount == 0) {
-
- //
- // All partial IRPs have completed.
- //
-
- DebugPrint((2,
- "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
- originalIrp));
-
- IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
-
- //
- // If the class driver has supplied a startio, start the
- // next request.
- //
-
- if (deviceExtension->ClassStartIo) {
- IoStartNextPacket(DeviceObject, FALSE);
- }
- }
-
- //
- // Deallocate IRP and indicate the I/O system should not attempt any more
- // processing.
- //
-
- IoFreeIrp(Irp);
- return STATUS_MORE_PROCESSING_REQUIRED;
-
-} // end ScsiClassIoCompleteAssociated()
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassSendSrbSynchronous(
- PDEVICE_OBJECT DeviceObject,
- PSCSI_REQUEST_BLOCK Srb,
- PVOID BufferAddress,
- ULONG BufferLength,
- BOOLEAN WriteToDevice
- )
-
-/*++
-
-Routine Description:
-
- This routine is called by SCSI device controls to complete an
- SRB and send it to the port driver synchronously (ie wait for
- completion). The CDB is already completed along with the SRB CDB
- size and request timeout value.
-
-Arguments:
-
- DeviceObject - Supplies the device object which represents the logical
- unit.
-
- Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
-
- BufferAddress - Supplies the address of the buffer.
-
- BufferLength - Supplies the length in bytes of the buffer.
-
- WriteToDevice - Indicates the data should be transfer to the device.
-
-Return Value:
-
- Nt status indicating the final results of the operation.
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- IO_STATUS_BLOCK ioStatus;
- ULONG controlType;
- PIRP irp;
- PIO_STACK_LOCATION irpStack;
- KEVENT event;
- PUCHAR senseInfoBuffer;
- ULONG retryCount = MAXIMUM_RETRIES;
- NTSTATUS status;
- BOOLEAN retry;
-
- PAGED_CODE();
-
- //
- // Write length to SRB.
- //
-
- Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
-
- //
- // Set SCSI bus address.
- //
-
- Srb->PathId = deviceExtension->PathId;
- Srb->TargetId = deviceExtension->TargetId;
- Srb->Lun = deviceExtension->Lun;
- Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
-
- //
- // NOTICE: The SCSI-II specification indicates that this field should be
- // zero; however, some target controllers ignore the logical unit number
- // in the INDENTIFY message and only look at the logical unit number field
- // in the CDB.
- //
-
- Srb->Cdb[1] |= deviceExtension->Lun << 5;
-
- //
- // Enable auto request sense.
- //
-
- Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
-
- //
- // Sense buffer is in aligned nonpaged pool.
- //
-
- senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
-
- if (senseInfoBuffer == NULL) {
-
- DebugPrint((1,
- "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- Srb->SenseInfoBuffer = senseInfoBuffer;
- Srb->DataBuffer = BufferAddress;
-
- //
- // Start retries here.
- //
-
-retry:
-
- //
- // Set the event object to the unsignaled state.
- // It will be used to signal request completion.
- //
-
- KeInitializeEvent(&event, NotificationEvent, FALSE);
-
- //
- // Set controlType and Srb direction flags.
- //
-
- if (BufferAddress != NULL) {
-
- if (WriteToDevice) {
-
- controlType = IOCTL_SCSI_EXECUTE_OUT;
- Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
-
- } else {
-
- controlType = IOCTL_SCSI_EXECUTE_IN;
- Srb->SrbFlags = SRB_FLAGS_DATA_IN;
-
- }
-
- } else {
-
- BufferLength = 0;
- controlType = IOCTL_SCSI_EXECUTE_NONE;
- Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
- }
-
- //
- // Build device I/O control request with data transfer.
- //
-
- irp = IoBuildDeviceIoControlRequest(controlType,
- deviceExtension->PortDeviceObject,
- NULL,
- 0,
- BufferAddress,
- BufferLength,
- TRUE,
- &event,
- &ioStatus);
-
- if (irp == NULL) {
- ExFreePool(senseInfoBuffer);
- DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- //
- // Disable synchronous transfer for these requests.
- //
-
- Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
-
- //
- // Set the transfer length.
- //
-
- Srb->DataTransferLength = BufferLength;
-
- //
- // Zero out status.
- //
-
- Srb->ScsiStatus = Srb->SrbStatus = 0;
- Srb->NextSrb = 0;
-
- //
- // Get next stack location.
- //
-
- irpStack = IoGetNextIrpStackLocation(irp);
-
- //
- // Set up SRB for execute scsi request. Save SRB address in next stack
- // for the port driver.
- //
-
- irpStack->Parameters.Scsi.Srb = Srb;
-
- //
- // Set up IRP Address.
- //
-
- Srb->OriginalRequest = irp;
-
- //
- // Call the port driver with the request and wait for it to complete.
- //
-
- status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
-
- if (status == STATUS_PENDING) {
- KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
- }
-
- //
- // Check that request completed without error.
- //
-
- if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
-
- //
- // Release the queue if it is frozen.
- //
-
- if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
- ScsiClassReleaseQueue(DeviceObject);
- }
-
- //
- // Update status and determine if request should be retried.
- //
-
- retry = ScsiClassInterpretSenseInfo(DeviceObject,
- Srb,
- IRP_MJ_SCSI,
- 0,
- MAXIMUM_RETRIES - retryCount,
- &status);
-
- if (retry) {
-
- if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
- ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
- SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
-
- LARGE_INTEGER delay;
-
- //
- // Delay for 2 seconds.
- //
-
- delay.QuadPart = (LONGLONG)( - 10 * 1000 * 1000 * 2 );
-
- //
- // Stall for a while to let the controller spinup.
- //
-
- KeDelayExecutionThread(KernelMode,
- FALSE,
- &delay);
-
- }
-
- //
- // If retries are not exhausted then retry this operation.
- //
-
- if (retryCount--) {
- goto retry;
- }
- }
-
- } else {
-
- status = STATUS_SUCCESS;
- }
-
- ExFreePool(senseInfoBuffer);
- return status;
-
-} // end ScsiClassSendSrbSynchronous()
-
-\f
-BOOLEAN
-STDCALL
-ScsiClassInterpretSenseInfo(
- IN PDEVICE_OBJECT DeviceObject,
- IN PSCSI_REQUEST_BLOCK Srb,
- IN UCHAR MajorFunctionCode,
- IN ULONG IoDeviceCode,
- IN ULONG RetryCount,
- OUT NTSTATUS *Status
- )
-
-/*++
-
-Routine Description:
-
- This routine interprets the data returned from the SCSI
- request sense. It determines the status to return in the
- IRP and whether this request can be retried.
-
-Arguments:
-
- DeviceObject - Supplies the device object associated with this request.
-
- Srb - Supplies the scsi request block which failed.
-
- MajorFunctionCode - Supplies the function code to be used for logging.
-
- IoDeviceCode - Supplies the device code to be used for logging.
-
- Status - Returns the status for the request.
-
-Return Value:
-
- BOOLEAN TRUE: Drivers should retry this request.
- FALSE: Drivers should not retry this request.
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
- PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
- BOOLEAN retry = TRUE;
- BOOLEAN logError = FALSE;
- ULONG badSector = 0;
- ULONG uniqueId;
- NTSTATUS logStatus;
- ULONG readSector;
- ULONG index;
- PIO_ERROR_LOG_PACKET errorLogEntry;
-#if DBG
- ULONG i;
-#endif
-
-
- //
- // Check that request sense buffer is valid.
- //
-
-#if DBG
- DebugPrint((3, "Opcode %x\nParameters: ",Srb->Cdb[0]));
- for (i = 1; i < 12; i++) {
- DebugPrint((3,"%x ",Srb->Cdb[i]));
- }
- DebugPrint((3,"\n"));
-#endif
-
- if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&
- Srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
- senseBuffer->ErrorCode));
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
- senseBuffer->SenseKey));
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
- senseBuffer->AdditionalSenseCode));
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
- senseBuffer->AdditionalSenseCodeQualifier));
-
- //
- // Zero the additional sense code and additional sense code qualifier
- // if they were not returned by the device.
- //
-
- readSector = senseBuffer->AdditionalSenseLength +
- FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength);
-
- if (readSector > Srb->SenseInfoBufferLength) {
- readSector = Srb->SenseInfoBufferLength;
- }
-
- if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCode)) {
- senseBuffer->AdditionalSenseCode = 0;
- }
-
- if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCodeQualifier)) {
- senseBuffer->AdditionalSenseCodeQualifier = 0;
- }
-
- switch (senseBuffer->SenseKey & 0xf) {
-
- case SCSI_SENSE_NOT_READY:
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
- *Status = STATUS_DEVICE_NOT_READY;
-
- switch (senseBuffer->AdditionalSenseCode) {
-
- case SCSI_ADSENSE_LUN_NOT_READY:
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
-
- switch (senseBuffer->AdditionalSenseCodeQualifier) {
-
- case SCSI_SENSEQ_BECOMING_READY:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo:"
- " In process of becoming ready\n"));
- break;
-
- case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo:"
- " Manual intervention required\n"));
- *Status = STATUS_NO_MEDIA_IN_DEVICE;
- retry = FALSE;
- break;
-
- case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
- retry = FALSE;
- break;
-
- case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
-
- default:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo:"
- " Initializing command required\n"));
-
- //
- // This sense code/additional sense code
- // combination may indicate that the device
- // needs to be started. Send an start unit if this
- // is a disk device.
- //
-
- if (deviceExtension->DeviceFlags & DEV_SAFE_START_UNIT) {
- StartUnit(DeviceObject);
- }
-
- break;
-
- } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
-
- break;
-
- case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
-
- DebugPrint((1,
- "ScsiClassInterpretSenseInfo:"
- " No Media in device.\n"));
- *Status = STATUS_NO_MEDIA_IN_DEVICE;
- retry = FALSE;
-
- //
- // signal autorun that there isn't any media in the device
- //
-
- if((deviceExtension->MediaChangeEvent != NULL)&&
- (!deviceExtension->MediaChangeNoMedia)) {
- KeSetEvent(deviceExtension->MediaChangeEvent,
- (KPRIORITY) 0,
- FALSE);
- DebugPrint((0, "ScsiClassInterpretSenseInfo:"
- "Detected No Media In Device "
- "[irp = 0x%lx]\n", Srb->OriginalRequest));
- deviceExtension->MediaChangeNoMedia = TRUE;
- }
-
- break;
- } // end switch (senseBuffer->AdditionalSenseCode)
-
- break;
-
- case SCSI_SENSE_DATA_PROTECT:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
- *Status = STATUS_MEDIA_WRITE_PROTECTED;
- retry = FALSE;
- break;
-
- case SCSI_SENSE_MEDIUM_ERROR:
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
- *Status = STATUS_DEVICE_DATA_ERROR;
-
- retry = FALSE;
- logError = TRUE;
- uniqueId = 256;
- logStatus = 0;//IO_ERR_BAD_BLOCK;
- break;
-
- case SCSI_SENSE_HARDWARE_ERROR:
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
- *Status = STATUS_IO_DEVICE_ERROR;
-
- logError = TRUE;
- uniqueId = 257;
- logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
-
- break;
-
- case SCSI_SENSE_ILLEGAL_REQUEST:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
- *Status = STATUS_INVALID_DEVICE_REQUEST;
-
- switch (senseBuffer->AdditionalSenseCode) {
-
- case SCSI_ADSENSE_ILLEGAL_COMMAND:
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
- retry = FALSE;
- break;
-
- case SCSI_ADSENSE_ILLEGAL_BLOCK:
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
- *Status = STATUS_NONEXISTENT_SECTOR;
- retry = FALSE;
- break;
-
- case SCSI_ADSENSE_INVALID_LUN:
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
- *Status = STATUS_NO_SUCH_DEVICE;
- retry = FALSE;
- break;
-
- case SCSI_ADSENSE_MUSIC_AREA:
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
- retry = FALSE;
- break;
-
- case SCSI_ADSENSE_DATA_AREA:
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
- retry = FALSE;
- break;
-
- case SCSI_ADSENSE_VOLUME_OVERFLOW:
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
- retry = FALSE;
- break;
-
- case SCSI_ADSENSE_INVALID_CDB:
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
-
- //
- // Check if write cache enabled.
- //
-
- if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
-
- //
- // Assume FUA is not supported.
- //
-
- deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
- retry = TRUE;
-
- } else {
- retry = FALSE;
- }
-
- break;
-
- } // end switch (senseBuffer->AdditionalSenseCode)
-
- break;
-
- case SCSI_SENSE_UNIT_ATTENTION:
-
- switch (senseBuffer->AdditionalSenseCode) {
- case SCSI_ADSENSE_MEDIUM_CHANGED:
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
-
- if(deviceExtension->MediaChangeEvent != NULL) {
-
- KeSetEvent(deviceExtension->MediaChangeEvent,
- (KPRIORITY) 0,
- FALSE);
- DebugPrint((0, "ScsiClassInterpretSenseInfo:"
- "New Media Found - Setting MediaChanged event"
- " [irp = 0x%lx]\n", Srb->OriginalRequest));
- deviceExtension->MediaChangeNoMedia = FALSE;
-
- }
- break;
-
- case SCSI_ADSENSE_BUS_RESET:
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
- break;
-
- default:
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
- break;
-
- } // end switch (senseBuffer->AdditionalSenseCode)
-
- if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
- DeviceObject->Vpb->Flags & VPB_MOUNTED) {
-
- //
- // Set bit to indicate that media may have changed
- // and volume needs verification.
- //
-
- DeviceObject->Flags |= DO_VERIFY_VOLUME;
-
- *Status = STATUS_VERIFY_REQUIRED;
- retry = FALSE;
-
- } else {
-
- *Status = STATUS_IO_DEVICE_ERROR;
-
- }
-
- //
- // A media change may have occured so increment the change
- // count for the physical device
- //
-
- physicalExtension->MediaChangeCount++;
-
- DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
- "count for device %d is %d\n",
- physicalExtension->DeviceNumber,
- physicalExtension->MediaChangeCount));
-
- break;
-
- case SCSI_SENSE_ABORTED_COMMAND:
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
- *Status = STATUS_IO_DEVICE_ERROR;
- break;
-
- case SCSI_SENSE_RECOVERED_ERROR:
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
- *Status = STATUS_SUCCESS;
- retry = FALSE;
- logError = TRUE;
- uniqueId = 258;
-
- switch(senseBuffer->AdditionalSenseCode) {
- case SCSI_ADSENSE_SEEK_ERROR:
- case SCSI_ADSENSE_TRACK_ERROR:
- logStatus = 0;//IO_ERR_SEEK_ERROR;
- break;
-
- case SCSI_ADSENSE_REC_DATA_NOECC:
- case SCSI_ADSENSE_REC_DATA_ECC:
- logStatus = 0;//IO_RECOVERED_VIA_ECC;
- break;
-
- default:
- logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
- break;
-
- } // end switch(senseBuffer->AdditionalSenseCode)
-
- if (senseBuffer->IncorrectLength) {
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
- *Status = STATUS_INVALID_BLOCK_LENGTH ;
- }
-
- break;
-
- case SCSI_SENSE_NO_SENSE:
-
- //
- // Check other indicators.
- //
-
- if (senseBuffer->IncorrectLength) {
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
- *Status = STATUS_INVALID_BLOCK_LENGTH ;
- retry = FALSE;
-
- } else {
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
- *Status = STATUS_IO_DEVICE_ERROR;
- retry = TRUE;
- }
-
- break;
-
- default:
-
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
- *Status = STATUS_IO_DEVICE_ERROR;
- break;
-
- } // end switch (senseBuffer->SenseKey & 0xf)
-
- //
- // Try to determine the bad sector from the inquiry data.
- //
-
- if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
- ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
- ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
-
- for (index = 0; index < 4; index++) {
- badSector = (badSector << 8) | senseBuffer->Information[index];
- }
-
- readSector = 0;
- for (index = 0; index < 4; index++) {
- readSector = (readSector << 8) | Srb->Cdb[index+2];
- }
-
- index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
- ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
-
- //
- // Make sure the bad sector is within the read sectors.
- //
-
- if (!(badSector >= readSector && badSector < readSector + index)) {
- badSector = readSector;
- }
- }
-
- } else {
-
- //
- // Request sense buffer not valid. No sense information
- // to pinpoint the error. Return general request fail.
- //
-
- DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
- SRB_STATUS(Srb->SrbStatus)));
- retry = TRUE;
-
- switch (SRB_STATUS(Srb->SrbStatus)) {
- case SRB_STATUS_INVALID_LUN:
- case SRB_STATUS_INVALID_TARGET_ID:
- case SRB_STATUS_NO_DEVICE:
- case SRB_STATUS_NO_HBA:
- case SRB_STATUS_INVALID_PATH_ID:
- *Status = STATUS_NO_SUCH_DEVICE;
- retry = FALSE;
- break;
-
- case SRB_STATUS_COMMAND_TIMEOUT:
- case SRB_STATUS_ABORTED:
- case SRB_STATUS_TIMEOUT:
-
- //
- // Update the error count for the device.
- //
-
- deviceExtension->ErrorCount++;
- *Status = STATUS_IO_TIMEOUT;
- break;
-
- case SRB_STATUS_SELECTION_TIMEOUT:
- logError = TRUE;
- logStatus = 0;//IO_ERR_NOT_READY;
- uniqueId = 260;
- *Status = STATUS_DEVICE_NOT_CONNECTED;
- retry = FALSE;
- break;
-
- case SRB_STATUS_DATA_OVERRUN:
- *Status = STATUS_DATA_OVERRUN;
- retry = FALSE;
- break;
-
- case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
-
- //
- // Update the error count for the device.
- //
-
- deviceExtension->ErrorCount++;
- *Status = STATUS_IO_DEVICE_ERROR;
-
- //
- // If there was phase sequence error then limit the number of
- // retries.
- //
-
- if (RetryCount > 1 ) {
- retry = FALSE;
- }
-
- break;
-
- case SRB_STATUS_REQUEST_FLUSHED:
-
- //
- // If the status needs verification bit is set. Then set
- // the status to need verification and no retry; otherwise,
- // just retry the request.
- //
-
- if (DeviceObject->Flags & DO_VERIFY_VOLUME ) {
-
- *Status = STATUS_VERIFY_REQUIRED;
- retry = FALSE;
- } else {
- *Status = STATUS_IO_DEVICE_ERROR;
- }
-
- break;
-
- case SRB_STATUS_INVALID_REQUEST:
-
- //
- // An invalid request was attempted.
- //
-
- *Status = STATUS_INVALID_DEVICE_REQUEST;
- retry = FALSE;
- break;
-
- case SRB_STATUS_UNEXPECTED_BUS_FREE:
- case SRB_STATUS_PARITY_ERROR:
-
- //
- // Update the error count for the device.
- //
-
- deviceExtension->ErrorCount++;
-
- //
- // Fall through to below.
- //
-
- case SRB_STATUS_BUS_RESET:
- *Status = STATUS_IO_DEVICE_ERROR;
- break;
-
- case SRB_STATUS_ERROR:
-
- *Status = STATUS_IO_DEVICE_ERROR;
- if (Srb->ScsiStatus == 0) {
-
- //
- // This is some strange return code. Update the error
- // count for the device.
- //
-
- deviceExtension->ErrorCount++;
-
- } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
-
- *Status = STATUS_DEVICE_NOT_READY;
-
- } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
-
- *Status = STATUS_DEVICE_BUSY;
- retry = FALSE;
-
- }
-
- break;
-
- default:
- logError = TRUE;
- logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
- uniqueId = 259;
- *Status = STATUS_IO_DEVICE_ERROR;
- break;
-
- }
-
- //
- // If the error count has exceeded the error limit, then disable
- // any tagged queuing, multiple requests per lu queueing
- // and sychronous data transfers.
- //
-
- if (deviceExtension->ErrorCount == 4) {
-
- //
- // Clearing the no queue freeze flag prevents the port driver
- // from sending multiple requests per logical unit.
- //
-
- deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE |
- SRB_FLAGS_NO_QUEUE_FREEZE);
-
- deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
-
- } else if (deviceExtension->ErrorCount == 8) {
-
- //
- // If a second threshold is reached, disable disconnects.
- //
-
- deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
- DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
- }
- }
-
- //
- // If there is a class specific error handler call it.
- //
-
- if (deviceExtension->ClassError != NULL) {
-
- deviceExtension->ClassError(DeviceObject,
- Srb,
- Status,
- &retry);
- }
-
- //
- // Log an error if necessary.
- //
-
- if (logError) {
-
- errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
- DeviceObject,
- sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG));
-
- if (errorLogEntry == NULL) {
-
- //
- // Return if no packet could be allocated.
- //
-
- return retry;
-
- }
-
- if (retry && RetryCount < MAXIMUM_RETRIES) {
- errorLogEntry->FinalStatus = STATUS_SUCCESS;
- } else {
- errorLogEntry->FinalStatus = *Status;
- }
-
- //
- // Calculate the device offset if there is a geometry.
- //
-
- if (deviceExtension->DiskGeometry != NULL) {
-
- errorLogEntry->DeviceOffset.QuadPart = (LONGLONG) badSector;
- errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply(
- errorLogEntry->DeviceOffset,
- deviceExtension->DiskGeometry->BytesPerSector);
- }
-
- errorLogEntry->ErrorCode = logStatus;
- errorLogEntry->SequenceNumber = 0;
- errorLogEntry->MajorFunctionCode = MajorFunctionCode;
- errorLogEntry->IoControlCode = IoDeviceCode;
- errorLogEntry->RetryCount = (UCHAR) RetryCount;
- errorLogEntry->UniqueErrorValue = uniqueId;
- errorLogEntry->DumpDataSize = 6 * sizeof(ULONG);
- errorLogEntry->DumpData[0] = Srb->PathId;
- errorLogEntry->DumpData[1] = Srb->TargetId;
- errorLogEntry->DumpData[2] = Srb->Lun;
- errorLogEntry->DumpData[3] = 0;
- errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
-
- if (senseBuffer != NULL) {
- errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
- senseBuffer->AdditionalSenseCode << 8 |
- senseBuffer->AdditionalSenseCodeQualifier;
-
- }
-
- //
- // Write the error log packet.
- //
-
- IoWriteErrorLogEntry(errorLogEntry);
- }
-
- return retry;
-
-} // end ScsiClassInterpretSenseInfo()
-
-\f
-VOID
-STDCALL
-RetryRequest(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PSCSI_REQUEST_BLOCK Srb,
- BOOLEAN Associated
- )
-
-/*++
-
-Routine Description:
-
- This routine reinitalizes the necessary fields, and sends the request
- to the port driver.
-
-Arguments:
-
- DeviceObject - Supplies the device object associated with this request.
-
- Irp - Supplies the request to be retried.
-
- Srb - Supplies a Pointer to the SCSI request block to be retied.
-
- Assocaiated - Indicates this is an assocatied Irp created by split request.
-
-Return Value:
-
- None
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
- PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
- ULONG transferByteCount;
-
- //
- // Determine the transfer count of the request. If this is a read or a
- // write then the transfer count is in the Irp stack. Otherwise assume
- // the MDL contains the correct length. If there is no MDL then the
- // transfer length must be zero.
- //
-
- if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
- currentIrpStack->MajorFunction == IRP_MJ_WRITE) {
-
- transferByteCount = currentIrpStack->Parameters.Read.Length;
-
- } else if (Irp->MdlAddress != NULL) {
-
- //
- // Note this assumes that only read and write requests are spilt and
- // other request do not need to be. If the data buffer address in
- // the MDL and the SRB don't match then transfer length is most
- // likely incorrect.
- //
-
- ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
- transferByteCount = Irp->MdlAddress->ByteCount;
-
- } else {
-
- transferByteCount = 0;
- }
-
- //
- // Reset byte count of transfer in SRB Extension.
- //
-
- Srb->DataTransferLength = transferByteCount;
-
- //
- // Zero SRB statuses.
- //
-
- Srb->SrbStatus = Srb->ScsiStatus = 0;
-
- //
- // Set the no disconnect flag, disable synchronous data transfers and
- // disable tagged queuing. This fixes some errors.
- //
-
- Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT |
- SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
-
- Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
- Srb->QueueTag = SP_UNTAGGED;
-
- //
- // Set up major SCSI function.
- //
-
- nextIrpStack->MajorFunction = IRP_MJ_SCSI;
-
- //
- // Save SRB address in next stack for port driver.
- //
-
- nextIrpStack->Parameters.Scsi.Srb = Srb;
-
- //
- // Set up IoCompletion routine address.
- //
-
- if (Associated) {
-
- IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE);
-
- } else {
-
- IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
- }
-
- //
- // Pass the request to the port driver.
- //
-
- (PVOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp);
-
-} // end RetryRequest()
-\f
-VOID
-STDCALL
-ScsiClassBuildRequest(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
-
-/*++
-
-Routine Description:
-
- This routine allocates and builds an Srb for a read or write request.
- The block address and length are supplied by the Irp. The retry count
- is stored in the current stack for use by ScsiClassIoComplete which
- processes these requests when they complete. The Irp is ready to be
- passed to the port driver when this routine returns.
-
-Arguments:
-
- DeviceObject - Supplies the device object associated with this request.
-
- Irp - Supplies the request to be retried.
-
-Note:
-
- If the IRP is for a disk transfer, the byteoffset field
- will already have been adjusted to make it relative to
- the beginning of the disk.
-
-
-Return Value:
-
- None.
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
- PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
- LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
- PSCSI_REQUEST_BLOCK srb;
- PCDB cdb;
- ULONG logicalBlockAddress;
- USHORT transferBlocks;
-
- //
- // Calculate relative sector address.
- //
-
- logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift));
-
- //
- // Allocate an Srb.
- //
-
- srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
-
- srb->SrbFlags = 0;
-
- //
- // Write length to SRB.
- //
-
- srb->Length = SCSI_REQUEST_BLOCK_SIZE;
-
- //
- // Set up IRP Address.
- //
-
- srb->OriginalRequest = Irp;
-
- //
- // Set up target ID and logical unit number.
- //
-
- srb->PathId = deviceExtension->PathId;
- srb->TargetId = deviceExtension->TargetId;
- srb->Lun = deviceExtension->Lun;
- srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
- srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
-
- //
- // Save byte count of transfer in SRB Extension.
- //
-
- srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
-
- //
- // Initialize the queue actions field.
- //
-
- srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
-
- //
- // Queue sort key is Relative Block Address.
- //
-
- srb->QueueSortKey = logicalBlockAddress;
-
- //
- // Indicate auto request sense by specifying buffer and size.
- //
-
- srb->SenseInfoBuffer = deviceExtension->SenseData;
- srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
-
- //
- // Set timeout value of one unit per 64k bytes of data.
- //
-
- srb->TimeOutValue = ((srb->DataTransferLength + 0xFFFF) >> 16) *
- deviceExtension->TimeOutValue;
-
- //
- // Zero statuses.
- //
-
- srb->SrbStatus = srb->ScsiStatus = 0;
- srb->NextSrb = 0;
-
- //
- // Indicate that 10-byte CDB's will be used.
- //
-
- srb->CdbLength = 10;
-
- //
- // Fill in CDB fields.
- //
-
- cdb = (PCDB)srb->Cdb;
-
- //
- // Zero 12 bytes for Atapi Packets
- //
-
- RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
-
- cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
- transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift);
-
- //
- // Move little endian values into CDB in big endian format.
- //
-
- cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
- cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
- cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
- cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
-
- cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
- cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
-
- //
- // Set transfer direction flag and Cdb command.
- //
-
- if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
-
- DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
-
- srb->SrbFlags |= SRB_FLAGS_DATA_IN;
- cdb->CDB10.OperationCode = SCSIOP_READ;
-
- } else {
-
- DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
-
- srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
- cdb->CDB10.OperationCode = SCSIOP_WRITE;
- }
-
- //
- // If this is not a write-through request, then allow caching.
- //
-
- if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) {
-
- srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
-
- } else {
-
- //
- // If write caching is enable then force media access in the
- // cdb.
- //
-
- if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
- cdb->CDB10.ForceUnitAccess = TRUE;
- }
- }
-
- //
- // Or in the default flags from the device object.
- //
-
- srb->SrbFlags |= deviceExtension->SrbFlags;
-
- //
- // Set up major SCSI function.
- //
-
- nextIrpStack->MajorFunction = IRP_MJ_SCSI;
-
- //
- // Save SRB address in next stack for port driver.
- //
-
- nextIrpStack->Parameters.Scsi.Srb = srb;
-
- //
- // Save retry count in current IRP stack.
- //
-
- currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
-
- //
- // Set up IoCompletion routine address.
- //
-
- IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
-
- return;
-
-} // end ScsiClassBuildRequest()
-\f
-ULONG
-STDCALL
-ScsiClassModeSense(
- IN PDEVICE_OBJECT DeviceObject,
- IN PCHAR ModeSenseBuffer,
- IN ULONG Length,
- IN UCHAR PageMode
- )
-
-/*++
-
-Routine Description:
-
- This routine sends a mode sense command to a target ID and returns
- when it is complete.
-
-Arguments:
-
- DeviceObject - Supplies the device object associated with this request.
-
- ModeSenseBuffer - Supplies a buffer to store the sense data.
-
- Length - Supplies the length in bytes of the mode sense buffer.
-
- PageMode - Supplies the page or pages of mode sense data to be retrived.
-
-Return Value:
-
- Length of the transferred data is returned.
-
---*/
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PCDB cdb;
- SCSI_REQUEST_BLOCK srb;
- ULONG retries = 1;
- NTSTATUS status;
-
- RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
-
- //
- // Build the MODE SENSE CDB.
- //
-
- srb.CdbLength = 6;
- cdb = (PCDB)srb.Cdb;
-
- //
- // Set timeout value from device extension.
- //
-
- srb.TimeOutValue = deviceExtension->TimeOutValue;
-
- cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
- cdb->MODE_SENSE.PageCode = PageMode;
- cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
-
-Retry:
-
- status = ScsiClassSendSrbSynchronous(DeviceObject,
- &srb,
- ModeSenseBuffer,
- Length,
- FALSE);
-
-
- if (status == STATUS_VERIFY_REQUIRED) {
-
- //
- // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
- // this status. MODE SENSE commands should be retried anyway.
- //
-
- if (retries--) {
-
- //
- // Retry request.
- //
-
- goto Retry;
- }
-
- } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
- status = STATUS_SUCCESS;
- }
-
- if (NT_SUCCESS(status)) {
- return(srb.DataTransferLength);
- } else {
- return(0);
- }
-
-} // end ScsiClassModeSense()
-
-\f
-PVOID
-STDCALL
-ScsiClassFindModePage(
- IN PCHAR ModeSenseBuffer,
- IN ULONG Length,
- IN UCHAR PageMode,
- IN BOOLEAN Use6Byte
- )
-
-/*++
-
-Routine Description:
-
- This routine scans through the mode sense data and finds the requested
- mode sense page code.
-
-Arguments:
- ModeSenseBuffer - Supplies a pointer to the mode sense data.
-
- Length - Indicates the length of valid data.
-
- PageMode - Supplies the page mode to be searched for.
-
- Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
-
-Return Value:
-
- A pointer to the the requested mode page. If the mode page was not found
- then NULL is return.
-
---*/
-{
- PUCHAR limit;
- ULONG parameterHeaderLength;
-
- limit = ModeSenseBuffer + Length;
- parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
-
-
- //
- // Skip the mode select header and block descriptors.
- //
-
- if (Length < parameterHeaderLength) {
- return(NULL);
- }
-
-
-
- ModeSenseBuffer += parameterHeaderLength + ((Use6Byte) ? ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength :
- ((PMODE_PARAMETER_HEADER10) ModeSenseBuffer)->BlockDescriptorLength[1]);
-
- //
- // ModeSenseBuffer now points at pages. Walk the pages looking for the
- // requested page until the limit is reached.
- //
-
-
- while (ModeSenseBuffer < limit) {
-
- if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
- return(ModeSenseBuffer);
- }
-
- //
- // Advance to the next page.
- //
-
- ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
- }
-
- return(NULL);
-}
-\f
-NTSTATUS
-STDCALL
-ScsiClassSendSrbAsynchronous(
- PDEVICE_OBJECT DeviceObject,
- PSCSI_REQUEST_BLOCK Srb,
- PIRP Irp,
- PVOID BufferAddress,
- ULONG BufferLength,
- BOOLEAN WriteToDevice
- )
-/*++
-
-Routine Description:
-
- This routine takes a partially built Srb and an Irp and sends it down to
- the port driver.
-
-Arguments:
- DeviceObject - Supplies the device object for the orginal request.
-
- Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
- CDB and the SRB timeout value must be filled in. The SRB must not be
- allocated from zone.
-
- Irp - Supplies the requesting Irp.
-
- BufferAddress - Supplies a pointer to the buffer to be transfered.
-
- BufferLength - Supplies the length of data transfer.
-
- WriteToDevice - Indicates the data transfer will be from system memory to
- device.
-
-Return Value:
-
- Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
-
---*/
-{
-
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PIO_STACK_LOCATION irpStack;
-
- PAGED_CODE();
-
- //
- // Write length to SRB.
- //
-
- Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
-
- //
- // Set SCSI bus address.
- //
-
- Srb->PathId = deviceExtension->PathId;
- Srb->TargetId = deviceExtension->TargetId;
- Srb->Lun = deviceExtension->Lun;
-
- Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
-
- //
- // This is a violation of the SCSI spec but it is required for
- // some targets.
- //
-
- Srb->Cdb[1] |= deviceExtension->Lun << 5;
-
- //
- // Indicate auto request sense by specifying buffer and size.
- //
-
- Srb->SenseInfoBuffer = deviceExtension->SenseData;
- Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
- Srb->DataBuffer = BufferAddress;
-
- if (BufferAddress != NULL) {
-
- //
- // Build Mdl if necessary.
- //
-
- if (Irp->MdlAddress == NULL) {
-
- if (IoAllocateMdl(BufferAddress,
- BufferLength,
- FALSE,
- FALSE,
- Irp) == NULL) {
-
- return(STATUS_INSUFFICIENT_RESOURCES);
- }
-
- MmBuildMdlForNonPagedPool(Irp->MdlAddress);
-
- } else {
-
- //
- // Make sure the buffer requested matches the MDL.
- //
-
- ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
- }
-
- //
- // Set read flag.
- //
-
- Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
-
- } else {
-
- //
- // Clear flags.
- //
-
- Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
- }
-
- //
- // Disable synchronous transfer for these requests.
- //
-
- Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
-
- //
- // Set the transfer length.
- //
-
- Srb->DataTransferLength = BufferLength;
-
- //
- // Zero out status.
- //
-
- Srb->ScsiStatus = Srb->SrbStatus = 0;
-
- Srb->NextSrb = 0;
-
- //
- // Save a few parameters in the current stack location.
- //
-
- irpStack = IoGetCurrentIrpStackLocation(Irp);
-
- //
- // Save retry count in current Irp stack.
- //
-
- irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
-
- //
- // Set up IoCompletion routine address.
- //
-
- IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
-
- //
- // Get next stack location and
- // set major function code.
- //
-
- irpStack = IoGetNextIrpStackLocation(Irp);
-
- irpStack->MajorFunction = IRP_MJ_SCSI;
-
- //
- // Save SRB address in next stack for port driver.
- //
-
- irpStack->Parameters.Scsi.Srb = Srb;
-
- //
- // Set up Irp Address.
- //
-
- Srb->OriginalRequest = Irp;
-
- //
- // Call the port driver to process the request.
- //
-
- return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
-
-}
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassDeviceControlDispatch(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
-
-/*++
-
-Routine Description:
-
- The routine is the common class driver device control dispatch entry point.
- This routine is invokes the device-specific drivers DeviceControl routine,
- (which may call the Class driver's common DeviceControl routine).
-
-Arguments:
-
- DeviceObject - Supplies a pointer to the device object for this request.
-
- Irp - Supplies the Irp making the request.
-
-Return Value:
-
- Returns the status returned from the device-specific driver.
-
---*/
-
-{
-
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
-
-
- //
- // Call the class specific driver DeviceControl routine.
- // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
- //
-
- ASSERT(deviceExtension->ClassDeviceControl);
-
- return deviceExtension->ClassDeviceControl(DeviceObject,Irp);
-}
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassDeviceControl(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
-/*++
-
-Routine Description:
-
- The routine is the common class driver device control dispatch function.
- This routine is called by a class driver when it get an unrecognized
- device control request. This routine will perform the correct action for
- common requests such as lock media. If the device request is unknown it
- passed down to the next level.
-
-Arguments:
-
- DeviceObject - Supplies a pointer to the device object for this request.
-
- Irp - Supplies the Irp making the request.
-
-Return Value:
-
- Returns back a STATUS_PENDING or a completion status.
-
---*/
-
-{
- PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
- PIO_STACK_LOCATION nextStack;
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PSCSI_REQUEST_BLOCK srb;
- PCDB cdb;
- NTSTATUS status;
- ULONG modifiedIoControlCode;
-
- //
- // If this is a pass through I/O control, set the minor function code
- // and device address and pass it to the port driver.
- //
-
- if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH
- || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) {
-
- PSCSI_PASS_THROUGH scsiPass;
-
- nextStack = IoGetNextIrpStackLocation(Irp);
-
- //
- // Validiate the user buffer.
- //
-
- if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
-
- Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_INVALID_PARAMETER;
- goto SetStatusAndReturn;
- }
-
- //
- // Force the SCSI address to the correct value.
- //
-
- scsiPass = Irp->AssociatedIrp.SystemBuffer;
- scsiPass->PathId = deviceExtension->PathId;
- scsiPass->TargetId = deviceExtension->TargetId;
- scsiPass->Lun = deviceExtension->Lun;
-
- //
- // NOTICE: The SCSI-II specificaiton indicates that this field
- // should be zero; however, some target controllers ignore the logical
- // unit number in the INDENTIFY message and only look at the logical
- // unit number field in the CDB.
- //
-
- scsiPass->Cdb[1] |= deviceExtension->Lun << 5;
-
- nextStack->Parameters = irpStack->Parameters;
- nextStack->MajorFunction = irpStack->MajorFunction;
- nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
-
- status = IoCallDriver(deviceExtension->PortDeviceObject, Irp);
- goto SetStatusAndReturn;
- }
-
- if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) {
-
- PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
-
- if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
- sizeof(SCSI_ADDRESS)) {
-
- //
- // Indicate unsuccessful status and no data transferred.
- //
-
- Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_BUFFER_TOO_SMALL;
- goto SetStatusAndReturn;
-
- }
-
- scsiAddress->Length = sizeof(SCSI_ADDRESS);
- scsiAddress->PortNumber = deviceExtension->PortNumber;
- scsiAddress->PathId = deviceExtension->PathId;
- scsiAddress->TargetId = deviceExtension->TargetId;
- scsiAddress->Lun = deviceExtension->Lun;
- Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_SUCCESS;
- goto SetStatusAndReturn;
- }
-
- srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
-
- if (srb == NULL) {
-
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto SetStatusAndReturn;
- }
-
- //
- // Write zeros to Srb.
- //
-
- RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
-
- cdb = (PCDB)srb->Cdb;
-
- //
- // Change the device type to disk for the switch statement.
- //
-
- modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode
- & ~0xffff0000) | (IOCTL_DISK_BASE << 16);
-
- switch (modifiedIoControlCode) {
-
- case IOCTL_DISK_CHECK_VERIFY: {
-
- PIRP irp2 = NULL;
- PIO_STACK_LOCATION newStack;
-
- DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
-
- //
- // If a buffer for a media change count was provided, make sure it's
- // big enough to hold the result
- //
-
- if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
-
- //
- // If the buffer is too small to hold the media change count
- // then return an error to the caller
- //
-
- if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
- sizeof(ULONG)) {
-
- DebugPrint((3,"ScsiDeviceIoControl: media count "
- "buffer too small\n"));
-
- Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information = 0;
- ExFreePool(srb);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_BUFFER_TOO_SMALL;
- goto SetStatusAndReturn;
-
- }
-
- //
- // The caller has provided a valid buffer. Allocate an additional
- // irp and stick the CheckVerify completion routine on it. We will
- // then send this down to the port driver instead of the irp the
- // caller sent in
- //
-
- DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
- "media count\n"));
-
- //
- // Allocate a new irp to send the TestUnitReady to the port driver
- //
-
- irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
-
- if(irp2 == NULL) {
- Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- Irp->IoStatus.Information = 0;
- ExFreePool(srb);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto SetStatusAndReturn;
-
- break;
- }
-
- irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
- IoSetNextIrpStackLocation(irp2);
-
- //
- // Set the top stack location and shove the master Irp into the
- // top location
- //
-
- newStack = IoGetCurrentIrpStackLocation(irp2);
- newStack->Parameters.Others.Argument1 = Irp;
- newStack->DeviceObject = DeviceObject;
-
- //
- // Stick the check verify completion routine onto the stack
- // and prepare the irp for the port driver
- //
-
- IoSetCompletionRoutine(irp2,
- ScsiClassCheckVerifyComplete,
- NULL,
- TRUE,
- TRUE,
- TRUE);
-
- IoSetNextIrpStackLocation(irp2);
- newStack = IoGetCurrentIrpStackLocation(irp2);
- newStack->DeviceObject = DeviceObject;
-
- //
- // Mark the master irp as pending - whether the lower level
- // driver completes it immediately or not this should allow it
- // to go all the way back up.
- //
-
- IoMarkIrpPending(Irp);
-
- Irp = irp2;
-
- }
-
- //
- // Test Unit Ready
- //
-
- srb->CdbLength = 6;
- cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
-
- //
- // Set timeout value.
- //
-
- srb->TimeOutValue = deviceExtension->TimeOutValue;
-
- //
- // Since this routine will always hand the request to the
- // port driver if there isn't a data transfer to be done
- // we don't have to worry about completing the request here
- // on an error
- //
-
- status = ScsiClassSendSrbAsynchronous(DeviceObject,
- srb,
- Irp,
- NULL,
- 0,
- FALSE);
-
- break;
- }
-
- case IOCTL_DISK_MEDIA_REMOVAL: {
-
- PPREVENT_MEDIA_REMOVAL MediaRemoval = Irp->AssociatedIrp.SystemBuffer;
-
- //
- // Prevent/Allow media removal.
- //
-
- DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
-
- if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
- sizeof(PREVENT_MEDIA_REMOVAL)) {
-
- //
- // Indicate unsuccessful status and no data transferred.
- //
-
- Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information = 0;
- ExFreePool(srb);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_BUFFER_TOO_SMALL;
- goto SetStatusAndReturn;
- }
-
- //
- // Get physical device extension. This is where the
- // lock count is stored.
- //
-
- deviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
-
- //
- // If command succeeded then increment or decrement lock counter.
- //
-
- if (MediaRemoval->PreventMediaRemoval) {
-
- //
- // This is a lock command. Reissue the command in case bus or device
- // was reset and lock cleared.
- //
-
- InterlockedIncrement(&deviceExtension->LockCount);
-
- DebugPrint((1,
- "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
- deviceExtension->LockCount,
- deviceExtension->DeviceNumber));
-
- } else {
-
- //
- // This is an unlock command.
- //
-
- if (!deviceExtension->LockCount ||
- (InterlockedDecrement(&deviceExtension->LockCount) != 0)) {
-
- DebugPrint((1,
- "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
- deviceExtension->LockCount,
- deviceExtension->DeviceNumber));
-
- //
- // Don't unlock because someone still wants it locked.
- //
-
- Irp->IoStatus.Status = STATUS_SUCCESS;
- ExFreePool(srb);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- status = STATUS_SUCCESS;
- goto SetStatusAndReturn;
- }
-
- DebugPrint((1,
- "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
- deviceExtension->LockCount,
- deviceExtension->DeviceNumber));
- }
-
- srb->CdbLength = 6;
-
- cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
-
- //
- // TRUE - prevent media removal.
- // FALSE - allow media removal.
- //
-
- cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval;
-
- //
- // Set timeout value.
- //
-
- srb->TimeOutValue = deviceExtension->TimeOutValue;
- status = ScsiClassSendSrbAsynchronous(DeviceObject,
- srb,
- Irp,
- NULL,
- 0,
- FALSE);
-
- //
- // Some devices will not support lock/unlock.
- // Pretend that it worked.
- //
-
- break;
- }
-
- case IOCTL_DISK_RESERVE: {
-
- //
- // Reserve logical unit.
- //
-
- srb->CdbLength = 6;
-
- cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
-
- //
- // Set timeout value.
- //
-
- srb->TimeOutValue = deviceExtension->TimeOutValue;
-
- status = ScsiClassSendSrbAsynchronous(DeviceObject,
- srb,
- Irp,
- NULL,
- 0,
- FALSE);
-
- break;
- }
-
- case IOCTL_DISK_RELEASE: {
-
- //
- // Release logical unit.
- //
-
- srb->CdbLength = 6;
-
- cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
-
- //
- // Set timeout value.
- //
-
- srb->TimeOutValue = deviceExtension->TimeOutValue;
-
- status = ScsiClassSendSrbAsynchronous(DeviceObject,
- srb,
- Irp,
- NULL,
- 0,
- FALSE);
-
- break;
- }
-
- case IOCTL_DISK_EJECT_MEDIA: {
-
- //
- // Eject media.
- //
-
- srb->CdbLength = 6;
-
- cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
- cdb->START_STOP.LoadEject = 1;
- cdb->START_STOP.Start = 0;
-
- //
- // Set timeout value.
- //
-
- srb->TimeOutValue = deviceExtension->TimeOutValue;
- status = ScsiClassSendSrbAsynchronous(DeviceObject,
- srb,
- Irp,
- NULL,
- 0,
- FALSE);
- break;
- }
-
- case IOCTL_DISK_LOAD_MEDIA: {
-
- //
- // Load media.
- //
-
- DebugPrint((3,"CdRomDeviceControl: Load media\n"));
-
- srb->CdbLength = 6;
-
- cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
- cdb->START_STOP.LoadEject = 1;
- cdb->START_STOP.Start = 1;
-
- //
- // Set timeout value.
- //
-
- srb->TimeOutValue = deviceExtension->TimeOutValue;
- status = ScsiClassSendSrbAsynchronous(DeviceObject,
- srb,
- Irp,
- NULL,
- 0,
- FALSE);
-
- break;
- }
-
- case IOCTL_DISK_FIND_NEW_DEVICES: {
-
- //
- // Search for devices that have been powered on since the last
- // device search or system initialization.
- //
-
- DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
- status = DriverEntry(DeviceObject->DriverObject,
- NULL);
-
- Irp->IoStatus.Status = status;
- ExFreePool(srb);
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- break;
- }
-
- default: {
-
- DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
-
- //
- // Pass the device control to the next driver.
- //
-
- ExFreePool(srb);
-
- //
- // Copy the Irp stack parameters to the next stack location.
- //
-
- nextStack = IoGetNextIrpStackLocation(Irp);
- nextStack->Parameters = irpStack->Parameters;
- nextStack->MajorFunction = irpStack->MajorFunction;
- nextStack->MinorFunction = irpStack->MinorFunction;
-
- status = IoCallDriver(deviceExtension->PortDeviceObject, Irp);
- break;
- }
-
- } // end switch( ...
-
-SetStatusAndReturn:
-
- return status;
-}
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassShutdownFlush(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
-
-/*++
-
-Routine Description:
-
- This routine is called for a shutdown and flush IRPs. These are sent by the
- system before it actually shuts down or when the file system does a flush.
- If it exists, the device-specific driver's routine will be invoked. If there
- wasn't one specified, the Irp will be completed with an Invalid device request.
-
-Arguments:
-
- DriverObject - Pointer to device object to being shutdown by system.
-
- Irp - IRP involved.
-
-Return Value:
-
- NT Status
-
---*/
-
-{
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
-
- if (deviceExtension->ClassShutdownFlush) {
-
- //
- // Call the device-specific driver's routine.
- //
-
- return deviceExtension->ClassShutdownFlush(DeviceObject, Irp);
- }
-
- //
- // Device-specific driver doesn't support this.
- //
-
- Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return STATUS_INVALID_DEVICE_REQUEST;
-}
-
-\f
-ULONG
-STDCALL
-ScsiClassFindUnclaimedDevices(
- IN PCLASS_INIT_DATA InitializationData,
- IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
- )
-
-{
- ULONG scsiBus,deviceCount = 0;
- PCHAR buffer = (PCHAR)AdapterInformation;
- PSCSI_INQUIRY_DATA lunInfo;
- PINQUIRYDATA inquiryData;
-
- for (scsiBus=0; scsiBus < (ULONG)AdapterInformation->NumberOfBuses; scsiBus++) {
-
- //
- // Get the SCSI bus scan data for this bus.
- //
-
- lunInfo = (PVOID) (buffer + AdapterInformation->BusData[scsiBus].InquiryDataOffset);
-
- //
- // Search list for unclaimed disk devices.
- //
-
- while (AdapterInformation->BusData[scsiBus].InquiryDataOffset) {
-
- inquiryData = (PVOID)lunInfo->InquiryData;
-
- ASSERT(InitializationData->ClassFindDeviceCallBack);
-
- if ((InitializationData->ClassFindDeviceCallBack(inquiryData)) && (!lunInfo->DeviceClaimed)) {
-
- deviceCount++;
- }
-
- if (lunInfo->NextInquiryDataOffset == 0) {
- break;
- }
-
- lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
- }
- }
- return deviceCount;
-}
-
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassCreateDeviceObject(
- IN PDRIVER_OBJECT DriverObject,
- IN PCCHAR ObjectNameBuffer,
- IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject,
- IN OUT PDEVICE_OBJECT *DeviceObject,
- IN PCLASS_INIT_DATA InitializationData
- )
-
-/*++
-
-Routine Description:
-
- This routine creates an object for the physical device specified and
- sets up the deviceExtension's function pointers for each entry point
- in the device-specific driver.
-
-Arguments:
-
- DriverObject - Pointer to driver object created by system.
-
- ObjectNameBuffer - Dir. name of the object to create.
-
- PhysicalDeviceObject - Pointer to the physical (class) device object for
- this logical unit or NULL if this is it.
-
- DeviceObject - Pointer to the device object pointer we will return.
-
- InitializationData - Pointer to the init data created by the device-specific driver.
-
-Return Value:
-
- NTSTATUS
-
---*/
-
-{
- STRING ntNameString;
- UNICODE_STRING ntUnicodeString;
- NTSTATUS status;
- PDEVICE_OBJECT deviceObject = NULL;
-
- *DeviceObject = NULL;
-
- DebugPrint((2,
- "ScsiClassCreateDeviceObject: Create device object %s\n",
- ObjectNameBuffer));
-
- RtlInitString(&ntNameString,
- ObjectNameBuffer);
-
- status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
- &ntNameString,
- TRUE);
-
- if (!NT_SUCCESS(status)) {
-
- DebugPrint((1,
- "CreateDiskDeviceObjects: Cannot convert string %s\n",
- ObjectNameBuffer));
-
- ntUnicodeString.Buffer = NULL;
- return status;
- }
-
- status = IoCreateDevice(DriverObject,
- InitializationData->DeviceExtensionSize,
- &ntUnicodeString,
- InitializationData->DeviceType,
- InitializationData->DeviceCharacteristics,
- FALSE,
- &deviceObject);
-
-
- if (!NT_SUCCESS(status)) {
-
- DebugPrint((1,
- "CreateDiskDeviceObjects: Can not create device object %s\n",
- ObjectNameBuffer));
-
- } else {
-
- PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
-
- //
- // Fill in entry points
- //
-
- deviceExtension->ClassError = InitializationData->ClassError;
- deviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
- deviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
- deviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
- deviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
- deviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
- deviceExtension->ClassStartIo = InitializationData->ClassStartIo;
-
- deviceExtension->MediaChangeCount = 0;
-
- //
- // If a pointer to the physical device object was passed in then use
- // that. If the value was NULL, then this is the physical device so
- // use the pointer to the device we just created.
- //
-
- if(ARGUMENT_PRESENT(PhysicalDeviceObject)) {
- deviceExtension->PhysicalDevice = PhysicalDeviceObject;
- } else {
- deviceExtension->PhysicalDevice = deviceObject;
- }
- }
-
- *DeviceObject = deviceObject;
-
- RtlFreeUnicodeString(&ntUnicodeString);
-
- //
- // Indicate the ntUnicodeString is free.
- //
-
- ntUnicodeString.Buffer = NULL;
-
- return status;
-}
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassClaimDevice(
- IN PDEVICE_OBJECT PortDeviceObject,
- IN PSCSI_INQUIRY_DATA LunInfo,
- IN BOOLEAN Release,
- OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL
- )
-/*++
-
-Routine Description:
-
- This function claims a device in the port driver. The port driver object
- is updated with the correct driver object if the device is successfully
- claimed.
-
-Arguments:
-
- PortDeviceObject - Supplies the base port device object.
-
- LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
-
- Release - Indicates the logical unit should be released rather than claimed.
-
- NewPortDeviceObject - Returns the updated port device object to be used
- for all future accesses.
-
-Return Value:
-
- Returns a status indicating success or failure of the operation.
-
---*/
-
-{
- IO_STATUS_BLOCK ioStatus;
- PIRP irp;
- PIO_STACK_LOCATION irpStack;
- KEVENT event;
- NTSTATUS status;
- SCSI_REQUEST_BLOCK srb;
-
- PAGED_CODE();
-
- if (NewPortDeviceObject != NULL) {
- *NewPortDeviceObject = NULL;
- }
-
- //
- // Clear the SRB fields.
- //
-
- RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
-
- //
- // Write length to SRB.
- //
-
- srb.Length = SCSI_REQUEST_BLOCK_SIZE;
-
- //
- // Set SCSI bus address.
- //
-
- srb.PathId = LunInfo->PathId;
- srb.TargetId = LunInfo->TargetId;
- srb.Lun = LunInfo->Lun;
-
- srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
- SRB_FUNCTION_CLAIM_DEVICE;
-
- //
- // Set the event object to the unsignaled state.
- // It will be used to signal request completion.
- //
-
- KeInitializeEvent(&event, NotificationEvent, FALSE);
-
- //
- // Build synchronous request with no transfer.
- //
-
- irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
- PortDeviceObject,
- NULL,
- 0,
- NULL,
- 0,
- TRUE,
- &event,
- &ioStatus);
-
- if (irp == NULL) {
-
- DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- irpStack = IoGetNextIrpStackLocation(irp);
-
- //
- // Save SRB address in next stack for port driver.
- //
-
- irpStack->Parameters.Scsi.Srb = &srb;
-
- //
- // Set up IRP Address.
- //
-
- srb.OriginalRequest = irp;
-
- //
- // Call the port driver with the request and wait for it to complete.
- //
-
- status = IoCallDriver(PortDeviceObject, irp);
- if (status == STATUS_PENDING) {
-
- KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
- status = ioStatus.Status;
- }
-
- //
- // If this is a release request, then just decrement the reference count
- // and return. The status does not matter.
- //
-
- if (Release) {
-
- ObDereferenceObject(PortDeviceObject);
- return STATUS_SUCCESS;
- }
-
- if (!NT_SUCCESS(status)) {
- return status;
- }
-
- ASSERT(srb.DataBuffer != NULL);
-
- //
- // Reference the new port driver object so that it will not go away while
- // it is being used.
- //
-
- status = ObReferenceObjectByPointer(srb.DataBuffer,
- 0,
- NULL,
- KernelMode );
-
- if (!NT_SUCCESS(status)) {
-
- return status;
- }
-
- //
- // Return the new port device object pointer.
- //
-
- if (NewPortDeviceObject != NULL) {
- *NewPortDeviceObject = srb.DataBuffer;
- }
-
- return status;
-}
-
-\f
-NTSTATUS
-STDCALL
-ScsiClassInternalIoControl (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
-
-/*++
-
-Routine Description:
-
- This routine passes internal device controls to the port driver.
- Internal device controls are used by higher level class drivers to
- send scsi requests to a device that are not normally sent by a generic
- class driver.
-
- The path ID, target ID and logical unit ID are set in the srb so the
- higher level driver does not have to figure out what values are actually
- used.
-
-Arguments:
-
- DeviceObject - Supplies a pointer to the device object for this request.
-
- Irp - Supplies the Irp making the request.
-
-Return Value:
-
- Returns back a STATUS_PENDING or a completion status.
-
---*/
-{
- PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PSCSI_REQUEST_BLOCK srb;
-
- //
- // Get a pointer to the SRB.
- //
-
- srb = irpStack->Parameters.Scsi.Srb;
-
- //
- // Set SCSI bus address.
- //
-
- srb->PathId = deviceExtension->PathId;
- srb->TargetId = deviceExtension->TargetId;
- srb->Lun = deviceExtension->Lun;
-
- //
- // NOTICE: The SCSI-II specificaiton indicates that this field should be
- // zero; however, some target controllers ignore the logical unit number
- // in the INDENTIFY message and only look at the logical unit number field
- // in the CDB.
- //
-
- srb->Cdb[1] |= deviceExtension->Lun << 5;
-
- //
- // Set the parameters in the next stack location.
- //
-
- irpStack = IoGetNextIrpStackLocation(Irp);
-
- irpStack->Parameters.Scsi.Srb = srb;
- irpStack->MajorFunction = IRP_MJ_SCSI;
- irpStack->MinorFunction = IRP_MN_SCSI_CLASS;
-
- IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE);
- return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
-}
-\f
-NTSTATUS
-STDCALL
-ClassIoCompletion(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
-
-/*++
-
-Routine Description:
-
- This routine is called when an internal device control I/O request
- has completed. It marks the IRP pending if necessary and returns the
- status of the request.
-
-Arguments:
-
- DeviceObject - Target device object.
-
- Irp - Completed request.
-
- Context - not used.
-
-Return Value:
-
- Returns the status of the completed request.
-
---*/
-
-{
- UNREFERENCED_PARAMETER(Context);
- UNREFERENCED_PARAMETER(DeviceObject);
-
- //
- // If pending is returned for this Irp then mark current stack
- // as pending
- //
-
- if (Irp->PendingReturned) {
-
- IoMarkIrpPending( Irp );
- }
-
- return Irp->IoStatus.Status;
-}
-
-\f
-VOID
-STDCALL
-ScsiClassInitializeSrbLookasideList(
- IN PDEVICE_EXTENSION DeviceExtension,
- IN ULONG NumberElements
- )
-
-/*++
-
-Routine Description:
-
- This routine sets up a lookaside listhead for srbs.
-
-Arguments:
-
- DeviceExtension - Pointer to the deviceExtension containing the listhead.
-
- NumberElements - Supplies the maximum depth of the lookaside list.
-
-
-Return Value:
-
- None
-
---*/
-
-{
- ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
- NULL,
- NULL,
- NonPagedPoolMustSucceed,
- SCSI_REQUEST_BLOCK_SIZE,
- 'HscS',
- (USHORT)NumberElements);
-
-}
-
-\f
-ULONG
-STDCALL
-ScsiClassQueryTimeOutRegistryValue(
- IN PUNICODE_STRING RegistryPath
- )
-
-/*++
-
-Routine Description:
-
- This routine determines whether a reg key for a user-specified timeout value exists.
-
-Arguments:
-
- RegistryPath - Pointer to the hardware reg. entry describing the key.
-
-Return Value:
-
- New default timeout for a class of devices.
-
---*/
-
-{
- //
- // Find the appropriate reg. key
- //
-
- PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
- PWSTR path;
- NTSTATUS status;
- LONG timeOut = 0;
- ULONG zero = 0;
- ULONG size;
-
- if (!RegistryPath) {
- return 0;
- }
-
- parameters = ExAllocatePool(NonPagedPool,
- sizeof(RTL_QUERY_REGISTRY_TABLE)*2);
-
- if (!parameters) {
- return 0;
- }
-
- size = RegistryPath->MaximumLength + sizeof(WCHAR);
- path = ExAllocatePool(NonPagedPool, size);
-
- if (!path) {
- ExFreePool(parameters);
- return 0;
- }
-
- RtlZeroMemory(path,size);
- RtlCopyMemory(path, RegistryPath->Buffer, size - sizeof(WCHAR));
-
-
- //
- // Check for the Timeout value.
- //
-
- RtlZeroMemory(parameters,
- (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
-
- parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- parameters[0].Name = L"TimeOutValue";
- parameters[0].EntryContext = &timeOut;
- parameters[0].DefaultType = REG_DWORD;
- parameters[0].DefaultData = &zero;
- parameters[0].DefaultLength = sizeof(ULONG);
-
- status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
- path,
- parameters,
- NULL,
- NULL);
-
- if (!(NT_SUCCESS(status))) {
- timeOut = 0;
- }
-
- ExFreePool(parameters);
- ExFreePool(path);
-
- DebugPrint((2,
- "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
- timeOut));
-
-
- return timeOut;
-
-}
-\f
-NTSTATUS
-STDCALL
-ScsiClassCheckVerifyComplete(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- )
-
-/*++
-
-Routine Description:
-
- This routine executes when the port driver has completed a check verify
- ioctl. It will set the status of the master Irp, copy the media change
- count and complete the request.
-
-Arguments:
-
- DeviceObject - Supplies the device object which represents the logical
- unit.
-
- Irp - Supplies the Irp which has completed.
-
- Context - NULL
-
-Return Value:
-
- NT status
-
---*/
-
-{
- PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
- PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
- PDEVICE_EXTENSION physicalExtension =
- deviceExtension->PhysicalDevice->DeviceExtension;
- PIRP originalIrp;
-
- originalIrp = irpStack->Parameters.Others.Argument1;
-
- //
- // Copy the media change count and status
- //
-
- *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) =
- physicalExtension->MediaChangeCount;
-
- DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
- "device %d is %d\n",
- physicalExtension->DeviceNumber,
- physicalExtension->MediaChangeCount));
-
- originalIrp->IoStatus.Status = Irp->IoStatus.Status;
- originalIrp->IoStatus.Information = sizeof(ULONG);
-
- IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
-
- IoFreeIrp(Irp);
-
- return STATUS_MORE_PROCESSING_REQUIRED;
-}