402 lines
11 KiB
C
402 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 2000
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
pnp.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains plug and play code for the NT iSCSI port driver.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "port.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
|
|||
|
#pragma alloc_text(PAGE, iScsiPortAddDevice)
|
|||
|
#pragma alloc_text(PAGE, iScsiPortUnload)
|
|||
|
|
|||
|
#endif // ALLOC_PRAGMA
|
|||
|
|
|||
|
GUID iScsiServerGuid = iSCSI_SERVER_GUID;
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
iScsiPortAddDevice(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|||
|
)
|
|||
|
/*+++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles add-device requests for the iSCSI port driver
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - a pointer to the driver object for this device
|
|||
|
|
|||
|
PhysicalDeviceObject - a pointer to the PDO we are being added to
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if successful
|
|||
|
Appropriate NTStatus code on error
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
PDEVICE_OBJECT newDeviceObject;
|
|||
|
PDEVICE_OBJECT lowerDevice;
|
|||
|
PISCSI_FDO_EXTENSION fdoExtension;
|
|||
|
PCOMMON_EXTENSION commonExtension;
|
|||
|
NTSTATUS status;
|
|||
|
UNICODE_STRING deviceName;
|
|||
|
UNICODE_STRING dosUnicodeString;
|
|||
|
|
|||
|
//
|
|||
|
// Claim the device
|
|||
|
//
|
|||
|
lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
|
|||
|
status = iScsiPortClaimDevice(lowerDevice, FALSE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((0, "Failed to claim the device. Status : %x\n",
|
|||
|
status));
|
|||
|
ObDereferenceObject(lowerDevice);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&deviceName, ISCSI_DEVICE_NAME);
|
|||
|
status = IoCreateDevice(DriverObject,
|
|||
|
sizeof(ISCSI_FDO_EXTENSION),
|
|||
|
&deviceName,
|
|||
|
FILE_DEVICE_NETWORK,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&deviceObject);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((0, "iScsiPortAddDevice failed. Status %lx\n",
|
|||
|
status));
|
|||
|
|
|||
|
ObDereferenceObject(lowerDevice);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
newDeviceObject = IoAttachDeviceToDeviceStack(deviceObject,
|
|||
|
PhysicalDeviceObject);
|
|||
|
if (newDeviceObject == NULL) {
|
|||
|
DebugPrint((0,
|
|||
|
"IoAttachDeviceToDeviceStack failed in iScsiAddDevice\n"));
|
|||
|
IoDeleteDevice(deviceObject);
|
|||
|
|
|||
|
ObDereferenceObject(lowerDevice);
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|||
|
|
|||
|
fdoExtension = deviceObject->DeviceExtension;
|
|||
|
commonExtension = &(fdoExtension->CommonExtension);
|
|||
|
|
|||
|
RtlZeroMemory(fdoExtension, sizeof(ISCSI_FDO_EXTENSION));
|
|||
|
|
|||
|
fdoExtension->LowerPdo = PhysicalDeviceObject;
|
|||
|
commonExtension->LowerDeviceObject = newDeviceObject;
|
|||
|
|
|||
|
commonExtension->DeviceObject = deviceObject;
|
|||
|
commonExtension->IsPdo = FALSE;
|
|||
|
commonExtension->CurrentPnpState = 0xff;
|
|||
|
commonExtension->PreviousPnpState = 0xff;
|
|||
|
commonExtension->IsServerNodeSetup = FALSE;
|
|||
|
|
|||
|
commonExtension->IsRemoved = NO_REMOVE;
|
|||
|
commonExtension->RemoveLock = 0;
|
|||
|
KeInitializeEvent(&(commonExtension->RemoveEvent),
|
|||
|
SynchronizationEvent,
|
|||
|
FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Create the dos device name.
|
|||
|
//
|
|||
|
if ((commonExtension->DosNameCreated) == FALSE) {
|
|||
|
RtlInitUnicodeString(&dosUnicodeString,
|
|||
|
ISCSI_DOS_DEVICE_NAME);
|
|||
|
|
|||
|
//
|
|||
|
// Recreate the deviceName
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&deviceName,
|
|||
|
ISCSI_DEVICE_NAME);
|
|||
|
|
|||
|
status = IoAssignArcName(&dosUnicodeString,
|
|||
|
&deviceName);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
commonExtension->DosNameCreated = TRUE;
|
|||
|
} else {
|
|||
|
commonExtension->DosNameCreated = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the entry points for this device
|
|||
|
//
|
|||
|
iScsiPortInitializeDispatchTables();
|
|||
|
commonExtension->MajorFunction = FdoMajorFunctionTable;
|
|||
|
|
|||
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
|
|||
|
ObDereferenceObject(lowerDevice);
|
|||
|
|
|||
|
DebugPrint((3, "Add Device was successful\n"));
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
iScsiPortUnload(
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
)
|
|||
|
{
|
|||
|
PISCSIPORT_DRIVER_EXTENSION driverExtension;
|
|||
|
|
|||
|
driverExtension = IoGetDriverObjectExtension( DriverObject,
|
|||
|
(PVOID)ISCSI_TAG_DRIVER_EXTENSION);
|
|||
|
if (driverExtension != NULL) {
|
|||
|
ExFreePool(driverExtension->RegistryPath.Buffer);
|
|||
|
driverExtension->RegistryPath.Buffer = NULL;
|
|||
|
driverExtension->RegistryPath.Length = 0;
|
|||
|
driverExtension->RegistryPath.MaximumLength = 0;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
iScsiPortFdoPnp(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
|||
|
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
ULONG isRemoved;
|
|||
|
BOOLEAN forwardIrp = FALSE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
DebugPrint((3, "FdoPnp for DeviceObject %x, Irp %x, MinorFunction %x\n",
|
|||
|
DeviceObject, Irp, (irpStack->MinorFunction)));
|
|||
|
|
|||
|
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 (irpStack->MinorFunction) {
|
|||
|
case IRP_MN_START_DEVICE: {
|
|||
|
|
|||
|
status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
RtlInitUnicodeString(&(fdoExtension->IScsiInterfaceName), NULL);
|
|||
|
status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
|
|||
|
(LPGUID) &iScsiServerGuid,
|
|||
|
NULL,
|
|||
|
&(fdoExtension->IScsiInterfaceName));
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
RtlInitUnicodeString(&(fdoExtension->IScsiInterfaceName), NULL);
|
|||
|
} else {
|
|||
|
status = IoSetDeviceInterfaceState(&(fdoExtension->IScsiInterfaceName),
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((3, "Status from StartDevice : %x\n",
|
|||
|
status));
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IRP_MN_QUERY_STOP_DEVICE: {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
forwardIrp = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IRP_MN_CANCEL_STOP_DEVICE: {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
forwardIrp = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IRP_MN_STOP_DEVICE: {
|
|||
|
|
|||
|
//
|
|||
|
// Should stop the network and set state here
|
|||
|
//
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
if (commonExtension->IsServerNodeSetup) {
|
|||
|
status = iSpStopNetwork(DeviceObject);
|
|||
|
commonExtension->IsServerNodeSetup = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
|
|||
|
Irp);
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IRP_MN_QUERY_REMOVE_DEVICE: {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
forwardIrp = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IRP_MN_CANCEL_REMOVE_DEVICE: {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
forwardIrp = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case IRP_MN_REMOVE_DEVICE: {
|
|||
|
|
|||
|
//
|
|||
|
// If network node hasn't been released yet,
|
|||
|
// release it now
|
|||
|
//
|
|||
|
if (commonExtension->IsServerNodeSetup) {
|
|||
|
iSpStopNetwork(DeviceObject);
|
|||
|
commonExtension->IsServerNodeSetup = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|||
|
commonExtension->IsRemoved = REMOVE_PENDING;
|
|||
|
|
|||
|
DebugPrint((0, "Waiting for remove event.\n"));
|
|||
|
KeWaitForSingleObject(&(commonExtension->RemoveEvent),
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
DebugPrint((0, "Will process remove now.\n"));
|
|||
|
|
|||
|
status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
if ((fdoExtension->IScsiInterfaceName.Buffer) != NULL) {
|
|||
|
IoSetDeviceInterfaceState(&(fdoExtension->IScsiInterfaceName),
|
|||
|
FALSE);
|
|||
|
RtlFreeUnicodeString(&(fdoExtension->IScsiInterfaceName));
|
|||
|
RtlInitUnicodeString(&(fdoExtension->IScsiInterfaceName), NULL);
|
|||
|
}
|
|||
|
|
|||
|
if (fdoExtension->ServerNodeInfo) {
|
|||
|
ExFreePool(fdoExtension->ServerNodeInfo);
|
|||
|
fdoExtension->ServerNodeInfo = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (commonExtension->DosNameCreated) {
|
|||
|
UNICODE_STRING dosDeviceName;
|
|||
|
RtlInitUnicodeString(&dosDeviceName,
|
|||
|
ISCSI_DOS_DEVICE_NAME);
|
|||
|
IoDeleteSymbolicLink(&dosDeviceName);
|
|||
|
commonExtension->DosNameCreated = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
IoDetachDevice(commonExtension->LowerDeviceObject);
|
|||
|
|
|||
|
IoDeleteDevice(commonExtension->DeviceObject);
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default: {
|
|||
|
forwardIrp = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
} // switch (irpStack->MinorFunction)
|
|||
|
|
|||
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|||
|
|
|||
|
if (forwardIrp == TRUE) {
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(commonExtension->LowerDeviceObject,
|
|||
|
Irp);
|
|||
|
} else {
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
iSpSendIrpSynchronous(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
KEVENT event;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (DeviceObject == NULL) {
|
|||
|
DebugPrint((0, "DeviceObject NULL. Irp %x\n",
|
|||
|
Irp));
|
|||
|
return Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
IoSetCompletionRoutine(Irp,
|
|||
|
iSpSetEvent,
|
|||
|
&event,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE);
|
|||
|
status = IoCallDriver(DeviceObject, Irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|