/*++ 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; }