mirror of https://github.com/tongzx/nt5src
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.
1251 lines
38 KiB
1251 lines
38 KiB
|
|
/*++
|
|
|
|
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;
|
|
}
|