windows-nt/Source/XPSP1/NT/drivers/storage/iscsiprt/server/pnp.c

402 lines
11 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}