reactos/reactos/drivers/storage/class2/class2.c
Eric Kohl a950079369 Moved disk manager related offset calculation to class2.
Implemented dynamic partition management.
Removed unused header files.

svn path=/trunk/; revision=4596
2003-04-27 10:50:07 +00:00

1704 lines
42 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2001, 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: class2.c,v 1.33 2003/04/27 10:49:06 ekohl Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: services/storage/class2/class2.c
* PURPOSE: SCSI class driver
* PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
*/
/*
* TODO:
* - finish ScsiClassDeviceControl().
*/
/* INCLUDES *****************************************************************/
#include <ddk/ntddk.h>
#include <ddk/scsi.h>
#include <ddk/class2.h>
#define NDEBUG
#include <debug.h>
#define VERSION "0.0.1"
#define TAG_SRBT TAG('S', 'r', 'b', 'T')
#define INQUIRY_DATA_SIZE 2048
static NTSTATUS STDCALL
ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static NTSTATUS STDCALL
ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static NTSTATUS STDCALL
ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static NTSTATUS STDCALL
ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static NTSTATUS STDCALL
ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
static VOID
ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
PIRP Irp, PSCSI_REQUEST_BLOCK Srb, BOOLEAN Associated);
/* FUNCTIONS ****************************************************************/
/**********************************************************************
* NAME EXPORTED
* DriverEntry
*
* DESCRIPTION
* This function initializes the driver.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DriverObject
* System allocated Driver Object for this driver.
* RegistryPath
* Name of registry driver service key.
*
* RETURNS
* Status
*/
NTSTATUS STDCALL
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DPRINT("Class Driver %s\n", VERSION);
return(STATUS_SUCCESS);
}
VOID
ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
IN PCHAR DebugMessage,
...)
{
char Buffer[256];
va_list ap;
#if 0
if (DebugPrintLevel > InternalDebugLevel)
return;
#endif
va_start(ap, DebugMessage);
vsprintf(Buffer, DebugMessage, ap);
va_end(ap);
DbgPrint(Buffer);
}
NTSTATUS STDCALL
ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
UNIMPLEMENTED;
}
VOID STDCALL
ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION CurrentIrpStack;
PIO_STACK_LOCATION NextIrpStack;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER StartingBlock;
PSCSI_REQUEST_BLOCK Srb;
PCDB Cdb;
ULONG LogicalBlockAddress;
USHORT TransferBlocks;
DeviceExtension = DeviceObject->DeviceExtension;
CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
NextIrpStack = IoGetNextIrpStackLocation(Irp);
StartingOffset = CurrentIrpStack->Parameters.Read.ByteOffset;
/* Calculate logical block address */
StartingBlock.QuadPart = StartingOffset.QuadPart >> DeviceExtension->SectorShift;
LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
/* Allocate and initialize an SRB */
Srb = ExAllocateFromNPagedLookasideList(&DeviceExtension->SrbLookasideListHead);
Srb->SrbFlags = 0;
Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
Srb->OriginalRequest = Irp;
Srb->PathId = DeviceExtension->PathId;
Srb->TargetId = DeviceExtension->TargetId;
Srb->Lun = DeviceExtension->Lun;
Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
//FIXME: NT4 DDK sample uses MmGetMdlVirtualAddress! Why shouldn't we?
Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
Srb->QueueSortKey = LogicalBlockAddress;
Srb->SenseInfoBuffer = DeviceExtension->SenseData;
Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
Srb->TimeOutValue =
((Srb->DataTransferLength + 0xFFFF) >> 16) * DeviceExtension->TimeOutValue;
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->ScsiStatus = 0;
Srb->NextSrb = 0;
Srb->CdbLength = 10;
Cdb = (PCDB)Srb->Cdb;
/* Initialize ATAPI packet (12 bytes) */
RtlZeroMemory(Cdb,
MAXIMUM_CDB_SIZE);
Cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
TransferBlocks = (USHORT)(CurrentIrpStack->Parameters.Read.Length >> DeviceExtension->SectorShift);
/* Copy 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;
if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
{
DPRINT("ScsiClassBuildRequest: Read Command\n");
Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
Cdb->CDB10.OperationCode = SCSIOP_READ;
}
else
{
DPRINT("ScsiClassBuildRequest: Write Command\n");
Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
Cdb->CDB10.OperationCode = SCSIOP_WRITE;
}
#if 0
/* 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 (DeviceExtension->DeviceFlags & DEV_WRITE_CACHE)
{
/* if write caching is enable then force media access in the cdb */
Cdb->CDB10.ForceUnitAccess = TRUE;
}
#endif
/* Update srb flags */
Srb->SrbFlags |= DeviceExtension->SrbFlags;
/* Initialize next stack location */
NextIrpStack->MajorFunction = IRP_MJ_SCSI;
NextIrpStack->Parameters.Scsi.Srb = Srb;
/* Set retry count */
CurrentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp, Srb);
IoSetCompletionRoutine(Irp,
ScsiClassIoComplete,
Srb,
TRUE,
TRUE,
TRUE);
}
NTSTATUS STDCALL
ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject,
PSCSI_INQUIRY_DATA LunInfo,
BOOLEAN Release,
PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL)
{
PIO_STACK_LOCATION IoStack;
IO_STATUS_BLOCK IoStatusBlock;
SCSI_REQUEST_BLOCK Srb;
KEVENT Event;
PIRP Irp;
NTSTATUS Status;
DPRINT("ScsiClassClaimDevice() called\n");
if (NewPortDeviceObject != NULL)
*NewPortDeviceObject = NULL;
/* initialize an SRB */
RtlZeroMemory(&Srb,
sizeof(SCSI_REQUEST_BLOCK));
Srb.Length = SCSI_REQUEST_BLOCK_SIZE;
Srb.PathId = LunInfo->PathId;
Srb.TargetId = LunInfo->TargetId;
Srb.Lun = LunInfo->Lun;
Srb.Function =
(Release == TRUE) ? SRB_FUNCTION_RELEASE_DEVICE : SRB_FUNCTION_CLAIM_DEVICE;
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
PortDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&Event,
&IoStatusBlock);
if (Irp == NULL)
{
DPRINT("Failed to allocate Irp!\n");
return(STATUS_INSUFFICIENT_RESOURCES);
}
/* Link Srb and Irp */
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->Parameters.Scsi.Srb = &Srb;
Srb.OriginalRequest = Irp;
/* Call SCSI port driver */
Status = IoCallDriver(PortDeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Suspended,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
if (Release == TRUE)
{
ObDereferenceObject(PortDeviceObject);
return(STATUS_SUCCESS);
}
// Status = ObReferenceObjectByPointer(Srb.DataBuffer,
Status = ObReferenceObjectByPointer(PortDeviceObject,
0,
NULL,
KernelMode);
if (NewPortDeviceObject != NULL)
{
// *NewPortDeviceObject = Srb.DataBuffer;
*NewPortDeviceObject = PortDeviceObject;
}
return(STATUS_SUCCESS);
}
NTSTATUS STDCALL
ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
IN PCCHAR ObjectNameBuffer,
IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
IN OUT PDEVICE_OBJECT *DeviceObject,
IN PCLASS_INIT_DATA InitializationData)
{
PDEVICE_OBJECT InternalDeviceObject;
PDEVICE_EXTENSION DeviceExtension;
ANSI_STRING AnsiName;
UNICODE_STRING DeviceName;
NTSTATUS Status;
DPRINT("ScsiClassCreateDeviceObject() called\n");
*DeviceObject = NULL;
RtlInitAnsiString(&AnsiName,
ObjectNameBuffer);
Status = RtlAnsiStringToUnicodeString(&DeviceName,
&AnsiName,
TRUE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
DPRINT("Device name: '%wZ'\n", &DeviceName);
Status = IoCreateDevice(DriverObject,
InitializationData->DeviceExtensionSize,
&DeviceName,
InitializationData->DeviceType,
InitializationData->DeviceCharacteristics,
FALSE,
&InternalDeviceObject);
if (NT_SUCCESS(Status))
{
DeviceExtension = InternalDeviceObject->DeviceExtension;
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 (PhysicalDeviceObject != NULL)
{
DeviceExtension->PhysicalDevice = PhysicalDeviceObject;
}
else
{
DeviceExtension->PhysicalDevice = InternalDeviceObject;
}
*DeviceObject = InternalDeviceObject;
}
RtlFreeUnicodeString(&DeviceName);
return(Status);
}
NTSTATUS STDCALL
ScsiClassDeviceControl(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION Stack;
ULONG IoControlCode;
ULONG OutputBufferLength;
DPRINT("ScsiClassDeviceControl() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp);
IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
OutputBufferLength = Stack->Parameters.DeviceIoControl.OutputBufferLength;
if (IoControlCode == IOCTL_SCSI_GET_ADDRESS)
{
PSCSI_ADDRESS ScsiAddress;
if (OutputBufferLength < sizeof(SCSI_ADDRESS))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_BUFFER_TOO_SMALL);
}
ScsiAddress = Irp->AssociatedIrp.SystemBuffer;
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);
return(STATUS_SUCCESS);
}
if (IoControlCode == IOCTL_SCSI_PASS_THROUGH ||
IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
{
DPRINT1("Fixme: IOCTL_SCSI_PASS_THROUGH/IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_UNSUCCESSFUL);
}
DPRINT1("Fixme: unknown device io control code\n");
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_UNSUCCESSFUL);
}
PVOID STDCALL
ScsiClassFindModePage(PCHAR ModeSenseBuffer,
ULONG Length,
UCHAR PageMode,
BOOLEAN Use6Byte)
{
UNIMPLEMENTED;
}
ULONG STDCALL
ScsiClassFindUnclaimedDevices(PCLASS_INIT_DATA InitializationData,
PSCSI_ADAPTER_BUS_INFO AdapterInformation)
{
PSCSI_INQUIRY_DATA UnitInfo;
PINQUIRYDATA InquiryData;
PUCHAR Buffer;
ULONG Bus;
ULONG UnclaimedDevices = 0;
NTSTATUS Status;
DPRINT("ScsiClassFindUnclaimedDevices() called\n");
DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
Buffer = (PUCHAR)AdapterInformation;
for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
{
DPRINT("Searching bus %lu\n", Bus);
UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);
while (AdapterInformation->BusData[Bus].InquiryDataOffset)
{
InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
DPRINT("Device: '%.8s'\n", InquiryData->VendorId);
if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
(UnitInfo->DeviceClaimed == FALSE))
{
UnclaimedDevices++;
}
if (UnitInfo->NextInquiryDataOffset == 0)
break;
UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
}
}
return(UnclaimedDevices);
}
NTSTATUS STDCALL
ScsiClassGetCapabilities(PDEVICE_OBJECT PortDeviceObject,
PIO_SCSI_CAPABILITIES *PortCapabilities)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
KEVENT Event;
PIRP Irp;
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
PortDeviceObject,
NULL,
0,
PortCapabilities,
sizeof(PVOID),
FALSE,
&Event,
&IoStatusBlock);
if (Irp == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
Status = IoCallDriver(PortDeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Suspended,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
DPRINT("PortCapabilities at %p\n", *PortCapabilities);
return(Status);
}
NTSTATUS STDCALL
ScsiClassGetInquiryData(PDEVICE_OBJECT PortDeviceObject,
PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
{
PSCSI_ADAPTER_BUS_INFO Buffer;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
KEVENT Event;
PIRP Irp;
DPRINT("ScsiClassGetInquiryData() called\n");
*ConfigInfo = NULL;
Buffer = ExAllocatePool(NonPagedPool,
INQUIRY_DATA_SIZE);
if (Buffer == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
PortDeviceObject,
NULL,
0,
Buffer,
INQUIRY_DATA_SIZE,
FALSE,
&Event,
&IoStatusBlock);
if (Irp == NULL)
{
ExFreePool(Buffer);
return(STATUS_INSUFFICIENT_RESOURCES);
}
Status = IoCallDriver(PortDeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Suspended,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
if (!NT_SUCCESS(Status))
{
ExFreePool(Buffer);
}
else
{
*ConfigInfo = Buffer;
}
DPRINT("ScsiClassGetInquiryData() done\n");
return(Status);
}
ULONG STDCALL
ScsiClassInitialize(PVOID Argument1,
PVOID Argument2,
PCLASS_INIT_DATA InitializationData)
{
PCONFIGURATION_INFORMATION ConfigInfo;
PDRIVER_OBJECT DriverObject = Argument1;
WCHAR NameBuffer[80];
UNICODE_STRING PortName;
ULONG PortNumber;
PDEVICE_OBJECT PortDeviceObject;
PFILE_OBJECT FileObject;
BOOLEAN DiskFound = FALSE;
NTSTATUS Status;
DPRINT("ScsiClassInitialize() called!\n");
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] = ScsiClassScsiDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
if (InitializationData->ClassStartIo)
{
DriverObject->DriverStartIo = InitializationData->ClassStartIo;
}
ConfigInfo = IoGetConfigurationInformation();
DPRINT("ScsiPorts: %lu\n", ConfigInfo->ScsiPortCount);
/* look for ScsiPortX scsi port devices */
for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
{
swprintf(NameBuffer,
L"\\Device\\ScsiPort%lu",
PortNumber);
RtlInitUnicodeString(&PortName,
NameBuffer);
DPRINT("Checking scsi port %ld\n", PortNumber);
Status = IoGetDeviceObjectPointer(&PortName,
FILE_READ_ATTRIBUTES,
&FileObject,
&PortDeviceObject);
DPRINT("Status 0x%08lX\n", Status);
if (NT_SUCCESS(Status))
{
DPRINT("ScsiPort%lu found.\n", PortNumber);
/* check scsi port for attached disk drives */
if (InitializationData->ClassFindDevices(DriverObject,
Argument2,
InitializationData,
PortDeviceObject,
PortNumber))
{
DiskFound = TRUE;
}
}
else
{
DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber, Status);
}
}
DPRINT("ScsiClassInitialize() done!\n");
return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
}
/**********************************************************************
* NAME EXPORTED
* ScsiClassInitializeSrbLookasideList
*
* DESCRIPTION
* Initializes a lookaside list for SRBs.
*
* RUN LEVEL
* PASSIVE_LEVEL
*
* ARGUMENTS
* DeviceExtension
* Class specific device extension.
*
* NumberElements
* Maximum number of elements of the lookaside list.
*
* RETURN VALUE
* None.
*/
VOID STDCALL
ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension,
ULONG NumberElements)
{
ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
NULL,
NULL,
NonPagedPool,
sizeof(SCSI_REQUEST_BLOCK),
TAG_SRBT,
(USHORT)NumberElements);
}
NTSTATUS STDCALL
ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
UNIMPLEMENTED;
}
BOOLEAN STDCALL
ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject,
PSCSI_REQUEST_BLOCK Srb,
UCHAR MajorFunctionCode,
ULONG IoDeviceCode,
ULONG RetryCount,
NTSTATUS *Status)
{
PDEVICE_EXTENSION DeviceExtension;
PSENSE_DATA SenseData;
BOOLEAN Retry;
DPRINT("ScsiClassInterpretSenseInfo() called\n");
DPRINT("Srb->SrbStatus %lx\n", Srb->SrbStatus);
if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
{
*Status = STATUS_SUCCESS;
return(FALSE);
}
DeviceExtension = DeviceObject->DeviceExtension;
SenseData = Srb->SenseInfoBuffer;
Retry = TRUE;
if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
(Srb->SenseInfoBufferLength > 0))
{
/* Got valid sense data, interpret them */
DPRINT("ErrorCode: %x\n", SenseData->ErrorCode);
DPRINT("SenseKey: %x\n", SenseData->SenseKey);
DPRINT("SenseCode: %x\n", SenseData->AdditionalSenseCode);
switch (SenseData->SenseKey & 0xf)
{
/* FIXME: add more sense key codes */
case SCSI_SENSE_NOT_READY:
DPRINT("SCSI_SENSE_NOT_READY\n");
*Status = STATUS_DEVICE_NOT_READY;
break;
case SCSI_SENSE_UNIT_ATTENTION:
DPRINT("SCSI_SENSE_UNIT_ATTENTION\n");
if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
(DeviceObject->Vpb->Flags & VPB_MOUNTED))
{
DeviceObject->Flags |= DO_VERIFY_VOLUME;
*Status = STATUS_VERIFY_REQUIRED;
Retry = FALSE;
}
else
{
*Status = STATUS_IO_DEVICE_ERROR;
}
break;
case SCSI_SENSE_ILLEGAL_REQUEST:
DPRINT("SCSI_SENSE_ILLEGAL_REQUEST\n");
*Status = STATUS_INVALID_DEVICE_REQUEST;
Retry = FALSE;
break;
default:
DPRINT1("SCSI error (sense key: %x)\n",
SenseData->SenseKey & 0xf);
*Status = STATUS_IO_DEVICE_ERROR;
break;
}
}
else
{
/* Got no or invalid sense data, return generic error codes */
switch (SRB_STATUS(Srb->SrbStatus))
{
/* FIXME: add more srb status codes */
case SRB_STATUS_INVALID_PATH_ID:
case SRB_STATUS_INVALID_TARGET_ID:
case SRB_STATUS_INVALID_LUN:
case SRB_STATUS_NO_DEVICE:
case SRB_STATUS_NO_HBA:
*Status = STATUS_NO_SUCH_DEVICE;
Retry = FALSE;
break;
case SRB_STATUS_BUSY:
*Status = STATUS_DEVICE_BUSY;
Retry = TRUE;
break;
case SRB_STATUS_DATA_OVERRUN:
*Status = STATUS_DATA_OVERRUN;
Retry = FALSE;
break;
default:
DPRINT1("SCSI error (SRB status: %x)\n",
SRB_STATUS(Srb->SrbStatus));
*Status = STATUS_IO_DEVICE_ERROR;
break;
}
}
/* Call the class driver specific error function */
if (DeviceExtension->ClassError != NULL)
{
DeviceExtension->ClassError(DeviceObject,
Srb,
Status,
&Retry);
}
/* FIXME: log severe errors */
DPRINT("ScsiClassInterpretSenseInfo() done\n");
return(Retry);
}
NTSTATUS STDCALL
ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
PSCSI_REQUEST_BLOCK Srb;
BOOLEAN Retry;
NTSTATUS Status;
DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
DeviceObject, Irp, Context);
DeviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
//BUGBUG -> Srb = IrpStack->Parameters.Scsi.Srb;
//Must pass Srb as Context arg!! See comment about Completion routines in
//IofCallDriver for more info.
Srb = (PSCSI_REQUEST_BLOCK)Context;
DPRINT("Srb %p\n", Srb);
if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
{
Status = STATUS_SUCCESS;
}
else
{
Retry = ScsiClassInterpretSenseInfo(DeviceObject,
Srb,
IrpStack->MajorFunction,
0,
MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
&Status);
if ((Retry) &&
((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
{
((ULONG)IrpStack->Parameters.Others.Argument4)--;
ScsiClassRetryRequest(
DeviceObject,
Irp,
Srb,
FALSE);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
}
/* Free the SRB */
ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
Srb);
Irp->IoStatus.Status = Status;
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Information = 0;
if (IoIsErrorUserInduced(Status))
{
IoSetHardErrorOrVerifyDevice(Irp,
DeviceObject);
}
}
if (DeviceExtension->ClassStartIo != NULL)
{
if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
{
IoStartNextPacket(DeviceObject,
FALSE);
}
}
DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
return(Status);
}
NTSTATUS STDCALL
ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
PSCSI_REQUEST_BLOCK Srb;
PIRP MasterIrp;
BOOLEAN Retry;
LONG RequestCount;
NTSTATUS Status;
DPRINT("ScsiClassIoCompleteAssociated(DeviceObject %p Irp %p Context %p) called\n",
DeviceObject, Irp, Context);
MasterIrp = Irp->AssociatedIrp.MasterIrp;
DeviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
//BUGBUG -> Srb = Srb = IrpStack->Parameters.Scsi.Srb;
//Must pass Srb as Context arg!! See comment about Completion routines in
//IofCallDriver for more info.
Srb = (PSCSI_REQUEST_BLOCK)Context;
DPRINT("Srb %p\n", Srb);
if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
{
Status = STATUS_SUCCESS;
}
else
{
/* Get more detailed status information */
Retry = ScsiClassInterpretSenseInfo(DeviceObject,
Srb,
IrpStack->MajorFunction,
0,
MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
&Status);
if ((Retry) &&
((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
{
((ULONG)IrpStack->Parameters.Others.Argument4)--;
ScsiClassRetryRequest(
DeviceObject,
Irp,
Srb,
TRUE);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
}
/* Free the SRB */
ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
Srb);
Irp->IoStatus.Status = Status;
IrpStack = IoGetNextIrpStackLocation(MasterIrp);
if (!NT_SUCCESS(Status))
{
MasterIrp->IoStatus.Status = Status;
MasterIrp->IoStatus.Information = 0;
if (IoIsErrorUserInduced(Status))
{
IoSetHardErrorOrVerifyDevice(MasterIrp,
DeviceObject);
}
}
/* Decrement the request counter in the Master IRP */
RequestCount = InterlockedDecrement((PLONG)&IrpStack->Parameters.Others.Argument1);
if (RequestCount == 0)
{
/* Complete the Master IRP */
IoCompleteRequest(MasterIrp,
IO_DISK_INCREMENT);
if (DeviceExtension->ClassStartIo)
{
IoStartNextPacket(DeviceObject,
FALSE);
}
}
/* Free the current IRP */
IoFreeIrp(Irp);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
ULONG STDCALL
ScsiClassModeSense(PDEVICE_OBJECT DeviceObject,
CHAR ModeSenseBuffer,
ULONG Length,
UCHAR PageMode)
{
UNIMPLEMENTED;
}
ULONG STDCALL
ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
{
UNIMPLEMENTED;
}
NTSTATUS STDCALL
ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
{
PDEVICE_EXTENSION DeviceExtension;
PREAD_CAPACITY_DATA CapacityBuffer;
SCSI_REQUEST_BLOCK Srb;
PCDB Cdb;
NTSTATUS Status;
ULONG LastSector;
ULONG SectorSize;
DPRINT("ScsiClassReadDriveCapacity() called\n");
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
CapacityBuffer = ExAllocatePool(NonPagedPool,
sizeof(READ_CAPACITY_DATA));
if (CapacityBuffer == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
Srb.CdbLength = 10;
Srb.TimeOutValue = DeviceExtension->TimeOutValue;
Cdb = (PCDB)Srb.Cdb;
Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
Status = ScsiClassSendSrbSynchronous(DeviceObject,
&Srb,
CapacityBuffer,
sizeof(READ_CAPACITY_DATA),
FALSE);
DPRINT("Status: %lx\n", Status);
DPRINT("Srb: %p\n", &Srb);
if (NT_SUCCESS(Status))
{
SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
(((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
(((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
(((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
(((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
DeviceExtension->SectorShift);
DeviceExtension->PartitionLength.QuadPart =
(DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
{
DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
}
else
{
DeviceExtension->DiskGeometry->MediaType = FixedMedia;
}
DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
}
else
{
/* Use default values if disk geometry cannot be read */
RtlZeroMemory(DeviceExtension->DiskGeometry,
sizeof(DISK_GEOMETRY));
DeviceExtension->DiskGeometry->BytesPerSector = 512;
DeviceExtension->SectorShift = 9;
DeviceExtension->PartitionLength.QuadPart = 0;
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
{
DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
}
else
{
DeviceExtension->DiskGeometry->MediaType = FixedMedia;
}
DPRINT("SectorSize: 512 SectorCount: 0\n");
}
ExFreePool(CapacityBuffer);
DPRINT("ScsiClassReadDriveCapacity() done\n");
return(Status);
}
VOID STDCALL
ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
{
UNIMPLEMENTED;
}
NTSTATUS STDCALL
ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
PSCSI_REQUEST_BLOCK Srb,
PIRP Irp,
PVOID BufferAddress,
ULONG BufferLength,
BOOLEAN WriteToDevice)
{
UNIMPLEMENTED;
}
NTSTATUS STDCALL
ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
PSCSI_REQUEST_BLOCK Srb,
PVOID BufferAddress,
ULONG BufferLength,
BOOLEAN WriteToDevice)
{
PDEVICE_EXTENSION DeviceExtension;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IrpStack;
ULONG RequestType;
BOOLEAN Retry;
ULONG RetryCount;
PKEVENT Event;
PIRP Irp;
NTSTATUS Status;
DPRINT("ScsiClassSendSrbSynchronous() called\n");
RetryCount = MAXIMUM_RETRIES;
DeviceExtension = DeviceObject->DeviceExtension;
Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
Srb->PathId = DeviceExtension->PathId;
Srb->TargetId = DeviceExtension->TargetId;
Srb->Lun = DeviceExtension->Lun;
Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
SENSE_BUFFER_SIZE);
if (Srb->SenseInfoBuffer == NULL)
return(STATUS_INSUFFICIENT_RESOURCES);
if (BufferAddress == NULL)
{
BufferLength = 0;
RequestType = IOCTL_SCSI_EXECUTE_NONE;
Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
}
else
{
if (WriteToDevice == TRUE)
{
RequestType = IOCTL_SCSI_EXECUTE_IN; // needs _in_ to the device
Srb->SrbFlags = SRB_FLAGS_DATA_OUT; // needs _out_ from the caller
}
else
{
RequestType = IOCTL_SCSI_EXECUTE_OUT;
Srb->SrbFlags = SRB_FLAGS_DATA_IN;
}
}
Srb->DataTransferLength = BufferLength;
Srb->DataBuffer = BufferAddress;
Event = ExAllocatePool(NonPagedPool,
sizeof(KEVENT));
TryAgain:
KeInitializeEvent(Event,
NotificationEvent,
FALSE);
Irp = IoBuildDeviceIoControlRequest(RequestType,
DeviceExtension->PortDeviceObject,
NULL,
0,
BufferAddress,
BufferLength,
TRUE,
Event,
&IoStatusBlock);
if (Irp == NULL)
{
DPRINT("IoBuildDeviceIoControlRequest() failed\n");
ExFreePool(Srb->SenseInfoBuffer);
ExFreePool(Event);
return(STATUS_INSUFFICIENT_RESOURCES);
}
/* Attach Srb to the Irp */
IrpStack = IoGetNextIrpStackLocation(Irp);
IrpStack->Parameters.Scsi.Srb = Srb;
Srb->OriginalRequest = Irp;
/* Call the SCSI port driver */
Status = IoCallDriver(DeviceExtension->PortDeviceObject,
Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(Event,
Suspended,
KernelMode,
FALSE,
NULL);
}
if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
{
Retry = ScsiClassInterpretSenseInfo(DeviceObject,
Srb,
IRP_MJ_SCSI,
0,
MAXIMUM_RETRIES - RetryCount,
&Status);
if (Retry == TRUE)
{
DPRINT("Try again (RetryCount %lu)\n", RetryCount);
/* FIXME: Wait a little if we got a timeout error */
if (RetryCount--)
goto TryAgain;
}
}
else
{
Status = STATUS_SUCCESS;
}
ExFreePool(Srb->SenseInfoBuffer);
ExFreePool(Event);
DPRINT("ScsiClassSendSrbSynchronous() done\n");
return(Status);
}
VOID STDCALL
ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject,
PIRP Irp,
ULONG MaximumBytes)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION CurrentStack;
PIO_STACK_LOCATION NextStack;
PIO_STACK_LOCATION NewStack;
PSCSI_REQUEST_BLOCK Srb;
LARGE_INTEGER Offset;
PIRP NewIrp;
PVOID DataBuffer;
ULONG TransferLength;
ULONG RequestCount;
ULONG DataLength;
ULONG i;
DPRINT("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
DeviceObject, Irp, MaximumBytes);
DeviceExtension = DeviceObject->DeviceExtension;
CurrentStack = IoGetCurrentIrpStackLocation(Irp);
NextStack = IoGetNextIrpStackLocation(Irp);
DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
/* Initialize transfer data for first request */
Offset = CurrentStack->Parameters.Read.ByteOffset;
TransferLength = CurrentStack->Parameters.Read.Length;
DataLength = MaximumBytes;
RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
/* Save request count in the original IRP */
NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
DPRINT("RequestCount %lu\n", RequestCount);
for (i = 0; i < RequestCount; i++)
{
/* Create a new IRP */
NewIrp = IoAllocateIrp(DeviceObject->StackSize,
FALSE);
if (NewIrp == NULL)
{
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
if (i == 0)
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return;
}
/* Initialize the new IRP */
NewIrp->MdlAddress = Irp->MdlAddress;
IoSetNextIrpStackLocation(NewIrp);
NewStack = IoGetCurrentIrpStackLocation(NewIrp);
NewStack->MajorFunction = CurrentStack->MajorFunction;
NewStack->Parameters.Read.ByteOffset = Offset;
NewStack->Parameters.Read.Length = DataLength;
NewStack->DeviceObject = DeviceObject;
ScsiClassBuildRequest(DeviceObject,
NewIrp);
NewStack = IoGetNextIrpStackLocation(NewIrp);
Srb = NewStack->Parameters.Others.Argument1;
Srb->DataBuffer = DataBuffer;
NewIrp->AssociatedIrp.MasterIrp = Irp;
/* Initialize completion routine */
IoSetCompletionRoutine(NewIrp,
ScsiClassIoCompleteAssociated,
Srb,
TRUE,
TRUE,
TRUE);
/* Send the new IRP down to the port driver */
IoCallDriver(DeviceExtension->PortDeviceObject,
NewIrp);
/* Adjust transfer data for next request */
DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
TransferLength -= MaximumBytes;
DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
Offset.QuadPart = Offset.QuadPart + MaximumBytes;
}
}
/* INTERNAL FUNCTIONS *******************************************************/
static NTSTATUS STDCALL
ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
DPRINT("ScsiClassCreateClose() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->ClassCreateClose)
return(DeviceExtension->ClassCreateClose(DeviceObject,
Irp));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
static NTSTATUS STDCALL
ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
ULONG MaximumTransferLength;
ULONG CurrentTransferLength;
ULONG MaximumTransferPages;
ULONG CurrentTransferPages;
NTSTATUS Status;
DPRINT("ScsiClassReadWrite() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT("Relative Offset: %I64u Length: %lu\n",
IrpStack->Parameters.Read.ByteOffset.QuadPart,
IrpStack->Parameters.Read.Length);
MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
CurrentTransferLength = IrpStack->Parameters.Read.Length;
if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
{
IoSetHardErrorOrVerifyDevice(Irp,
DeviceObject);
Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(STATUS_VERIFY_REQUIRED);
}
/* Class driver verifies the IRP */
Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
Irp);
if (!NT_SUCCESS(Status))
{
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(Status);
}
else if (Status == STATUS_PENDING)
{
IoMarkIrpPending(Irp);
return(STATUS_PENDING);
}
/* Finish a zero-byte transfer */
if (CurrentTransferLength == 0)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
if (DeviceExtension->ClassStartIo != NULL)
{
DPRINT("ScsiClassReadWrite() starting packet\n");
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject,
Irp,
NULL,
NULL);
return(STATUS_PENDING);
}
/* Adjust partition-relative starting offset to absolute offset */
IrpStack->Parameters.Read.ByteOffset.QuadPart +=
(DeviceExtension->StartingOffset.QuadPart + DeviceExtension->DMByteSkew);
/* Calculate number of pages in this transfer */
CurrentTransferPages =
ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
IrpStack->Parameters.Read.Length);
if (CurrentTransferLength > MaximumTransferLength ||
CurrentTransferPages > MaximumTransferPages)
{
DPRINT("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
MaximumTransferLength, CurrentTransferLength);
/* Adjust the maximum transfer length */
CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
if (MaximumTransferLength > CurrentTransferPages * PAGE_SIZE)
MaximumTransferLength = CurrentTransferPages * PAGE_SIZE;
if (MaximumTransferLength == 0)
MaximumTransferLength = PAGE_SIZE;
IoMarkIrpPending(Irp);
/* Split current request */
ScsiClassSplitRequest(DeviceObject,
Irp,
MaximumTransferLength);
return(STATUS_PENDING);
}
ScsiClassBuildRequest(DeviceObject,
Irp);
DPRINT("ScsiClassReadWrite() done\n");
/* Call the port driver */
return(IoCallDriver(DeviceExtension->PortDeviceObject,
Irp));
}
static NTSTATUS STDCALL
ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT1("ScsiClassScsiDispatch() called\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
static NTSTATUS STDCALL
ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
DPRINT("ScsiClassDeviceDispatch() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->ClassDeviceControl)
{
return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
}
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_INVALID_DEVICE_REQUEST);
}
static NTSTATUS STDCALL
ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
DPRINT("ScsiClassShutdownFlush() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceExtension->ClassShutdownFlush)
{
return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
}
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_INVALID_DEVICE_REQUEST);
}
static VOID
ScsiClassRetryRequest(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PSCSI_REQUEST_BLOCK Srb,
BOOLEAN Associated
)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION CurrentIrpStack;
PIO_STACK_LOCATION NextIrpStack;
ULONG TransferLength;
DPRINT("ScsiPortRetryRequest() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
NextIrpStack = IoGetNextIrpStackLocation(Irp);
if (CurrentIrpStack->MajorFunction != IRP_MJ_READ &&
CurrentIrpStack->MajorFunction != IRP_MJ_WRITE)
{
/* We shouldn't setup the buffer pointer and transfer length on read/write requests. */
if (Irp->MdlAddress != NULL)
{
TransferLength = Irp->MdlAddress->ByteCount;
}
else
{
TransferLength = 0;
}
Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
Srb->DataTransferLength = TransferLength;
}
Srb->SrbStatus = 0;
Srb->ScsiStatus = 0;
/* Don't modify the flags */
// Srb->Flags =
// Srb->QueueTag = SP_UNTAGGED;
NextIrpStack->MajorFunction = IRP_MJ_SCSI;
NextIrpStack->Parameters.Scsi.Srb = Srb;
if (Associated == FALSE)
{
IoSetCompletionRoutine(Irp,
ScsiClassIoComplete,
Srb,
TRUE,
TRUE,
TRUE);
}
else
{
IoSetCompletionRoutine(Irp,
ScsiClassIoCompleteAssociated,
Srb,
TRUE,
TRUE,
TRUE);
}
IoCallDriver(DeviceExtension->PortDeviceObject,
Irp);
DPRINT("ScsiPortRetryRequest() done\n");
}
/* EOF */