windows-nt/Source/XPSP1/NT/drivers/storage/iscsiprt/client/protocol.c
2020-09-26 16:20:57 +08:00

1252 lines
38 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 2000
Module Name:
protocol.c
Abstract:
This file contains iSCSI protocol related routines.
Environment:
kernel mode only
Revision History:
--*/
#include "port.h"
LONG GlobalSessionID;
LONG InitiatorSessionID;
#define ISCSI_TARGET "target:"
#define ISCSI_TARGET_LENGTH 7
#define ISCSI_USE_RTT "UseRtt:no"
#define ISCSI_USE_RTT_LENGTH 9
ULONG
iSpGetActiveClientRequestIndex(
PISCSI_CONNECTION IScsiConnection,
ULONG TaskTag
);
ULONG
iSpGetReqIndexUsingCmdRN(
PISCSI_CONNECTION IScsiConnection,
ULONG CmdRN
);
NTSTATUS
iSpSendLoginCommand(
IN PISCSI_PDO_EXTENSION PdoExtension
)
{
PISCSI_CONNECTION iScsiConnection;
PISCSI_LOGIN_COMMAND iscsiLoginCommand;
PUCHAR loginParameters;
NTSTATUS status;
ULONG bytesSent;
ULONG tempULong;
ULONG packetSize;
ULONG targetLength;
iScsiConnection = PdoExtension->ClientNodeInfo;
ASSERT((iScsiConnection != NULL));
ASSERT((iScsiConnection->Type) == ISCSI_CONNECTION_TYPE);
targetLength = strlen(PdoExtension->TargetName);
packetSize = (sizeof(ISCSI_LOGIN_COMMAND) + ISCSI_TARGET_LENGTH +
targetLength + ISCSI_USE_RTT_LENGTH + 2);
iscsiLoginCommand = iSpAllocatePool(
NonPagedPool,
packetSize,
ISCSI_TAG_LOGIN_CMD);
if (iscsiLoginCommand == NULL) {
DebugPrint((0, "Failed to allocate logon packet\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(iscsiLoginCommand,
packetSize);
iscsiLoginCommand->OpCode = ISCSIOP_LOGIN_COMMAND;
//
// No authentication performed
//
iscsiLoginCommand->LoginType = ISCSI_LOGINTYPE_NONE;
//
// Connection ID for this session
//
tempULong = InterlockedIncrement(&GlobalSessionID);
iscsiLoginCommand->ConnectionID[0] = (UCHAR) ((tempULong & 0xFF00) >> 8);
iscsiLoginCommand->ConnectionID[1] = (UCHAR) (tempULong & 0xFF);
//
// Command Reference number starting from 1
//
iscsiLoginCommand->InitCmdRN[3] = 1;
tempULong = InterlockedIncrement(&InitiatorSessionID);
iscsiLoginCommand->ISID[0] = (UCHAR) ((tempULong & 0xFF00) >> 8);
iscsiLoginCommand->ISID[1] = (UCHAR) (tempULong & 0xFF);
//
// Identifier for the target device is passed as parameters
// in the Login packet
//
// "target:<TargetName>" -- Target device name
// "UseRtt:no" -- Do NOT use RTT
//
loginParameters = (PUCHAR) (iscsiLoginCommand + 1);
RtlCopyMemory(loginParameters, ISCSI_TARGET, ISCSI_TARGET_LENGTH);
loginParameters += ISCSI_TARGET_LENGTH;
RtlCopyMemory(loginParameters, PdoExtension->TargetName, targetLength);
loginParameters += targetLength + 1;
RtlCopyMemory(loginParameters, ISCSI_USE_RTT, ISCSI_USE_RTT_LENGTH);
iscsiLoginCommand->Length[3] =
ISCSI_TARGET_LENGTH + (UCHAR) targetLength + ISCSI_USE_RTT_LENGTH + 2;
/*
{
ULONG inx0, inx1, len;
DebugPrint((1, "\n Logon Packet\n"));
len = (ISCSI_TARGET_LENGTH + targetLength +
ISCSI_USE_RTT_LENGTH + 2 + 48);
inx0 = 0;
while(inx0 < len) {
inx1 = 0;
DebugPrint((1, "\t"));
while ((inx1 < 4) &&
((inx0+inx1) < len)) {
DebugPrint((1, "0x%02x ",
((PUCHAR)iscsiLoginCommand)[inx0+inx1]));
inx1++;
}
DebugPrint((1, "\n"));
inx0 += 4;
}
DebugPrint((1, "\n"));
}
*/
//
// Save away the connection ID in our device extension
//
PdoExtension->SavedConnectionID[0] = iscsiLoginCommand->ConnectionID[0];
PdoExtension->SavedConnectionID[1] = iscsiLoginCommand->ConnectionID[1];
status = iSpSendData(iScsiConnection->ConnectionDeviceObject,
iScsiConnection->ConnectionFileObject,
iscsiLoginCommand,
packetSize,
&bytesSent);
if (NT_SUCCESS(status)) {
DebugPrint((3, "Send succeeded for logon. Bytes sent : %d\n",
bytesSent));
} else {
DebugPrint((0, "Failed to logon packet. Status : %x\n",
status));
PdoExtension->SavedConnectionID[0] = 0;
PdoExtension->SavedConnectionID[1] = 0;
}
return status;
}
NTSTATUS
iSpSendScsiCommand(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PISCSI_PDO_EXTENSION pdoExtension = NULL;
PISCSI_CONNECTION iScsiConnection = NULL;
PISCSI_SCSI_COMMAND iScsiScsiCommand = NULL;
PACTIVE_REQUESTS currentRequest;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
PVOID requestBuffer = NULL;
PVOID originalDataBuffer = NULL;
ULONG_PTR offset;
PVOID receiveBuffer = NULL;
ULONG receiveBufferSize = 0;
ULONG cmdRN;
ULONG expectedDataLen;
ULONG packetSize;
ULONG inx;
ULONG bytesSent;
NTSTATUS status;
KIRQL oldIrql;
BOOLEAN writeToDevice;
ASSERT(commonExtension->IsPdo);
pdoExtension = (PISCSI_PDO_EXTENSION)(DeviceObject->DeviceExtension);
iScsiConnection = pdoExtension->ClientNodeInfo;
if ((iScsiConnection->ConnectionState) != ConnectionStateConnected) {
DebugPrint((0, "Not connected to target. Connection State : %d\n",
(iScsiConnection->ConnectionState)));
Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
Irp->IoStatus.Information = 0L;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_DEVICE_NOT_CONNECTED;
}
ASSERT((pdoExtension->CurrentProtocolState) == PSFullFeaturePhase);
//
// Get the lock to synchronize access to iSCSI
// Connection structure
//
KeAcquireSpinLock(&(iScsiConnection->RequestLock),
&oldIrql);
if ((iScsiConnection->NumberOfReqsInProgress) >=
(iScsiConnection->MaxPendingRequests)) {
//
// Queue it to the request list for this connection
//
IoMarkIrpPending(Irp);
ExInterlockedInsertTailList(&(iScsiConnection->RequestList),
&(Irp->Tail.Overlay.ListEntry),
&(iScsiConnection->ListSpinLock));
KeReleaseSpinLock(&(iScsiConnection->RequestLock),
oldIrql);
return STATUS_PENDING;
}
expectedDataLen = 0;
writeToDevice = FALSE;
packetSize = sizeof(ISCSI_SCSI_COMMAND);
if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
expectedDataLen = srb->DataTransferLength;
} else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
//
// If we are writing to the device, the data
// is sent as immediate data
//
packetSize += srb->DataTransferLength;
writeToDevice = TRUE;
}
if (Irp->MdlAddress) {
offset = (ULONG_PTR) ((ULONG_PTR) srb->DataBuffer -
(ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress));
DebugPrint((3, "Srb DataBuffer : 0x%x, Offset into the MDL : 0x%x\n",
srb->DataBuffer, offset));
requestBuffer = MmGetSystemAddressForMdlSafe(
Irp->MdlAddress,
((Irp->RequestorMode == KernelMode) ?
HighPagePriority :
NormalPagePriority));
if (requestBuffer != NULL) {
UCHAR readChar;
//
// Save the original DataBuffer passed in the SRB
//
originalDataBuffer = srb->DataBuffer;
DebugPrint((3, "SendCommand : Original DataBuffer - 0x%08x\n",
originalDataBuffer));
srb->DataBuffer = (PVOID) ((ULONG_PTR) requestBuffer +
(ULONG_PTR) offset);
//
// This is for catching the case where the Srb DataBuffer
// we have generated is not valid
//
readChar = *((PUCHAR)(srb->DataBuffer));
DebugPrint((3,
"OpCode : %d, SRB DataBuffer : %x. ReadChar : %d\n",
srb->Cdb[0],
srb->DataBuffer,
readChar));
DebugPrint((3, "System address for requestBuffer : 0x%08x\n",
requestBuffer));
} else {
DebugPrint((1, "Failed to get System Address for MDL\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0L;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
goto iSpSendScsiCommandExit;
}
}
iScsiScsiCommand = iSpAllocatePool(
NonPagedPool,
packetSize,
ISCSI_TAG_SCSI_CMD);
if (iScsiScsiCommand == NULL) {
DebugPrint((1, "Could not allocate iSCSI Command packet\n"));
//
// Restore the original DataBuffer in the SRB
//
if (originalDataBuffer != NULL) {
srb->DataBuffer = originalDataBuffer;
}
status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0L;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
goto iSpSendScsiCommandExit;
}
RtlZeroMemory(iScsiScsiCommand, packetSize);
iScsiScsiCommand->OpCode = ISCSIOP_SCSI_COMMAND;
if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
iScsiScsiCommand->Read = SETBITON;
}
if (writeToDevice == TRUE) {
SetUlongInArray((iScsiScsiCommand->Length),
(srb->DataTransferLength));
SetUlongInArray((iScsiScsiCommand->ExpDataXferLength),
(srb->DataTransferLength));
//
// Issue : nramas : 01/02/2001
// This should be later changed to chained MDLs
//
RtlCopyMemory((iScsiScsiCommand + 1),
(srb->DataBuffer),
srb->DataTransferLength);
}
if (expectedDataLen != 0) {
SetUlongInArray((iScsiScsiCommand->ExpDataXferLength),
expectedDataLen);
}
SetUlongInArray((iScsiScsiCommand->CmdRN),
(iScsiConnection->CommandRefNum));
SetUlongInArray((iScsiScsiCommand->ExpStatRN),
(iScsiConnection->CurrentStatusRefNum));
//DebugPrint((3, "Exp StatRN : 0x%x\n",
// (iScsiConnection->ExpStatusRefNum)));
SetUlongInArray((iScsiScsiCommand->TaskTag),
(iScsiConnection->InitiatorTaskTag));
ASSERT((srb->CdbLength) <= 16);
DebugPrint((3, "CDB : "));
for (inx = 0; inx < (srb->CdbLength); inx++) {
DebugPrint((3, "0x%02x ", srb->Cdb[inx]));
}
DebugPrint((3, "\n"));
RtlCopyMemory((iScsiScsiCommand->Cdb),
(srb->Cdb),
(srb->CdbLength));
cmdRN = (iScsiConnection->CommandRefNum);
inx = cmdRN % (iScsiConnection->MaxPendingRequests);
if (inx == 0) {
inx = (iScsiConnection->MaxPendingRequests);
}
DebugPrint((3, "Request will be added to slot %d\n",
inx));
currentRequest = &(iScsiConnection->ActiveClientRequests[inx]);
ASSERT((currentRequest->InUse) == FALSE);
currentRequest->CommandRefNum = iScsiConnection->CommandRefNum;
currentRequest->Irp = Irp;
currentRequest->DeviceObject = DeviceObject;
currentRequest->TaskTag = iScsiConnection->InitiatorTaskTag;
if (originalDataBuffer != NULL) {
currentRequest->OriginalDataBuffer = originalDataBuffer;
}
currentRequest->RequestBuffer = srb->DataBuffer;
currentRequest->RequestBufferOffset = 0;
currentRequest->InUse = TRUE;
currentRequest->Completed = FALSE;
(iScsiConnection->InitiatorTaskTag)++;
if ((iScsiConnection->InitiatorTaskTag) == 0) {
iScsiConnection->InitiatorTaskTag = 1;
}
(iScsiConnection->CommandRefNum)++;
(iScsiConnection->NumberOfReqsInProgress)++;
DebugPrint((3, "Number of requests in progress %d\n",
(iScsiConnection->NumberOfReqsInProgress)));
DebugPrint((3,
"CmdRN %d. PacketSize %d, Expected Xfer Length %d\n",
cmdRN, packetSize, expectedDataLen));
DebugPrint((3, "SCSI packet : %x\n", iScsiScsiCommand));
status = iSpSendData(iScsiConnection->ConnectionDeviceObject,
iScsiConnection->ConnectionFileObject,
iScsiScsiCommand,
packetSize,
&bytesSent);
if (NT_SUCCESS(status)) {
//
// Command packet successfully sent. Mark the IRP pending,
// and return STATUS_PENDING
//
IoMarkIrpPending(Irp);
status = STATUS_PENDING;
} else {
DebugPrint((0, "Failed to send SCSI Command. Status : 0x%08x\n",
status));
if (currentRequest->OriginalDataBuffer) {
srb->DataBuffer = currentRequest->OriginalDataBuffer;
}
(iScsiConnection->InitiatorTaskTag)--;
(iScsiConnection->CommandRefNum)--;
(iScsiConnection->NumberOfReqsInProgress)--;
RtlZeroMemory(currentRequest, sizeof(ACTIVE_REQUESTS));
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0L;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
iSpSendScsiCommandExit:
KeReleaseSpinLock(&(iScsiConnection->RequestLock),
oldIrql);
return status;
}
NTSTATUS
iSpProcessScsiResponse(
PISCSI_CONNECTION IScsiConnection,
PISCSI_SCSI_RESPONSE IScsiScsiResponse
)
{
PISCSI_PDO_EXTENSION pdoExtension;
PCOMMON_EXTENSION commonExtension;
PIO_STACK_LOCATION irpStack;
PSCSI_REQUEST_BLOCK srb;
PIRP irp;
PDEVICE_OBJECT deviceObject;
PACTIVE_REQUESTS currentRequest;
ULONG inx;
ULONG taskTag;
ULONG cmdStatus;
ULONG iScsiStatus;
ULONG statusRN;
ULONG length;
ULONG expCmdRefNum;
NTSTATUS status;
ASSERT((IScsiScsiResponse->OpCode) == ISCSIOP_SCSI_RESPONSE);
ASSERT(IScsiConnection->Type == ISCSI_CONNECTION_TYPE);
currentRequest = IScsiConnection->CurrentRequest;
GetUlongFromArray((IScsiScsiResponse->TaskTag),
taskTag);
GetUlongFromArray((IScsiScsiResponse->StatusRN),
statusRN);
IScsiConnection->CurrentStatusRefNum = statusRN;
DebugPrint((3, "iSpProcessScsiResponse - TaskTag 0x%08x\n",
taskTag));
(IScsiConnection->NumberOfReqsInProgress)--;
commonExtension =
(currentRequest->DeviceObject)->DeviceExtension;
pdoExtension = (PISCSI_PDO_EXTENSION) commonExtension;
irp = currentRequest->Irp;
deviceObject = currentRequest->DeviceObject;
irpStack = IoGetCurrentIrpStackLocation(irp);
srb = irpStack->Parameters.Scsi.Srb;
cmdStatus = IScsiScsiResponse->CmdStatus;
iScsiStatus = IScsiScsiResponse->iSCSIStatus;
GetUlongFromArray((IScsiScsiResponse->ExpCmdRN),
(expCmdRefNum));
GetUlongFromArray((IScsiScsiResponse->MaxCmdRN),
(IScsiConnection->MaxCommandRefNum));
DebugPrint((3,
"SCSI Response : Expected CmdRefNum %d, MaxCmdRN %d\n",
expCmdRefNum,
(IScsiConnection->MaxCommandRefNum)));
//
// Retrieve the size of immediate data
//
GetUlongFromArray((IScsiScsiResponse->Length),
length);
if (cmdStatus == SCSISTAT_GOOD) {
ASSERT(iScsiStatus == ISCSISTAT_GOOD);
irp->IoStatus.Status = STATUS_SUCCESS;
if ((srb->SrbFlags) & SRB_FLAGS_DATA_IN) {
//
// Read request. Fill the number of bytes read
//
irp->IoStatus.Information = currentRequest->ReceivedDataLength;
srb->DataTransferLength = currentRequest->ReceivedDataLength;
} else if ((srb->SrbFlags) & SRB_FLAGS_DATA_OUT) {
//
// Write request. Set IoStatus Information to
// number of bytes written (srb->DataTransferLength)
//
irp->IoStatus.Information = srb->DataTransferLength;
} else {
//
// No I/O involved in this request.
//
irp->IoStatus.Information = 0;
}
srb->SrbStatus = SRB_STATUS_SUCCESS;
srb->ScsiStatus = SCSISTAT_GOOD;
DebugPrint((3, "Info : 0x%x\n", irp->IoStatus.Information));
} else {
DebugPrint((0, "Command failed\n"));
srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
//
// Should map SRB status error using sense data
//
srb->SrbStatus = SRB_STATUS_ERROR;
//
// If the upper driver passed a valid senseinfo buffer,
// and the target sent sense data, copy it to the buffer
//
if ((srb->SenseInfoBufferLength) && (length > 0)) {
ULONG senseInx;
if (length > (srb->SenseInfoBufferLength)) {
DebugPrint((0,
"Sense info greater than buffer size. Size %d\n",
length));
length = srb->SenseInfoBufferLength;
}
DebugPrint((0, "Command 0x%02x failed. Sense Data : ",
srb->Cdb[0]));
for (senseInx = 0; senseInx < length; senseInx++) {
DebugPrint((0, "%02x ", currentRequest->SenseData[senseInx]));
}
DebugPrint((0, "\n"));
RtlCopyMemory(srb->SenseInfoBuffer,
currentRequest->SenseData,
length);
srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
srb->SenseInfoBufferLength = (UCHAR) length;
}
//
// ISSUE : nramas : 01/15/2001
// Need to determine the correct NTSTATUS here
//
irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
irp->IoStatus.Information = 0;
}
//
// Restore the original DataBuffer in the SRB
//
if ((currentRequest->OriginalDataBuffer) != NULL) {
DebugPrint((3, "ProcessResponse : Original DataBuffer - 0x%08x\n",
currentRequest->OriginalDataBuffer));
srb->DataBuffer = currentRequest->OriginalDataBuffer;
}
DebugPrint((3, "Irp done : 0x%x\n", irp));
IoCompleteRequest(irp, IO_NO_INCREMENT);
RtlZeroMemory(currentRequest, sizeof(ACTIVE_REQUESTS));
return STATUS_SUCCESS;
}
NTSTATUS
iSpProcessReceivedData(
IN PISCSI_CONNECTION IScsiConnection,
IN ULONG BytesIndicated,
OUT ULONG *BytesTaken,
IN PVOID DataBuffer
)
{
PUCHAR requestBuffer = NULL;
PISCSI_GENERIC_HEADER iScsiHeader = NULL;
PISCSI_SCSI_RESPONSE iScsiResponse = NULL;
PISCSI_SCSI_DATA_READ iScsiDataRead = NULL;
PACTIVE_REQUESTS currentRequest = NULL;
ULONG length;
ULONG receivedDataLen;
ULONG inx;
ULONG taskTag;
ULONG statusRefNum;
ULONG expCmdRN;
LONG byteCount;
NTSTATUS status = STATUS_SUCCESS;
UCHAR opCode;
KIRQL oldIrql;
//
// We always take all the data given to us
// in this routine. So set BytesTaken to
// BytesIndicated
*BytesTaken = BytesIndicated;
byteCount = (LONG) BytesIndicated;
DebugPrint((3, "Bytes indicated : %d\n", BytesIndicated));
//
// Get the lock to synchronize access to iSCSI
// Connection structure
//
KeAcquireSpinLock(&(IScsiConnection->RequestLock),
&oldIrql);
while (byteCount > 0) {
if ((IScsiConnection->ReceiveState) == ReceiveHeader) {
DebugPrint((3, "Receiving header\n"));
if ((IScsiConnection->CompleteHeaderReceived)== FALSE) {
LONG bytesToCopy;
BOOLEAN headerComplete = FALSE;
bytesToCopy = sizeof(ISCSI_GENERIC_HEADER) -
(IScsiConnection->IScsiPacketOffset);
DebugPrint((0, "CHR False. ToCopy : %d, Count : %d\n",
bytesToCopy, byteCount));
if (byteCount < bytesToCopy) {
bytesToCopy = byteCount;
} else {
headerComplete = TRUE;
}
RtlCopyMemory((IScsiConnection->IScsiPacket) +
(IScsiConnection->IScsiPacketOffset),
DataBuffer,
bytesToCopy);
if (headerComplete == FALSE) {
DebugPrint((0, "CHR still FALSE\n"));
IScsiConnection->IScsiPacketOffset += bytesToCopy;
KeReleaseSpinLock(&(IScsiConnection->RequestLock),
oldIrql);
return STATUS_SUCCESS;
} else {
DebugPrint((0, "Header complete\n"));
IScsiConnection->IScsiPacketOffset = 0;
IScsiConnection->CompleteHeaderReceived = TRUE;
byteCount -= bytesToCopy;
ASSERT(byteCount >= 0);
(PUCHAR) DataBuffer += bytesToCopy;
}
} else if (byteCount < sizeof(ISCSI_GENERIC_HEADER)) {
DebugPrint((0,
"Complete header NOT received. Count : %d\n",
byteCount));
IScsiConnection->CompleteHeaderReceived = FALSE;
RtlCopyMemory((IScsiConnection->IScsiPacket),
DataBuffer,
byteCount);
IScsiConnection->IScsiPacketOffset = byteCount;
KeReleaseSpinLock(&(IScsiConnection->RequestLock),
oldIrql);
return STATUS_SUCCESS;
} else {
RtlCopyMemory((IScsiConnection->IScsiPacket),
DataBuffer,
sizeof(ISCSI_GENERIC_HEADER));
byteCount -= sizeof(ISCSI_GENERIC_HEADER);
ASSERT(byteCount >= 0);
(PUCHAR) DataBuffer += sizeof(ISCSI_GENERIC_HEADER);
}
//
// At this point, we should have the complete header
// available
//
iScsiHeader =
(PISCSI_GENERIC_HEADER) (IScsiConnection->IScsiPacket);
opCode = iScsiHeader->OpCode;
//
// Retrieve the length of immediate data
// associated with this iSCSI packet
//
GetUlongFromArray((iScsiHeader->Length),
length);
DebugPrint((3, "Opcode : %x, Length : %x\n",
opCode, length));
switch (opCode) {
case ISCSIOP_SCSI_DATA_READ: {
iScsiDataRead = (PISCSI_SCSI_DATA_READ) iScsiHeader;
GetUlongFromArray((iScsiDataRead->InitiatorTransferTag),
taskTag);
DebugPrint((3, "XfrTag - 0x%08x\n", taskTag));
if ((IScsiConnection->CurrentRequest) == NULL) {
inx = iSpGetActiveClientRequestIndex(
IScsiConnection,
taskTag);
DebugPrint((3, "ActiveClientRequest index : %d\n", inx));
ASSERT((inx <= (IScsiConnection->MaxPendingRequests)));
currentRequest = &(IScsiConnection->ActiveClientRequests[inx]);
IScsiConnection->CurrentRequest = currentRequest;
} else {
DebugPrint((0, "CurrentRequest not null in data\n"));
currentRequest = IScsiConnection->CurrentRequest;
}
currentRequest->CommandStatus = iScsiDataRead->CommandStatus;
//
// If the command status is not SCSISTAT_GOOD, use
// SenseData buffer to read the sense info. Else, use
// RequestBuffer to read input data
//
if ((iScsiDataRead->CommandStatus) != SCSISTAT_GOOD) {
DebugPrint((0, "Command status is %x\n",
iScsiDataRead->CommandStatus));
requestBuffer = currentRequest->SenseData;
} else {
requestBuffer = currentRequest->RequestBuffer;
}
//
// If immediate data is available, copy that
//
if (length != 0) {
ULONG receivedDataLen;
IScsiConnection->ReceiveState = ReceiveData;
if ((LONG)length <= byteCount ) {
receivedDataLen = length;
} else {
receivedDataLen = byteCount;
}
if ((iScsiDataRead->CommandStatus) != SCSISTAT_GOOD) {
ASSERT(receivedDataLen <= sizeof(currentRequest->SenseData));
}
RtlCopyMemory(requestBuffer,
DataBuffer,
receivedDataLen);
(PUCHAR) DataBuffer += receivedDataLen;
byteCount -= receivedDataLen;
ASSERT(byteCount >= 0);
if (byteCount != 0) {
DebugPrint((1, "More bytes available\n"));
}
currentRequest->ExpectedDataLength = length;
currentRequest->RequestBufferOffset = receivedDataLen;
currentRequest->ReceivedDataLength = receivedDataLen;
if ((currentRequest->ExpectedDataLength) ==
currentRequest->ReceivedDataLength) {
IScsiConnection->ReceiveState = ReceiveHeader;
}
}
break;
}
case ISCSIOP_SCSI_RESPONSE: {
BOOLEAN responseComplete = FALSE;
iScsiResponse = (PISCSI_SCSI_RESPONSE) iScsiHeader;
IScsiConnection->ReceiveState = ReceiveHeader;
GetUlongFromArray((iScsiResponse->TaskTag),
taskTag);
DebugPrint((3, "ResTag - 0x%08x\n", taskTag));
if ((IScsiConnection->CurrentRequest) == NULL) {
inx = iSpGetActiveClientRequestIndex(
IScsiConnection,
taskTag);
DebugPrint((3, "ActiveClientRequest index : %d\n", inx));
if (inx > (IScsiConnection->MaxPendingRequests)) {
ULONG cmdRN;
DebugPrint((0,
"Tag : %x. Will use cmdRN to search\n",
taskTag));
GetUlongFromArray((iScsiResponse->ExpCmdRN),
cmdRN);
inx = iSpGetReqIndexUsingCmdRN(IScsiConnection,
(cmdRN - 1));
DebugPrint((0, "Inx returned : 0x%x\n", inx));
}
ASSERT((inx <= (IScsiConnection->MaxPendingRequests)));
currentRequest = &(IScsiConnection->ActiveClientRequests[inx]);
IScsiConnection->CurrentRequest = currentRequest;
} else {
currentRequest = IScsiConnection->CurrentRequest;
}
currentRequest->CommandStatus = iScsiResponse->CmdStatus;
if ((iScsiResponse->CmdStatus) != SCSISTAT_GOOD) {
DebugPrint((0, "Command status is %x. Length : %d\n",
iScsiResponse->CmdStatus,
length));
requestBuffer = currentRequest->SenseData;
} else {
requestBuffer = currentRequest->RequestBuffer;
}
if (length != 0) {
ULONG receivedDataLen;
DebugPrint((3, "Non-zero length in response : %d\n",
length));
IScsiConnection->ReceiveState = ReceiveData;
if ((LONG)length <= byteCount ) {
receivedDataLen = length;
} else {
receivedDataLen = byteCount;
}
if ((iScsiResponse->CmdStatus) != SCSISTAT_GOOD) {
ASSERT(receivedDataLen <= sizeof(currentRequest->SenseData));
}
RtlCopyMemory(requestBuffer,
DataBuffer,
receivedDataLen);
(PUCHAR) DataBuffer += receivedDataLen;
byteCount -= receivedDataLen;
ASSERT(byteCount >= 0);
currentRequest->ExpectedDataLength = length;
currentRequest->RequestBufferOffset = receivedDataLen;
currentRequest->ReceivedDataLength = receivedDataLen;
if ((currentRequest->ExpectedDataLength) ==
currentRequest->ReceivedDataLength) {
IScsiConnection->ReceiveState = ReceiveHeader;
responseComplete = TRUE;
DebugPrint((3, "Response complete. Will process it\n"));
}
} else {
responseComplete = TRUE;
}
//
// Should use this field to determine
// Data Overrun\Underrun cases
//
if ((iScsiResponse->OverFlow) ||
(iScsiResponse->UnderFlow)) {
ULONG residualCount;
GetUlongFromArray((iScsiResponse->ResidualCount),
residualCount);
DebugPrint((0, "Residualcount is : %d\n",
residualCount));
}
if (responseComplete == TRUE) {
if ((iScsiResponse->CmdStatus) != SCSISTAT_GOOD) {
PUCHAR resBuff =
(PUCHAR) (IScsiConnection->IScsiPacket);
ULONG inx0, inx1;
ULONG sizeRequired = sizeof(ISCSI_SCSI_RESPONSE);
DebugPrint((1, "\n Beginning Of Data\n"));
inx0 = 0;
while (inx0 < sizeRequired) {
inx1 = 0;
DebugPrint((1, "\t"));
while ((inx1 < 4) && ((inx0+inx1) < sizeRequired)) {
DebugPrint((1, "%02x ",
resBuff[inx0+inx1]));
inx1++;
}
DebugPrint((1, "\n"));
inx0 += 4;
}
DebugPrint((1, " End Of Data\n"));
}
iSpProcessScsiResponse(
IScsiConnection,
(PISCSI_SCSI_RESPONSE)(IScsiConnection->IScsiPacket));
IScsiConnection->CurrentRequest = NULL;
}
break;
}
case ISCSIOP_NOP_IN_MESSAGE: {
PISCSI_NOP_IN iScsiNopIn = (PISCSI_NOP_IN) iScsiHeader;
IScsiConnection->ReceiveState = ReceiveHeader;
if (iScsiNopIn->Poll) {
//
// Need to handle this case. Should send
// response to the target
//
DebugPrint((0, "Target expects NOP OUT message\n"));
} else {
DebugPrint((1, "No NOP OUT message needed.\n"));
}
break;
}
default: {
ULONG inx0, inx1;
//
// Opcode that we don't currently handle.
// For the timebeing, just dump the iSCSI
// packet.
//
DebugPrint((0, "Unknown opcode : 0x%02x\n", opCode));
inx0 = 0;
while(inx0 < 48) {
inx1 = 0;
DebugPrint((0, "\t"));
while ((inx1 < 4) &&
((inx0+inx1) < 48)) {
DebugPrint((0, "0x%02x ",
((PUCHAR)(iScsiHeader))[inx0+inx1]));
inx1++;
}
DebugPrint((0, "\n"));
inx0 += 4;
}
DebugPrint((0, "\n"));
break;
}
} // switch (opCode)
} else {
ULONG bytesToCopy;
UCHAR opCode;
//
// We are receiving the data portion of the packet
//
ASSERT((IScsiConnection->ReceiveState) == ReceiveData);
ASSERT(IScsiConnection->CurrentRequest);
DebugPrint((3, "Receiving data\n"));
currentRequest = IScsiConnection->CurrentRequest;
if ((currentRequest->CommandStatus) != SCSISTAT_GOOD) {
requestBuffer = currentRequest->SenseData;
} else {
requestBuffer = currentRequest->RequestBuffer;
}
requestBuffer += currentRequest->RequestBufferOffset;
bytesToCopy = ((currentRequest->ExpectedDataLength) -
(currentRequest->ReceivedDataLength));
if ((LONG)bytesToCopy > byteCount) {
bytesToCopy = byteCount;
} else {
DebugPrint((3, "More bytes in current buffer than expected\n"));
}
RtlCopyMemory(requestBuffer, DataBuffer, bytesToCopy);
byteCount -= bytesToCopy;
(PUCHAR) DataBuffer += bytesToCopy;
ASSERT(byteCount >= 0);
currentRequest->RequestBufferOffset += bytesToCopy;
currentRequest->ReceivedDataLength += bytesToCopy;
if ((currentRequest->ExpectedDataLength) ==
currentRequest->ReceivedDataLength) {
DebugPrint((3, "Got all data. Bytes left %d\n",
byteCount));
IScsiConnection->ReceiveState = ReceiveHeader;
opCode = IScsiConnection->IScsiPacket[0];
if (opCode == ISCSIOP_SCSI_RESPONSE) {
DebugPrint((3, "Will process the response\n"));
iSpProcessScsiResponse(
IScsiConnection,
(PISCSI_SCSI_RESPONSE)(IScsiConnection->IScsiPacket));
IScsiConnection->CurrentRequest = NULL;
}
}
}
}
KeReleaseSpinLock(&(IScsiConnection->RequestLock),
oldIrql);
return status;
}
ULONG
iSpGetActiveClientRequestIndex(
PISCSI_CONNECTION IScsiConnection,
ULONG TaskTag
)
{
ULONG retIndex = ~0;
ULONG inx;
DebugPrint((3, "Given Task Tag : 0x%08x\n", TaskTag));
for (inx = 1; inx <= (IScsiConnection->MaxPendingRequests); inx++) {
DebugPrint((3, "Index %d : CmdRN - 0x%08x\n",
inx,
((IScsiConnection->ActiveClientRequests[inx]).TaskTag)));
if (((IScsiConnection->ActiveClientRequests[inx]).TaskTag)
== TaskTag) {
retIndex = inx;
DebugPrint((1, "inx : 0x%04x\n", retIndex));
break;
}
}
if (retIndex > (IScsiConnection->MaxPendingRequests)) {
DebugPrint((0, "Tag : Did not find the request for this response\n"));
}
return retIndex;
}
ULONG
iSpGetReqIndexUsingCmdRN(
PISCSI_CONNECTION IScsiConnection,
ULONG CmdRN
)
{
ULONG retIndex = ~0;
ULONG inx;
DebugPrint((3, "Given CmdRN : 0x%08x\n", CmdRN));
for (inx = 1; inx <= (IScsiConnection->MaxPendingRequests); inx++) {
if (((IScsiConnection->ActiveClientRequests[inx]).CommandRefNum)
== CmdRN) {
retIndex = inx;
DebugPrint((1, "inx : 0x%04x\n", retIndex));
break;
}
}
if (retIndex > (IScsiConnection->MaxPendingRequests)) {
ASSERTMSG("CmdRN : Did not find the request for this response\n",
FALSE);
}
return retIndex;
}