class2.c
来自「一个类似windows」· C语言 代码 · 共 2,461 行 · 第 1/5 页
C
2,461 行
/*
* 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 21260 2006-03-08 23:23:57Z audit $
*
* 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 <ntddk.h>
#include <ntdddisk.h>
#include <scsi.h>
#include <include/class2.h>
#include <stdio.h>
#define NDEBUG
#include <debug.h>
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
#define VERSION "0.0.2"
#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
#define TAG_SRBT TAG('S', 'r', 'b', 'T')
#define INQUIRY_DATA_SIZE 2048
#define START_UNIT_TIMEOUT 30
/*
* FIXME:
* Create a macro, which rounds up a size value to the next multiple of two.
*/
#define SENSEINFO_ALIGNMENT 32
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
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);
static NTSTATUS STDCALL
ScsiClassCheckVerifyCompletion (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context);
/* 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);
}
/*
* @implemented
*/
NTSTATUS STDCALL
ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PCOMPLETION_CONTEXT CompletionContext;
PSCSI_REQUEST_BLOCK Srb;
CompletionContext = (PCOMPLETION_CONTEXT) Context;
Srb = &CompletionContext->Srb;
/* Release the queue if it is frozen */
if (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI &&
Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
{
ScsiClassReleaseQueue (CompletionContext->DeviceObject);
}
/* Release the completion context and the IRP */
if (Irp->MdlAddress != NULL)
{
MmUnlockPages (Irp->MdlAddress);
IoFreeMdl (Irp->MdlAddress);
Irp->MdlAddress = NULL;
}
ExFreePool (CompletionContext);
IoFreeIrp (Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*
* @implemented
*/
VOID STDCALL
ScsiClassBuildRequest(IN PDEVICE_OBJECT DeviceObject,
IN 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 = (SENSE_DATA*)ROUND_UP((ULONG_PTR)(Srb + 1), SENSEINFO_ALIGNMENT);
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);
}
/*
* @implemented
*/
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);
}
/*
* @implemented
*/
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);
}
/*
* @implemented
*/
NTSTATUS STDCALL
ScsiClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION NextStack;
PIO_STACK_LOCATION Stack;
ULONG IoControlCode;
ULONG InputBufferLength;
ULONG OutputBufferLength;
ULONG ModifiedControlCode;
PSCSI_REQUEST_BLOCK Srb;
PCDB Cdb;
PIRP SubIrp;
DPRINT("ScsiClassDeviceControl() called\n");
DeviceExtension = DeviceObject->DeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp);
IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
InputBufferLength = Stack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = Stack->Parameters.DeviceIoControl.OutputBufferLength;
if (IoControlCode == IOCTL_SCSI_GET_DUMP_POINTERS)
{
PDUMP_POINTERS DumpPointers;
if (OutputBufferLength < sizeof(DUMP_POINTERS))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?