Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

621 lines
17 KiB

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