/*++ Copyright (C) Microsoft Corporation, 2000 Module Name: pdo.c Abstract: This file contains PDO routines Environment: kernel mode only Revision History: --*/ #include "port.h" NTSTATUS iScsiPortPdoDeviceControl( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PISCSI_PDO_EXTENSION pdoExtension = Pdo->DeviceExtension; PCOMMON_EXTENSION commonExtension = Pdo->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ULONG ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; NTSTATUS status; ULONG isRemoved; isRemoved = iSpAcquireRemoveLock(Pdo, Irp); if(isRemoved) { iSpReleaseRemoveLock(Pdo, Irp); Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DEVICE_DOES_NOT_EXIST; } DebugPrint((3, "PDO DeviceControl - IO Control Code : 0x%08x\n", ioControlCode)); switch (ioControlCode) { case IOCTL_STORAGE_QUERY_PROPERTY: { // // Validate the query // PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer; if(irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) { status = STATUS_INVALID_PARAMETER; break; } status = iScsiPortQueryProperty(Pdo, Irp); return status; break; } case IOCTL_SCSI_GET_IP_ADDRESS: { PISCSI_IP_ADDRESS iScsiAddress = Irp->AssociatedIrp.SystemBuffer; if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ISCSI_IP_ADDRESS)) { status = STATUS_BUFFER_TOO_SMALL; break; } iScsiAddress->IPAddress = pdoExtension->TargetIPAddress; iScsiAddress->PortNumber = pdoExtension->TargetPortNumber; Irp->IoStatus.Information = sizeof(ISCSI_IP_ADDRESS); status = STATUS_SUCCESS; break; } case IOCTL_SCSI_GET_ADDRESS: { PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer; if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SCSI_ADDRESS)) { status = STATUS_BUFFER_TOO_SMALL; break; } scsiAddress->Length = sizeof(PSCSI_ADDRESS); scsiAddress->PortNumber = (UCHAR) pdoExtension->PortNumber; scsiAddress->PathId = pdoExtension->PathId; scsiAddress->TargetId = pdoExtension->TargetId; scsiAddress->Lun = pdoExtension->Lun; Irp->IoStatus.Information = sizeof(SCSI_ADDRESS); status = STATUS_SUCCESS; break; } default: { IoSkipCurrentIrpStackLocation(Irp); iSpReleaseRemoveLock(Pdo, Irp); return IoCallDriver(commonExtension->LowerDeviceObject, Irp); } } // switch (ioControlCode) iSpReleaseRemoveLock(Pdo, Irp); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } NTSTATUS iScsiPortPdoPnp( IN PDEVICE_OBJECT LogicalUnit, IN PIRP Irp ) { PISCSI_PDO_EXTENSION pdoExtension = LogicalUnit->DeviceExtension; PCOMMON_EXTENSION commonExtension = LogicalUnit->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; ULONG isRemoved; isRemoved = iSpAcquireRemoveLock(LogicalUnit, Irp); if(isRemoved) { iSpReleaseRemoveLock(LogicalUnit, Irp); Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DEVICE_DOES_NOT_EXIST; } DebugPrint((1, "PDO PnP - Minorfunction Code : 0x%x\n", irpStack->MinorFunction)); switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: { commonExtension->CurrentPnpState = IRP_MN_START_DEVICE; commonExtension->PreviousPnpState = 0xff; commonExtension->IsInitialized = TRUE; // // Make up numbers here // pdoExtension->PortNumber = 5; pdoExtension->PathId = 0; // // N.B. TargetId is set in iSpInitializeLocalNodes // routine when the PDO is created. // pdoExtension->Lun = 0; Irp->IoStatus.Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_DEVICE_RELATIONS: { PDEVICE_RELATIONS deviceRelations; if(irpStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) { DebugPrint((1, "Not TargetDevicesRelations for PDO\n")); break; } // // DEVICE_RELATIONS definition contains one object pointer. // deviceRelations = iSpAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS), ISCSI_TAG_DEVICE_RELATIONS); if(deviceRelations == NULL) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(deviceRelations, sizeof(DEVICE_RELATIONS)); deviceRelations->Count = 1; deviceRelations->Objects[0] = LogicalUnit; ObReferenceObject(deviceRelations->Objects[0]); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; DebugPrint((1, "Completing QDR for PDO successfully\n")); break; } case IRP_MN_QUERY_PNP_DEVICE_STATE: { Irp->IoStatus.Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_DEVICE_TEXT: { Irp->IoStatus.Status = iSpQueryDeviceText( LogicalUnit, irpStack->Parameters.QueryDeviceText.DeviceTextType, irpStack->Parameters.QueryDeviceText.LocaleId, (PWSTR *) &Irp->IoStatus.Information ); break; } case IRP_MN_QUERY_ID: { UCHAR rawIdString[64] = "UNKNOWN ID TYPE"; ANSI_STRING ansiIdString; UNICODE_STRING unicodeIdString; BOOLEAN multiStrings; PINQUIRYDATA inquiryData = &(pdoExtension->InquiryData); if ((pdoExtension->InquiryDataInitialized) == FALSE) { DebugPrint((3, "PdoPnp : Will obtain inquiry data\n")); status = IssueInquiry(LogicalUnit); if (!NT_SUCCESS(status)) { DebugPrint((1, "Failed to get inquiry data. Status : %x\n", status)); Irp->IoStatus.Status = status; iSpReleaseRemoveLock(LogicalUnit, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } else { DebugPrint((3, "PdoPnp : Obtained Inquiry data.\n")); } } // // We've been asked for the id of one of the physical device objects // DebugPrint((3, "PDO PnP: Got IRP_MN_QUERY_ID\n")); RtlInitUnicodeString(&unicodeIdString, NULL); RtlInitAnsiString(&ansiIdString, NULL); switch(irpStack->Parameters.QueryId.IdType) { case BusQueryDeviceID: { DebugPrint((3, "BusQueryDeviceID\n")); status = iScsiPortGetDeviceId(LogicalUnit, &unicodeIdString); multiStrings = FALSE; break; } case BusQueryInstanceID: { DebugPrint((3, "BusQueryInstanceID\n")); status = iScsiPortGetInstanceId(LogicalUnit, &unicodeIdString); multiStrings = FALSE; break; } case BusQueryHardwareIDs: { DebugPrint((3, "BusQueryHardwareIDs\n")); status = iScsiPortGetHardwareIds( LogicalUnit->DriverObject, &(pdoExtension->InquiryData), &unicodeIdString); multiStrings = TRUE; break; } case BusQueryCompatibleIDs: { DebugPrint((3, "BusQueryCompatibleIDs\n")); status = iScsiPortGetCompatibleIds( LogicalUnit->DriverObject, &(pdoExtension->InquiryData), &unicodeIdString); multiStrings = TRUE; break; } default: { status = Irp->IoStatus.Status; Irp->IoStatus.Information = 0; break; } } Irp->IoStatus.Status = status; if(NT_SUCCESS(status)) { PWCHAR idString; DebugPrint((3, "Query ID successful\n")); // // fix up all invalid characters // idString = unicodeIdString.Buffer; while (*idString) { if ((*idString <= L' ') || (*idString > (WCHAR)0x7F) || (*idString == L',')) { *idString = L'_'; } idString++; if ((*idString == L'\0') && multiStrings) { idString++; } } Irp->IoStatus.Information = (ULONG_PTR) unicodeIdString.Buffer; } else { DebugPrint((1, "Query ID failed\n")); Irp->IoStatus.Information = (ULONG_PTR) NULL; } iSpReleaseRemoveLock(LogicalUnit, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; break; } case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: { status = STATUS_SUCCESS; Irp->IoStatus.Information = (ULONG_PTR) NULL; break; } case IRP_MN_REMOVE_DEVICE: { PISCSI_FDO_EXTENSION fdoExtension; ULONG inx; BOOLEAN foundPDO = FALSE; iSpReleaseRemoveLock(LogicalUnit, Irp); // // Remove this PDO from FDO's PDO List // fdoExtension = pdoExtension->ParentFDOExtension; inx = 0; while (inx < (fdoExtension->NumberOfTargets)) { if (fdoExtension->PDOList[inx] == LogicalUnit) { foundPDO = TRUE; break; } inx++; } if (foundPDO == TRUE) { DebugPrint((1, "Found the PDO : 0x%x\n", LogicalUnit)); pdoExtension->IsClaimed = FALSE; commonExtension->IsRemoved = REMOVE_PENDING; if ((pdoExtension->IsMissing == TRUE) && (pdoExtension->IsEnumerated == FALSE)) { (fdoExtension->NumberOfTargets)--; DebugPrint((0, "Will remove the PDO\n")); commonExtension->IsRemoved = REMOVE_COMPLETE; pdoExtension->PathId = 0xff; pdoExtension->TargetId = 0xff; pdoExtension->Lun = 0xff; DebugPrint((0, "Query remove received for the PDO\n")); iSpStopNetwork(LogicalUnit); IoDeleteDevice(LogicalUnit); } else { DebugPrint((0, "Will not delete the PDO\n")); commonExtension->IsRemoved = NO_REMOVE; } status = STATUS_SUCCESS; } else { DebugPrint((0, "Did not find the PDO\n")); status = STATUS_NO_SUCH_DEVICE; } Irp->IoStatus.Status = status; Irp->IoStatus.Information = (ULONG_PTR) NULL; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: { DebugPrint((0, "Query remove or query stop received\n")); Irp->IoStatus.Status = STATUS_SUCCESS; break; } default: { DebugPrint((1, "Not handling PDO MN Code - 0x%x. Status - 0x%08x\n", (irpStack->MinorFunction), (Irp->IoStatus.Status))); } } iSpReleaseRemoveLock(LogicalUnit, Irp); status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } NTSTATUS iScsiPortPdoDispatch( IN PDEVICE_OBJECT LogicalUnit, IN PIRP Irp ) { PISCSI_PDO_EXTENSION pdoExtension = LogicalUnit->DeviceExtension; PCOMMON_EXTENSION commonExtension = LogicalUnit->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb; NTSTATUS status; ULONG isRemoved; BOOLEAN sendCommandToServer = FALSE; DebugPrint((3, "PdoDispatch - SRB Function : 0x%x\n", srb->Function)); isRemoved = iSpAcquireRemoveLock(LogicalUnit, Irp); if (isRemoved && !IS_CLEANUP_REQUEST(irpStack) && (srb->Function != SRB_FUNCTION_CLAIM_DEVICE)) { iSpReleaseRemoveLock(LogicalUnit, Irp); Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DEVICE_DOES_NOT_EXIST; } switch(srb->Function) { case SRB_FUNCTION_ABORT_COMMAND: { DebugPrint((1, "Not handling abort command\n")); status = STATUS_NOT_SUPPORTED; break; } case SRB_FUNCTION_CLAIM_DEVICE: case SRB_FUNCTION_REMOVE_DEVICE: { status = iSpClaimLogicalUnit( pdoExtension->CommonExtension.LowerDeviceObject->DeviceExtension, pdoExtension, Irp); break; } case SRB_FUNCTION_RELEASE_QUEUE: case SRB_FUNCTION_FLUSH_QUEUE: 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_RESET_BUS: 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_EXECUTE_SCSI: { // // Mark Irp status pending. // IoMarkIrpPending(Irp); sendCommandToServer = TRUE; status = STATUS_PENDING; break; } default: { // // Unsupported SRB function. // DebugPrint((0, "PdoDispatch: Unsupported function, SRB %p\n", srb)); srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; break; } } if (sendCommandToServer == FALSE) { DebugPrint((1, "Not sending the command to the server\n")); iSpReleaseRemoveLock(LogicalUnit, Irp); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } DebugPrint((3, "Will send the command to the server\n")); status = iSpSendScsiCommand(LogicalUnit, Irp); if (NT_SUCCESS(status)) { DebugPrint((3, "Command successfully sent to the server.\n")); status = STATUS_PENDING; } else { // // In case of error, the lock will be released and the irp will // be completed in iSpSendScsiCommand routine. // DebugPrint((1, "Failed to send the command. Status : %x\n", status)); } return status; } NTSTATUS iScsiPortPdoCreateClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { ULONG isRemoved; NTSTATUS status = STATUS_SUCCESS; isRemoved = iSpAcquireRemoveLock(DeviceObject, Irp); if(IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_CREATE) { if(isRemoved) { status = STATUS_DEVICE_DOES_NOT_EXIST; } } Irp->IoStatus.Status = status; iSpReleaseRemoveLock(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }