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;
|
||
}
|
||
|