mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 23:03:00 +00:00

Implemented dynamic partition management. Removed unused header files. svn path=/trunk/; revision=4596
1704 lines
42 KiB
C
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 */
|