754 lines
21 KiB
C
754 lines
21 KiB
C
|
||
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 2000
|
||
|
||
Module Name:
|
||
|
||
enum.c
|
||
|
||
Abstract:
|
||
|
||
This file contains device enumeration routines
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "port.h"
|
||
|
||
|
||
VOID
|
||
iSpEnumerateDevicesAsynchronous(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
PISCSI_FDO_EXTENSION fdoExtension;
|
||
PCOMMON_EXTENSION commonExtension;
|
||
PISCSI_CONNECTION iScsiConnection;
|
||
PIRP Irp;
|
||
LARGE_INTEGER Timeout;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
UCHAR oldIrql;
|
||
|
||
fdoExtension = (PISCSI_FDO_EXTENSION) Context;
|
||
commonExtension = DeviceObject->DeviceExtension;
|
||
|
||
IoFreeWorkItem(fdoExtension->EnumerationWorkItem);
|
||
fdoExtension->EnumerationWorkItem = NULL;
|
||
|
||
//
|
||
// Local network nodes should be setup at this point.
|
||
// If not, fail the enumeration irp
|
||
//
|
||
if ((fdoExtension->LocalNodesInitialized) == TRUE) {
|
||
PDEVICE_OBJECT pdo;
|
||
PISCSI_PDO_EXTENSION pdoExtension;
|
||
ULONG inx;
|
||
|
||
DebugPrint((3, "Number of targets : %d\n",
|
||
(fdoExtension->NumberOfTargets)));
|
||
|
||
fdoExtension->TargetsYetToRespond = fdoExtension->NumberOfTargets;
|
||
|
||
for (inx = 0; inx < (fdoExtension->NumberOfTargets); inx++) {
|
||
|
||
pdo = fdoExtension->PDOList[inx];
|
||
pdoExtension = (PISCSI_PDO_EXTENSION)(pdo->DeviceExtension);
|
||
iScsiConnection = pdoExtension->ClientNodeInfo;
|
||
|
||
DebugPrint((3, "Will connect to the server\n"));
|
||
|
||
pdoExtension->LogonTickCount = 0;
|
||
|
||
//
|
||
// Connection timeout is 60 seconds. Is this enough???
|
||
//
|
||
Timeout.QuadPart = -600000000;
|
||
status = iSpTdiConnect(iScsiConnection->ConnectionDeviceObject,
|
||
iScsiConnection->ConnectionFileObject,
|
||
pdoExtension->TargetIPAddress,
|
||
htons(pdoExtension->TargetPortNumber),
|
||
Timeout);
|
||
if (NT_SUCCESS(status)) {
|
||
DebugPrint((3, "Connected to the server\n"));
|
||
|
||
iScsiConnection->ConnectionState = ConnectionStateConnected;
|
||
|
||
pdoExtension->CurrentProtocolState = PSLogonInProgress;
|
||
|
||
DebugPrint((3, "Will send logon packet\n"));
|
||
|
||
status = iSpSendLoginCommand(pdoExtension);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
pdoExtension->LogonTickCount = 0;
|
||
|
||
DebugPrint((3, "Login command sent successfully\n"));
|
||
} else {
|
||
|
||
LARGE_INTEGER disconnectTimeout;
|
||
|
||
DebugPrint((1,
|
||
"Send failed for logon. Status : %x\n",
|
||
status));
|
||
|
||
InterlockedDecrement(&(fdoExtension->TargetsYetToRespond));
|
||
pdoExtension->CurrentProtocolState = PSLogonFailed;
|
||
|
||
disconnectTimeout.QuadPart = -100000000L;
|
||
|
||
iScsiConnection->ConnectionState = ConnectionStateStopping;
|
||
|
||
status = iSpTdiDisconnect(iScsiConnection->ConnectionDeviceObject,
|
||
iScsiConnection->ConnectionFileObject,
|
||
TDI_DISCONNECT_RELEASE,
|
||
iSpTdiCompletionRoutine,
|
||
iScsiConnection,
|
||
disconnectTimeout);
|
||
|
||
DebugPrint((3, "iSpTdiDisconnect returned : %x\n",
|
||
status));
|
||
|
||
}
|
||
} else {
|
||
|
||
DebugPrint((1, "Could not connect to server. Status : %x\n",
|
||
status));
|
||
pdoExtension->CurrentProtocolState = PSConnectToServerFailed;
|
||
InterlockedDecrement(&(fdoExtension->TargetsYetToRespond));
|
||
}
|
||
}
|
||
|
||
KeAcquireSpinLock(&(fdoExtension->EnumerationSpinLock),
|
||
&oldIrql);
|
||
|
||
//
|
||
// Launch the enum completion thread if all targets have
|
||
// responded or none could be contacted.
|
||
//
|
||
if (((fdoExtension->TargetsYetToRespond) == 0) &&
|
||
((fdoExtension->EnumerationThreadLaunched) == FALSE)) {
|
||
|
||
DebugPrint((0,
|
||
"All or no targets responded. Will complete QDR\n"));
|
||
|
||
iSpLaunchEnumerationCompletion(fdoExtension);
|
||
|
||
}
|
||
|
||
KeReleaseSpinLock(&(fdoExtension->EnumerationSpinLock),
|
||
oldIrql);
|
||
|
||
} else {
|
||
DebugPrint((1, "iSpEnumerateDevices : Client node not setup yet\n"));
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
|
||
Irp = fdoExtension->EnumerationIrp;
|
||
fdoExtension->EnumerationIrp = NULL;
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = 0L;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/*
|
||
|
||
NTSTATUS
|
||
iSpPerformDeviceEnumeration(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp
|
||
)
|
||
{
|
||
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
||
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||
PISCSI_CONNECTION iScsiConnection = fdoExtension->ClientNodeInfo;
|
||
PISCSI_LOGIN_COMMAND iscsiLoginCommand;
|
||
LARGE_INTEGER disconnectTimeout;
|
||
NTSTATUS status;
|
||
USHORT connectionID;
|
||
|
||
ASSERT((iScsiConnection != NULL));
|
||
ASSERT((iScsiConnection->Type) == ISCSI_CONNECTION_TYPE);
|
||
ASSERT((iScsiConnection->ConnectionState) == ConnectionStateConnected);
|
||
|
||
if ((fdoExtension->CurrentProtocolState) != PSConnectedToServer) {
|
||
DebugPrint((1, "Probably already logged on. CurrentState : %d\n",
|
||
(fdoExtension->CurrentProtocolState)));
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// First send logon packet
|
||
//
|
||
fdoExtension->CurrentIrp = Irp;
|
||
fdoExtension->CurrentProtocolState = PSLogonInProgress;
|
||
|
||
status = iSpSendLoginCommand(fdoExtension);
|
||
if (NT_SUCCESS(status)) {
|
||
DebugPrint((3, "Login command sent successfully\n"));
|
||
} else {
|
||
DebugPrint((1, "Send failed for logon. Status : %x\n", status));
|
||
|
||
fdoExtension->CurrentIrp = NULL;
|
||
fdoExtension->CurrentProtocolState = PSLogonFailed;
|
||
|
||
disconnectTimeout.QuadPart = -100000000L;
|
||
|
||
iScsiConnection->ConnectionState = ConnectionStateStopping;
|
||
|
||
status = iSpTdiDisconnect(iScsiConnection->ConnectionDeviceObject,
|
||
iScsiConnection->ConnectionFileObject,
|
||
TDI_DISCONNECT_RELEASE,
|
||
iSpTdiCompletionRoutine,
|
||
iScsiConnection,
|
||
disconnectTimeout);
|
||
|
||
DebugPrint((3, "iSpTdiDisconnect returned : %x\n",
|
||
status));
|
||
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// QDR Irp will be completed upon receipt of login response
|
||
//
|
||
// ISSUE : nramas : 12/24/2000
|
||
// Should have a timer here to take care of the case where
|
||
// the server fails to send logon response.
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
*/
|
||
|
||
|
||
NTSTATUS
|
||
iSpQueryDeviceRelationsCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
||
PISCSI_PDO_EXTENSION pdoExtension;
|
||
|
||
PCOMMON_EXTENSION commonExtension;
|
||
PISCSI_CONNECTION iScsiConnection;
|
||
PISCSI_LOGIN_RESPONSE loginResponse;
|
||
PIRP Irp;
|
||
PDEVICE_OBJECT pdo;
|
||
PDEVICE_RELATIONS deviceRelations;
|
||
|
||
PACTIVE_REQUESTS activeClientRequests = NULL;
|
||
|
||
ULONG relationSize;
|
||
ULONG maxCmdRN = 0;
|
||
ULONG inx;
|
||
ULONG targetIndex;
|
||
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
IoFreeWorkItem((PIO_WORKITEM) Context);
|
||
|
||
Irp = fdoExtension->EnumerationIrp;
|
||
fdoExtension->EnumerationIrp = NULL;
|
||
|
||
relationSize = sizeof(DEVICE_RELATIONS) +
|
||
((fdoExtension->NumberOfTargets) * sizeof(PDEVICE_OBJECT));
|
||
|
||
deviceRelations = iSpAllocatePool(PagedPool,
|
||
relationSize,
|
||
ISCSI_TAG_DEVICE_RELATIONS);
|
||
if (deviceRelations == NULL) {
|
||
DebugPrint((1, "Failed to allocate memory for device relations\n"));
|
||
|
||
for (inx = 0; inx < (fdoExtension->NumberOfTargets); inx++) {
|
||
pdo = fdoExtension->PDOList[inx];
|
||
|
||
iSpStopNetwork(pdo);
|
||
|
||
IoDeleteDevice(pdo);
|
||
|
||
fdoExtension->PDOList[inx] = NULL;
|
||
}
|
||
|
||
fdoExtension->NumberOfTargets = 0;
|
||
|
||
fdoExtension->LocalNodesInitialized = FALSE;
|
||
|
||
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
Irp->IoStatus.Information = 0L;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
deviceRelations->Count = 0;
|
||
|
||
targetIndex = 0;
|
||
for (inx = 0; inx < (fdoExtension->NumberOfTargets); inx++) {
|
||
|
||
pdo = fdoExtension->PDOList[inx];
|
||
|
||
pdoExtension = (PISCSI_PDO_EXTENSION)(pdo->DeviceExtension);
|
||
|
||
iScsiConnection = pdoExtension->ClientNodeInfo;
|
||
|
||
if ((pdoExtension->CurrentProtocolState) == PSLogonSucceeded) {
|
||
|
||
loginResponse = (PISCSI_LOGIN_RESPONSE) (iScsiConnection->IScsiPacket);
|
||
|
||
//
|
||
// Allocate memory to keep active requests. Size of this
|
||
// array is the value returned in MaxCmdRN field
|
||
//
|
||
GetUlongFromArray((loginResponse->InitStatRN),
|
||
(iScsiConnection->CurrentStatusRefNum));
|
||
|
||
GetUlongFromArray((loginResponse->ExpCmdRN),
|
||
(iScsiConnection->CommandRefNum));
|
||
|
||
GetUlongFromArray((loginResponse->MaxCmdRN), maxCmdRN);
|
||
|
||
iScsiConnection->MaxCommandRefNum = maxCmdRN;
|
||
|
||
DebugPrint((1, "InitStatRN : %d, ExpCmdRN : %d, MaxCmdRN : %d\n",
|
||
(iScsiConnection->CurrentStatusRefNum),
|
||
(iScsiConnection->CommandRefNum),
|
||
maxCmdRN));
|
||
|
||
ASSERT((maxCmdRN != 0));
|
||
|
||
ASSERT(((iScsiConnection->CommandRefNum) <= maxCmdRN));
|
||
|
||
iScsiConnection->NumberOfReqsInProgress = 0;
|
||
|
||
iScsiConnection->ReceiveState = ReceiveHeader;
|
||
|
||
iScsiConnection->MaxPendingRequests = maxCmdRN;
|
||
|
||
activeClientRequests = iSpAllocatePool(
|
||
NonPagedPool,
|
||
(sizeof(ACTIVE_REQUESTS) * (maxCmdRN + 1)),
|
||
ISCSI_TAG_ACTIVE_REQ);
|
||
|
||
if (activeClientRequests == NULL) {
|
||
|
||
DebugPrint((1, "Failed to allocate ActiveClientRequests array\n"));
|
||
|
||
iSpStopNetwork(pdo);
|
||
|
||
IoDeleteDevice(pdo);
|
||
|
||
fdoExtension->PDOList[inx] = NULL;
|
||
} else {
|
||
RtlZeroMemory(activeClientRequests,
|
||
(sizeof(ACTIVE_REQUESTS) * (maxCmdRN + 1)));
|
||
|
||
commonExtension = pdo->DeviceExtension;
|
||
pdoExtension = pdo->DeviceExtension;
|
||
pdo->StackSize = 1;
|
||
pdo->Flags |= (DO_BUS_ENUMERATED_DEVICE | DO_DIRECT_IO);
|
||
pdo->AlignmentRequirement = DeviceObject->AlignmentRequirement;
|
||
|
||
commonExtension->DeviceObject = pdo;
|
||
commonExtension->LowerDeviceObject = DeviceObject;
|
||
commonExtension->IsPdo = TRUE;
|
||
commonExtension->MajorFunction = PdoMajorFunctionTable;
|
||
commonExtension->RemoveLock = 0;
|
||
commonExtension->CurrentPnpState = 0xff;
|
||
commonExtension->PreviousPnpState = 0xff;
|
||
|
||
iScsiConnection->ActiveClientRequests = activeClientRequests;
|
||
|
||
//
|
||
// Inquiry data will be filled when we get the
|
||
// first query id irp
|
||
//
|
||
pdoExtension->InquiryDataInitialized = FALSE;
|
||
|
||
pdoExtension->CurrentProtocolState = PSFullFeaturePhase;
|
||
|
||
pdoExtension->IsEnumerated = TRUE;
|
||
|
||
//
|
||
// Initialize the remove lock event.
|
||
//
|
||
|
||
KeInitializeEvent(
|
||
&(commonExtension->RemoveEvent),
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
//
|
||
// Initialize the request list for this PDO
|
||
//
|
||
InitializeListHead(&(iScsiConnection->RequestList));
|
||
|
||
pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
fdoExtension->PDOList[targetIndex] = pdo;
|
||
targetIndex++;
|
||
|
||
ObReferenceObject(pdo);
|
||
|
||
DebugPrint((1, "PDO %d : 0x%x\n",
|
||
(deviceRelations->Count), pdo));
|
||
|
||
deviceRelations->Objects[deviceRelations->Count] = pdo;
|
||
|
||
(deviceRelations->Count)++;
|
||
|
||
}
|
||
} else {
|
||
iSpStopNetwork(pdo);
|
||
|
||
IoDeleteDevice(pdo);
|
||
|
||
fdoExtension->PDOList[inx] = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Group all the targets to the beginning of the PDOList
|
||
//
|
||
for (inx = targetIndex; inx < MAX_TARGETS_SUPPORTED; inx++) {
|
||
fdoExtension->PDOList[inx] = NULL;
|
||
}
|
||
|
||
DebugPrint((1, "Number of PDOs reported : %d\n",
|
||
(deviceRelations->Count)));
|
||
|
||
if ((deviceRelations->Count) > 0) {
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
||
|
||
fdoExtension->EnumerationComplete = TRUE;
|
||
fdoExtension->NumberOfTargets = deviceRelations->Count;
|
||
|
||
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||
|
||
return IoCallDriver((fdoExtension->CommonExtension.LowerDeviceObject),
|
||
Irp);
|
||
} else {
|
||
DebugPrint((1, "No PDOs to report in QDR\n"));
|
||
ExFreePool(deviceRelations);
|
||
|
||
fdoExtension->NumberOfTargets = 0;
|
||
|
||
fdoExtension->LocalNodesInitialized = FALSE;
|
||
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||
Irp->IoStatus.Information = 0L;
|
||
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
IssueInquiry(
|
||
IN PDEVICE_OBJECT LogicalUnit
|
||
)
|
||
{
|
||
PISCSI_PDO_EXTENSION pdoExtension = LogicalUnit->DeviceExtension;
|
||
PIRP irp;
|
||
SCSI_REQUEST_BLOCK srb;
|
||
PCDB cdb;
|
||
PVOID dataBuffer;
|
||
PSENSE_DATA senseInfoBuffer;
|
||
|
||
UCHAR allocationLength;
|
||
ULONG bytesReturned;
|
||
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
dataBuffer = &(pdoExtension->InquiryData);
|
||
senseInfoBuffer = &(pdoExtension->InquirySenseBuffer);
|
||
|
||
irp = IoAllocateIrp((LogicalUnit->StackSize) + 1, FALSE);
|
||
if (irp == NULL) {
|
||
DebugPrint((1, "IssueInquiry : Failed to allocate IRP.\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
IoInitializeIrp(irp,
|
||
IoSizeOfIrp((LogicalUnit->StackSize) + 1),
|
||
((LogicalUnit->StackSize) + 1));
|
||
|
||
//
|
||
// Fill in SRB fields.
|
||
//
|
||
|
||
RtlZeroMemory(dataBuffer, sizeof(INQUIRYDATA));
|
||
RtlZeroMemory(senseInfoBuffer, SENSE_BUFFER_SIZE);
|
||
RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
|
||
|
||
srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
srb.Length = SCSI_REQUEST_BLOCK_SIZE;
|
||
|
||
//
|
||
// Set flags to disable synchronous negociation.
|
||
//
|
||
|
||
srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
||
|
||
//
|
||
// Set timeout to 4 seconds.
|
||
//
|
||
|
||
srb.TimeOutValue = 4;
|
||
|
||
srb.CdbLength = 6;
|
||
|
||
cdb = (PCDB)(srb.Cdb);
|
||
|
||
//
|
||
// Set CDB operation code.
|
||
//
|
||
|
||
cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY;
|
||
|
||
//
|
||
// Set allocation length to inquiry data buffer size.
|
||
//
|
||
|
||
allocationLength = sizeof(INQUIRYDATA);
|
||
|
||
cdb->CDB6INQUIRY3.AllocationLength = allocationLength;
|
||
|
||
cdb->CDB6INQUIRY3.EnableVitalProductData = FALSE;
|
||
|
||
|
||
cdb->CDB6INQUIRY3.PageCode = 0;
|
||
|
||
status = iSpSendSrbSynchronous(LogicalUnit,
|
||
&srb,
|
||
irp,
|
||
dataBuffer,
|
||
allocationLength,
|
||
senseInfoBuffer,
|
||
SENSE_BUFFER_SIZE,
|
||
&bytesReturned
|
||
);
|
||
|
||
ASSERT(bytesReturned <= allocationLength);
|
||
|
||
//
|
||
// Return the inquiry data for the device if the call was successful.
|
||
// Otherwise cleanup.
|
||
//
|
||
|
||
if(NT_SUCCESS(status)) {
|
||
|
||
pdoExtension->InquiryDataInitialized = TRUE;
|
||
|
||
DebugPrint((3, "Inquiry data obtained successfully\n"));
|
||
} else {
|
||
DebugPrint((1, "Failed to obtain inquiry data. Status : %x\n",
|
||
status));
|
||
}
|
||
|
||
IoFreeIrp(irp);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
iSpSendSrbSynchronous(
|
||
IN PDEVICE_OBJECT LogicalUnit,
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
IN PIRP Irp,
|
||
IN PVOID DataBuffer,
|
||
IN ULONG TransferLength,
|
||
IN OPTIONAL PVOID SenseInfoBuffer,
|
||
IN OPTIONAL UCHAR SenseInfoBufferLength,
|
||
OUT PULONG BytesReturned
|
||
)
|
||
{
|
||
KEVENT event;
|
||
|
||
PIO_STACK_LOCATION irpStack;
|
||
PMDL Mdl = NULL;
|
||
|
||
PSENSE_DATA senseInfo = SenseInfoBuffer;
|
||
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
if(ARGUMENT_PRESENT(DataBuffer)) {
|
||
ASSERT(TransferLength != 0);
|
||
|
||
Mdl = IoAllocateMdl(DataBuffer,
|
||
TransferLength,
|
||
FALSE,
|
||
FALSE,
|
||
NULL);
|
||
|
||
if(Mdl == NULL) {
|
||
IoFreeIrp(Irp);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
MmBuildMdlForNonPagedPool(Mdl);
|
||
Irp->MdlAddress = Mdl;
|
||
} else {
|
||
ASSERT(TransferLength == 0);
|
||
}
|
||
|
||
irpStack = IoGetNextIrpStackLocation(Irp);
|
||
|
||
//
|
||
// Mark the minor function to indicate that this is an internal scsiport
|
||
// request and that the start state of the device can be ignored.
|
||
//
|
||
|
||
irpStack->MajorFunction = IRP_MJ_SCSI;
|
||
irpStack->MinorFunction = 1;
|
||
|
||
irpStack->Parameters.Scsi.Srb = Srb;
|
||
|
||
Srb->SrbStatus = Srb->ScsiStatus = 0;
|
||
|
||
Srb->OriginalRequest = Irp;
|
||
|
||
//
|
||
// Enable auto request sense.
|
||
//
|
||
|
||
if(ARGUMENT_PRESENT(SenseInfoBuffer)) {
|
||
Srb->SenseInfoBuffer = SenseInfoBuffer;
|
||
Srb->SenseInfoBufferLength = SenseInfoBufferLength;
|
||
} else {
|
||
Srb->SenseInfoBuffer = NULL;
|
||
Srb->SenseInfoBufferLength = 0;
|
||
SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
|
||
}
|
||
|
||
if(ARGUMENT_PRESENT(Mdl)) {
|
||
Srb->DataBuffer = MmGetMdlVirtualAddress(Mdl);
|
||
Srb->DataTransferLength = TransferLength;
|
||
} else {
|
||
Srb->DataBuffer = NULL;
|
||
Srb->DataTransferLength = 0;
|
||
}
|
||
|
||
IoSetCompletionRoutine(Irp,
|
||
iSpSetEvent,
|
||
&event,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
KeEnterCriticalRegion();
|
||
|
||
status = IoCallDriver(LogicalUnit, Irp);
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
|
||
status = Irp->IoStatus.Status;
|
||
|
||
*BytesReturned = (ULONG) Irp->IoStatus.Information;
|
||
|
||
IoFreeMdl(Mdl);
|
||
|
||
KeLeaveCriticalRegion();
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
VOID
|
||
iSpTickHandler(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
PISCSI_FDO_EXTENSION fdoExtension;
|
||
PISCSI_PDO_EXTENSION pdoExtension;
|
||
PDEVICE_OBJECT pdo;
|
||
ULONG inx;
|
||
UCHAR oldIrql;
|
||
|
||
fdoExtension = (PISCSI_FDO_EXTENSION) DeviceObject->DeviceExtension;
|
||
|
||
KeAcquireSpinLock(&(fdoExtension->EnumerationSpinLock),
|
||
&oldIrql);
|
||
|
||
if ((fdoExtension->TargetsYetToRespond) > 0) {
|
||
|
||
for (inx = 0; inx < (fdoExtension->NumberOfTargets); inx++) {
|
||
|
||
pdo = fdoExtension->PDOList[inx];
|
||
if (pdo != NULL) {
|
||
|
||
pdoExtension = (PISCSI_PDO_EXTENSION) (pdo->DeviceExtension);
|
||
|
||
if ((pdoExtension->CurrentProtocolState) == PSLogonInProgress) {
|
||
(pdoExtension->LogonTickCount)++;
|
||
}
|
||
|
||
if ((pdoExtension->LogonTickCount) == MAX_LOGON_WAIT_TIME) {
|
||
|
||
DebugPrint((0, "Timeout waiting for logon response\n"));
|
||
|
||
pdoExtension->CurrentProtocolState = PSLogonTimedOut;
|
||
|
||
(fdoExtension->TargetsYetToRespond)--;
|
||
|
||
if ((fdoExtension->TargetsYetToRespond) == 0) {
|
||
|
||
DebugPrint((0,
|
||
"TickHandler : All targets responded.\n"));
|
||
|
||
iSpLaunchEnumerationCompletion(fdoExtension);
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
KeReleaseSpinLock(&(fdoExtension->EnumerationSpinLock),
|
||
oldIrql);
|
||
}
|
||
|
||
|
||
VOID
|
||
iSpLaunchEnumerationCompletion(
|
||
IN PISCSI_FDO_EXTENSION FdoExtension
|
||
)
|
||
{
|
||
PIO_WORKITEM workItem;
|
||
|
||
if ((FdoExtension->EnumerationThreadLaunched) == FALSE) {
|
||
|
||
workItem = IoAllocateWorkItem(FdoExtension->DeviceObject);
|
||
if (workItem != NULL) {
|
||
|
||
IoQueueWorkItem(workItem,
|
||
iSpQueryDeviceRelationsCompletion,
|
||
DelayedWorkQueue,
|
||
workItem);
|
||
|
||
FdoExtension->EnumerationThreadLaunched = TRUE;
|
||
}
|
||
|
||
}
|
||
}
|