622 lines
17 KiB
C
622 lines
17 KiB
C
|
||
/*++
|
||
|
||
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;
|
||
}
|
||
|