541 lines
13 KiB
C
541 lines
13 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|
||
|