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