mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
540 lines
13 KiB
540 lines
13 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 2000
|
|
|
|
Module Name:
|
|
|
|
internal.c
|
|
|
|
Abstract:
|
|
|
|
This file contains internal routines
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "port.h"
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, iScsiPortFdoDeviceControl)
|
|
#pragma alloc_text(PAGE, iScsiPortFdoCreateClose)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
/*
|
|
PISCSI_PDO_EXTENSION
|
|
GetPdoExtension(
|
|
IN PISCSI_FDO_EXTENSION fdoExtension
|
|
);
|
|
*/
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortFdoDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status;
|
|
ULONG isRemoved;
|
|
ULONG ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
DebugPrint((1, "FDO DeviceControl - IO control code : 0x%08x\n",
|
|
ioControlCode));
|
|
|
|
isRemoved = iSpAcquireRemoveLock(DeviceObject, Irp);
|
|
if(isRemoved) {
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
switch (ioControlCode) {
|
|
case IOCTL_STORAGE_QUERY_PROPERTY: {
|
|
|
|
PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(STORAGE_PROPERTY_QUERY)) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This routine will release the lock and complete the irp.
|
|
//
|
|
status = iScsiPortQueryProperty(DeviceObject, Irp);
|
|
return status;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get adapter capabilities.
|
|
//
|
|
case IOCTL_SCSI_GET_CAPABILITIES: {
|
|
|
|
//
|
|
// If the output buffer is equal to the size of the a PVOID then just
|
|
// return a pointer to the buffer.
|
|
//
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
== sizeof(PVOID)) {
|
|
|
|
*((PVOID *)Irp->AssociatedIrp.SystemBuffer)
|
|
= &fdoExtension->IoScsiCapabilities;
|
|
|
|
Irp->IoStatus.Information = sizeof(PVOID);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
}
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
< sizeof(IO_SCSI_CAPABILITIES)) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
|
&fdoExtension->IoScsiCapabilities,
|
|
sizeof(IO_SCSI_CAPABILITIES));
|
|
|
|
Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT: {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SCSI_MINIPORT: {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SCSI_GET_DUMP_POINTERS: {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SCSI_RESCAN_BUS:
|
|
case IOCTL_SCSI_GET_INQUIRY_DATA: {
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
DebugPrint((1,
|
|
"iScsiPortFdoDeviceControl: Unsupported IOCTL (%x)\n",
|
|
ioControlCode));
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Set status in Irp.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortFdoDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
|
PISCSI_PDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
ULONG isRemoved;
|
|
BOOLEAN sendCommandToServer = FALSE;
|
|
|
|
//
|
|
// Should never get here. All SCSI requests are handled
|
|
// by the PDO Dispatch routine
|
|
//
|
|
DebugPrint((0, "SRB function sent to FDO Dispatch\n"));
|
|
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
/*
|
|
isRemoved = iSpAcquireRemoveLock(DeviceObject, Irp);
|
|
|
|
if (isRemoved && !IS_CLEANUP_REQUEST(irpStack)) {
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
if ((srb->Function) != SRB_FUNCTION_EXECUTE_SCSI) {
|
|
DebugPrint((1, "FdoDispatch - SRB Function : 0x%x\n",
|
|
srb->Function));
|
|
}
|
|
|
|
pdoExtension = GetPdoExtension(fdoExtension);
|
|
|
|
ASSERT(pdoExtension != NULL);
|
|
|
|
switch (srb->Function) {
|
|
|
|
case SRB_FUNCTION_SHUTDOWN:
|
|
case SRB_FUNCTION_FLUSH:
|
|
case SRB_FUNCTION_LOCK_QUEUE:
|
|
case SRB_FUNCTION_UNLOCK_QUEUE:
|
|
case SRB_FUNCTION_IO_CONTROL:
|
|
case SRB_FUNCTION_WMI: {
|
|
|
|
//
|
|
// We won't handle these functions on the client
|
|
// side for the timebeing.
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
case SRB_FUNCTION_SHUTDOWN:
|
|
case SRB_FUNCTION_FLUSH: {
|
|
|
|
//
|
|
// Send SCSIOP_SYNCHRONIZE_CACHE command
|
|
// to flush the queue
|
|
//
|
|
srb->CdbLength = 10;
|
|
srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
sendCommandToServer = TRUE;
|
|
|
|
status = STATUS_PENDING;
|
|
|
|
break;
|
|
}
|
|
|
|
case SRB_FUNCTION_EXECUTE_SCSI: {
|
|
|
|
//
|
|
// Mark Irp status pending.
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
sendCommandToServer = TRUE;
|
|
|
|
status = STATUS_PENDING;
|
|
}
|
|
|
|
case SRB_FUNCTION_RELEASE_QUEUE:
|
|
case SRB_FUNCTION_FLUSH_QUEUE: {
|
|
|
|
//
|
|
// These will be handled on the server
|
|
// side. Here, just return STATUS_SUCCESS
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
case SRB_FUNCTION_RESET_BUS: {
|
|
|
|
DebugPrint((1, "FdoDospatch : Received reset request\n"));
|
|
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
case SRB_FUNCTION_ABORT_COMMAND: {
|
|
|
|
DebugPrint((1, "FdoDispatch: SCSI Abort command\n"));
|
|
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
case SRB_FUNCTION_ATTACH_DEVICE:
|
|
case SRB_FUNCTION_CLAIM_DEVICE:
|
|
case SRB_FUNCTION_RELEASE_DEVICE: {
|
|
|
|
iSpAcquireRemoveLock((pdoExtension->CommonExtension.DeviceObject),
|
|
Irp);
|
|
|
|
status = iSpClaimLogicalUnit(fdoExtension,
|
|
pdoExtension,
|
|
Irp);
|
|
|
|
iSpReleaseRemoveLock((pdoExtension->CommonExtension.DeviceObject),
|
|
Irp);
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
|
|
//
|
|
// Found unsupported SRB function.
|
|
//
|
|
DebugPrint((1,
|
|
"FdoDispatch: Unsupported function, SRB %p\n",
|
|
srb));
|
|
|
|
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sendCommandToServer == FALSE) {
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
DebugPrint((3, "FdoDispatch : Will send the command to the server\n"));
|
|
|
|
status = iSpSendScsiCommand(DeviceObject, Irp);
|
|
|
|
//
|
|
// The lock will be released and IRP will be completed in
|
|
// iSpSendScsiCommand.
|
|
//
|
|
if (NT_SUCCESS(status)) {
|
|
DebugPrint((3,
|
|
"FdoDispatch : Command sent to the server.\n"));
|
|
status = STATUS_PENDING;
|
|
} else {
|
|
DebugPrint((1,
|
|
"FdoDispatch : Failed to send the command. Status : %x\n",
|
|
status));
|
|
}
|
|
|
|
return status;
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortFdoCreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ULONG isRemoved;
|
|
|
|
isRemoved = iSpAcquireRemoveLock(DeviceObject, Irp);
|
|
if(irpStack->MajorFunction == IRP_MJ_CREATE) {
|
|
|
|
if(isRemoved != NO_REMOVE) {
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
} else if(commonExtension->CurrentPnpState != IRP_MN_START_DEVICE) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
}
|
|
}
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iSpSetEvent(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
KeSetEvent((PKEVENT)Context, 0, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iSpClaimLogicalUnit(
|
|
IN PISCSI_FDO_EXTENSION FdoExtension,
|
|
IN PISCSI_PDO_EXTENSION PdoExtension,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
PDEVICE_OBJECT saveDevice;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugPrint((3, "Entering iSpClaimLogicalUnit\n"));
|
|
|
|
//
|
|
// Get SRB address from current IRP stack.
|
|
//
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
srb = (PSCSI_REQUEST_BLOCK) irpStack->Parameters.Others.Argument1;
|
|
|
|
if (srb->Function == SRB_FUNCTION_RELEASE_DEVICE) {
|
|
|
|
PdoExtension->IsClaimed = FALSE;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Check for a claimed device.
|
|
//
|
|
|
|
if (PdoExtension->IsClaimed) {
|
|
|
|
DebugPrint((0, "Device already claimed\n"));
|
|
srb->SrbStatus = SRB_STATUS_BUSY;
|
|
return(STATUS_DEVICE_BUSY);
|
|
}
|
|
|
|
//
|
|
// Save the current device object.
|
|
//
|
|
|
|
saveDevice = PdoExtension->CommonExtension.DeviceObject;
|
|
|
|
//
|
|
// Update the lun information based on the operation type.
|
|
//
|
|
|
|
if (srb->Function == SRB_FUNCTION_CLAIM_DEVICE) {
|
|
PdoExtension->IsClaimed = TRUE;
|
|
}
|
|
|
|
if (srb->Function == SRB_FUNCTION_ATTACH_DEVICE) {
|
|
ASSERT(FALSE);
|
|
PdoExtension->CommonExtension.DeviceObject = srb->DataBuffer;
|
|
}
|
|
|
|
srb->DataBuffer = saveDevice;
|
|
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
DebugPrint((3, "Successfully claimed the device\n"));
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
|
|
PISCSI_PDO_EXTENSION
|
|
GetPdoExtension(
|
|
IN PISCSI_FDO_EXTENSION fdoExtension
|
|
)
|
|
{
|
|
return ((fdoExtension->UpperPDO)->DeviceExtension);
|
|
}
|
|
*/
|
|
|
|
|
|
NTSTATUS
|
|
iSpProcessScsiRequest(
|
|
IN PDEVICE_OBJECT LogicalUnit,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
)
|
|
{
|
|
PISCSI_PDO_EXTENSION pdoExtension = LogicalUnit->DeviceExtension;
|
|
PIRP irp;
|
|
|
|
ULONG bytesReturned;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
irp = IoAllocateIrp((LogicalUnit->StackSize) + 1, FALSE);
|
|
if (irp == NULL) {
|
|
DebugPrint((1, "IssueInquiry : Failed to allocate IRP.\n"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
IoInitializeIrp(irp,
|
|
IoSizeOfIrp((LogicalUnit->StackSize) + 1),
|
|
((LogicalUnit->StackSize) + 1));
|
|
|
|
status = iSpSendSrbSynchronous(LogicalUnit,
|
|
Srb,
|
|
irp,
|
|
Srb->DataBuffer,
|
|
Srb->DataTransferLength,
|
|
Srb->SenseInfoBuffer,
|
|
Srb->SenseInfoBufferLength,
|
|
&bytesReturned
|
|
);
|
|
|
|
ASSERT(bytesReturned <= (Srb->DataTransferLength));
|
|
|
|
if(!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint((1, "Failed to process SRB. Status : %x\n",
|
|
status));
|
|
}
|
|
|
|
IoFreeIrp(irp);
|
|
|
|
return status;
|
|
}
|
|
|
|
|