698 lines
19 KiB
C
698 lines
19 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
BOOLEAN PrintDataBuffer = FALSE;
|
|||
|
|
|||
|
UCHAR
|
|||
|
GetCdbLength(
|
|||
|
IN UCHAR OpCode
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
iSpSendLoginResponse(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|||
|
PISCSI_CONNECTION iScsiConnection = fdoExtension->ServerNodeInfo;
|
|||
|
PISCSI_LOGIN_RESPONSE iscsiLoginResponse;
|
|||
|
PISCSI_LOGIN_COMMAND loginCommand;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG bytesSent;
|
|||
|
ULONG tempULong;
|
|||
|
|
|||
|
|
|||
|
DelayThreadExecution(1);
|
|||
|
|
|||
|
IoFreeWorkItem((PIO_WORKITEM) Context);
|
|||
|
|
|||
|
ASSERT((iScsiConnection != NULL));
|
|||
|
ASSERT((iScsiConnection->Type) == ISCSI_CONNECTION_TYPE);
|
|||
|
|
|||
|
|
|||
|
loginCommand = (PISCSI_LOGIN_COMMAND)(iScsiConnection->IScsiHeader);
|
|||
|
|
|||
|
iscsiLoginResponse = iSpAllocatePool(NonPagedPool,
|
|||
|
sizeof(ISCSI_LOGIN_RESPONSE),
|
|||
|
ISCSI_TAG_LOGIN_RES);
|
|||
|
if (iscsiLoginResponse == NULL) {
|
|||
|
DebugPrint((0, "Failed to allocate logon response packet\n"));
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(iscsiLoginResponse, sizeof(ISCSI_LOGIN_RESPONSE));
|
|||
|
|
|||
|
iscsiLoginResponse->OpCode = ISCSIOP_LOGIN_RESPONSE;
|
|||
|
|
|||
|
//
|
|||
|
// Copy client's Session ID
|
|||
|
//
|
|||
|
iscsiLoginResponse->ISID[0] = loginCommand->ISID[0];
|
|||
|
iscsiLoginResponse->ISID[1] = loginCommand->ISID[1];
|
|||
|
|
|||
|
tempULong = InterlockedIncrement(&GlobalSessionID);
|
|||
|
iscsiLoginResponse->TSID[0] = (UCHAR) ((tempULong & 0xFF00) >> 8);
|
|||
|
iscsiLoginResponse->TSID[1] = (UCHAR) (tempULong & 0xFF);
|
|||
|
|
|||
|
iscsiLoginResponse->ExpCmdRN[0] = loginCommand->InitCmdRN[0];
|
|||
|
iscsiLoginResponse->ExpCmdRN[1] = loginCommand->InitCmdRN[1];
|
|||
|
iscsiLoginResponse->ExpCmdRN[2] = loginCommand->InitCmdRN[2];
|
|||
|
iscsiLoginResponse->ExpCmdRN[3] = loginCommand->InitCmdRN[3];
|
|||
|
|
|||
|
iscsiLoginResponse->MaxCmdRN[3] = MAX_PENDING_REQUESTS;
|
|||
|
|
|||
|
iscsiLoginResponse->InitStatRN[3] = 1;
|
|||
|
|
|||
|
iscsiLoginResponse->Status = ISCSI_LOGINSTATUS_ACCEPT;
|
|||
|
|
|||
|
GetUlongFromArray((loginCommand->InitCmdRN),
|
|||
|
(iScsiConnection->ExpCommandRefNum));
|
|||
|
|
|||
|
iScsiConnection->MaxCommandRefNum = MAX_PENDING_REQUESTS;
|
|||
|
|
|||
|
iScsiConnection->StatusRefNum = 1;
|
|||
|
|
|||
|
//
|
|||
|
// Send logon response
|
|||
|
//
|
|||
|
fdoExtension->CurrentProtocolState = PSFullFeaturePhase;
|
|||
|
status = iSpSendData(iScsiConnection->ConnectionDeviceObject,
|
|||
|
iScsiConnection->ConnectionFileObject,
|
|||
|
iscsiLoginResponse,
|
|||
|
sizeof(ISCSI_LOGIN_RESPONSE),
|
|||
|
&bytesSent);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DebugPrint((3,
|
|||
|
"Send succeeded for logon response. Bytes sent : %d\n",
|
|||
|
bytesSent));
|
|||
|
} else {
|
|||
|
DebugPrint((0, "Could not send logon response. Status %x\n",
|
|||
|
status));
|
|||
|
|
|||
|
fdoExtension->CurrentProtocolState = PSLogonFailed;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
iSpProcessScsiCommand(
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
PISCSI_FDO_EXTENSION fdoExtension = (PISCSI_FDO_EXTENSION) Context;
|
|||
|
PISCSI_CONNECTION iScsiConnection = fdoExtension->ServerNodeInfo;
|
|||
|
PISCSI_SCSI_COMMAND iScsiCommand;
|
|||
|
PISCSI_SCSI_RESPONSE iScsiResponse = NULL;
|
|||
|
PIRP irp = NULL;
|
|||
|
PMDL mdl = NULL;
|
|||
|
PACTIVE_REQUESTS currentRequest;
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
PCDB cdb;
|
|||
|
SCSI_REQUEST_BLOCK srb;
|
|||
|
KEVENT event;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
ULONG length =0;
|
|||
|
ULONG sizeRequired;
|
|||
|
ULONG inx;
|
|||
|
ULONG bytesSent;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
KeWaitForSingleObject(
|
|||
|
(PVOID) &(iScsiConnection->RequestSemaphore),
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ((iScsiConnection->TerminateThread) == TRUE) {
|
|||
|
|
|||
|
//
|
|||
|
// This is an indication to terminate this thread
|
|||
|
//
|
|||
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
inx = (iScsiConnection->ExpCommandRefNum) % MAX_PENDING_REQUESTS;
|
|||
|
if (inx == 0) {
|
|||
|
inx = MAX_PENDING_REQUESTS;
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((3, "Will process request at index %d\n", inx));
|
|||
|
|
|||
|
currentRequest = &(iScsiConnection->ActiveRequests[inx]);
|
|||
|
|
|||
|
iScsiCommand = (PISCSI_SCSI_COMMAND) (currentRequest->IScsiHeader);
|
|||
|
|
|||
|
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
|
|||
|
|
|||
|
//
|
|||
|
// Set the size of the SCSI Request Block
|
|||
|
//
|
|||
|
srb.Length = SCSI_REQUEST_BLOCK_SIZE;
|
|||
|
|
|||
|
srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
|||
|
|
|||
|
if ((iScsiCommand->TurnOffAutoSense) == FALSE) {
|
|||
|
srb.SenseInfoBuffer = currentRequest->SenseData;
|
|||
|
|
|||
|
srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the CDB Length based on the CDB OpCode
|
|||
|
//
|
|||
|
srb.CdbLength = GetCdbLength(iScsiCommand->Cdb[0]);
|
|||
|
|
|||
|
cdb = (PCDB)(srb.Cdb);
|
|||
|
RtlCopyMemory(cdb, iScsiCommand->Cdb, srb.CdbLength);
|
|||
|
|
|||
|
//
|
|||
|
// Set DataBuffer pointer to the command buffer in
|
|||
|
// the current request.
|
|||
|
//
|
|||
|
srb.DataBuffer = currentRequest->CommandBuffer;
|
|||
|
|
|||
|
GetUlongFromArray((iScsiCommand->Length),
|
|||
|
length);
|
|||
|
if (length == 0) {
|
|||
|
DebugPrint((3, "Length 0. Probably READ command\n"));
|
|||
|
GetUlongFromArray((iScsiCommand->ExpDataXferLength),
|
|||
|
length);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If length is non-zero at this point, then it's
|
|||
|
// either a Read (ExpDataXferLength is non-zero), or
|
|||
|
// Write (Immediate data length is non-zero) command.
|
|||
|
//
|
|||
|
if (length != 0) {
|
|||
|
DebugPrint((3, "Read or Write data command\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Set the transfer length.
|
|||
|
//
|
|||
|
srb.DataTransferLength = length;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (iScsiCommand->Read) {
|
|||
|
|
|||
|
srb.SrbFlags = SRB_FLAGS_DATA_IN;
|
|||
|
|
|||
|
} else if (length != 0) {
|
|||
|
|
|||
|
//
|
|||
|
// If length is Non-Zero and Read bit is
|
|||
|
// NOT set, then it should be a Write command
|
|||
|
//
|
|||
|
srb.SrbFlags = SRB_FLAGS_DATA_OUT;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
switch (iScsiCommand->ATTR) {
|
|||
|
case ISCSI_TASKATTR_UNTAGGED:
|
|||
|
case ISCSI_TASKATTR_SIMPLE : {
|
|||
|
srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case ISCSI_TASKATTR_ORDERED: {
|
|||
|
srb.QueueAction = SRB_ORDERED_QUEUE_TAG_REQUEST;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case ISCSI_TASKATTR_HEADOFQUEUE: {
|
|||
|
srb.QueueAction = SRB_HEAD_OF_QUEUE_TAG_REQUEST;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default: {
|
|||
|
srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
srb.QueueTag = SP_UNTAGGED;
|
|||
|
|
|||
|
SET_FLAG(srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
|||
|
SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
|
|||
|
|
|||
|
//
|
|||
|
// Set the event object to the unsignaled state.
|
|||
|
// It will be used to signal request completion.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Build device I/O control request with METHOD_NEITHER data transfer.
|
|||
|
// We'll queue a completion routine to cleanup the MDL's and such ourself.
|
|||
|
//
|
|||
|
|
|||
|
irp = IoAllocateIrp(
|
|||
|
(CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
|
|||
|
FALSE);
|
|||
|
|
|||
|
if(irp == NULL) {
|
|||
|
|
|||
|
DebugPrint((0, "Failed to allocate Irp\n"));
|
|||
|
|
|||
|
//
|
|||
|
// ISSUE : Should handle this failure better
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get next stack location.
|
|||
|
//
|
|||
|
|
|||
|
irpStack = IoGetNextIrpStackLocation(irp);
|
|||
|
|
|||
|
//
|
|||
|
// Set up SRB for execute scsi request. Save SRB address in next stack
|
|||
|
// for the port driver.
|
|||
|
//
|
|||
|
|
|||
|
irpStack->MajorFunction = IRP_MJ_SCSI;
|
|||
|
irpStack->Parameters.Scsi.Srb = &srb;
|
|||
|
|
|||
|
IoSetCompletionRoutine(irp,
|
|||
|
iSpSendSrbSynchronousCompletion,
|
|||
|
&srb,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE);
|
|||
|
|
|||
|
irp->UserIosb = &ioStatus;
|
|||
|
irp->UserEvent = &event;
|
|||
|
|
|||
|
if (srb.DataTransferLength) {
|
|||
|
//
|
|||
|
// Build an MDL for the data buffer and stick it into the irp. The
|
|||
|
// completion routine will unlock the pages and free the MDL.
|
|||
|
//
|
|||
|
|
|||
|
irp->MdlAddress = IoAllocateMdl(srb.DataBuffer,
|
|||
|
length,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
irp );
|
|||
|
if (irp->MdlAddress == NULL) {
|
|||
|
IoFreeIrp( irp );
|
|||
|
|
|||
|
DebugPrint((0, "Failed to allocate MDL\n"));
|
|||
|
|
|||
|
//
|
|||
|
// ISSUE : Should handle this failure better
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
MmProbeAndLockPages( irp->MdlAddress,
|
|||
|
KernelMode,
|
|||
|
(iScsiCommand->Read ? IoWriteAccess :
|
|||
|
IoWriteAccess));
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
status = GetExceptionCode();
|
|||
|
|
|||
|
IoFreeMdl(irp->MdlAddress);
|
|||
|
|
|||
|
IoFreeIrp( irp );
|
|||
|
|
|||
|
DebugPrint((0,
|
|||
|
"Could not lock pages. Status : %x\n",
|
|||
|
status));
|
|||
|
|
|||
|
//
|
|||
|
// ISSUE : Should handle this failure better
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set timeout value for this request.
|
|||
|
//
|
|||
|
// N.B. The value should be chosen depending on
|
|||
|
// the type of the device, and type of command.
|
|||
|
// For now, just set some reasonable value
|
|||
|
//
|
|||
|
srb.TimeOutValue = 180;
|
|||
|
|
|||
|
//
|
|||
|
// Zero out status.
|
|||
|
//
|
|||
|
|
|||
|
srb.ScsiStatus = srb.SrbStatus = 0;
|
|||
|
|
|||
|
srb.NextSrb = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Set up IRP Address.
|
|||
|
//
|
|||
|
|
|||
|
srb.OriginalRequest = irp;
|
|||
|
|
|||
|
//
|
|||
|
// Call the port driver with the request and wait for it to complete.
|
|||
|
//
|
|||
|
|
|||
|
status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
|
|||
|
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Send the response to the client
|
|||
|
//
|
|||
|
sizeRequired = sizeof(ISCSI_SCSI_RESPONSE);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
if (status == STATUS_BUFFER_OVERFLOW) {
|
|||
|
|
|||
|
if (length >= srb.DataTransferLength) {
|
|||
|
DebugPrint((1, "DataUnderrun. Xp Len %d, XFer Len %d\n",
|
|||
|
length, srb.DataTransferLength));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
sizeRequired += srb.DataTransferLength;
|
|||
|
length = srb.DataTransferLength;
|
|||
|
} else {
|
|||
|
DebugPrint((0,
|
|||
|
"Buffer overflow error. XLen %d, XFer Len %d\n",
|
|||
|
length, srb.DataTransferLength));
|
|||
|
|
|||
|
sizeRequired += srb.SenseInfoBufferLength;
|
|||
|
length = srb.SenseInfoBufferLength;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
DebugPrint((0,
|
|||
|
"Command failed. OpCode : 0x%x, Status : 0x%x\n",
|
|||
|
srb.Cdb[0],
|
|||
|
status));
|
|||
|
|
|||
|
DebugPrint((1, "Expected length : %d, Transfered length : %d\n",
|
|||
|
length, srb.DataTransferLength));
|
|||
|
|
|||
|
sizeRequired += srb.SenseInfoBufferLength;
|
|||
|
length = srb.SenseInfoBufferLength;
|
|||
|
}
|
|||
|
|
|||
|
} else if (iScsiCommand->Read) {
|
|||
|
|
|||
|
ASSERT((length >= srb.DataTransferLength));
|
|||
|
|
|||
|
sizeRequired += srb.DataTransferLength;
|
|||
|
length = srb.DataTransferLength;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
length = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((3, "Size of the response - %d. \n", sizeRequired));
|
|||
|
|
|||
|
if ((PrintDataBuffer == TRUE) && (length != 0)) {
|
|||
|
|
|||
|
for (inx = 0; inx < length; inx++) {
|
|||
|
DebugPrint((0, "%02x ",
|
|||
|
(((PUCHAR)(srb.DataBuffer))[inx])));
|
|||
|
if ((inx != 0) && ((inx % 16) == 0)) {
|
|||
|
DebugPrint((0, "\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((0, "\n"));
|
|||
|
}
|
|||
|
|
|||
|
iScsiResponse = iSpAllocatePool(NonPagedPool,
|
|||
|
sizeRequired,
|
|||
|
ISCSI_TAG_SCSIRES);
|
|||
|
if (iScsiResponse != NULL) {
|
|||
|
|
|||
|
RtlZeroMemory(iScsiResponse, sizeRequired);
|
|||
|
|
|||
|
iScsiResponse->OpCode = ISCSIOP_SCSI_RESPONSE;
|
|||
|
|
|||
|
CopyFourBytes((iScsiResponse->TaskTag),
|
|||
|
(iScsiCommand->TaskTag));
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
iScsiResponse->CmdStatus = SCSISTAT_GOOD;
|
|||
|
iScsiResponse->iSCSIStatus = ISCSISTAT_GOOD;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugPrint((1, "Error. Response data size : %d\n",
|
|||
|
sizeRequired));
|
|||
|
|
|||
|
iScsiResponse->CmdStatus = SCSISTAT_CHECK_CONDITION;
|
|||
|
iScsiResponse->iSCSIStatus = ISCSISTAT_CHECK_CONDITION;
|
|||
|
}
|
|||
|
|
|||
|
SetUlongInArray((iScsiResponse->StatusRN),
|
|||
|
(iScsiConnection->StatusRefNum));
|
|||
|
(iScsiConnection->StatusRefNum)++;
|
|||
|
|
|||
|
(iScsiConnection->ExpCommandRefNum)++;
|
|||
|
SetUlongInArray((iScsiResponse->ExpCmdRN),
|
|||
|
(iScsiConnection->ExpCommandRefNum));
|
|||
|
|
|||
|
SetUlongInArray((iScsiResponse->MaxCmdRN),
|
|||
|
(iScsiConnection->ExpCommandRefNum) +
|
|||
|
(MAX_PENDING_REQUESTS) - 1);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
if (srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
|
|||
|
DebugPrint((1, "Sense Data is valid\n"));
|
|||
|
|
|||
|
if ((iScsiCommand->TurnOffAutoSense) == FALSE) {
|
|||
|
ULONG inx;
|
|||
|
RtlCopyMemory((iScsiResponse + 1),
|
|||
|
srb.SenseInfoBuffer,
|
|||
|
srb.SenseInfoBufferLength);
|
|||
|
|
|||
|
DebugPrint((0, "OpCode : %x, Sense Data : ",
|
|||
|
srb.Cdb[0]));
|
|||
|
for (inx = 0; inx < (srb.SenseInfoBufferLength); inx++) {
|
|||
|
DebugPrint((0, "%02x ", ((PUCHAR)(srb.SenseInfoBuffer))[inx]));
|
|||
|
}
|
|||
|
DebugPrint((0, "\n"));
|
|||
|
|
|||
|
SetUlongInArray((iScsiResponse->Length),
|
|||
|
srb.SenseInfoBufferLength);
|
|||
|
|
|||
|
iScsiResponse->SenseDataLength[0] =
|
|||
|
(UCHAR) ((srb.SenseInfoBufferLength) & 0x0000FF00);
|
|||
|
iScsiResponse->SenseDataLength[1] =
|
|||
|
(UCHAR) ((srb.SenseInfoBufferLength) & 0x000000FF);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
ULONG inx0, inx1;
|
|||
|
PUCHAR responseBuffer = (PUCHAR) iScsiResponse;
|
|||
|
|
|||
|
DebugPrint((0, "Sense Data is NOT valid\n"));
|
|||
|
|
|||
|
length = 0;
|
|||
|
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 ",
|
|||
|
responseBuffer[inx0+inx1]));
|
|||
|
|
|||
|
inx1++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((1, "\n"));
|
|||
|
|
|||
|
inx0 += 4;
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((1, " End Of Data\n"));
|
|||
|
}
|
|||
|
|
|||
|
} else if (length != 0) {
|
|||
|
|
|||
|
RtlCopyMemory((iScsiResponse + 1),
|
|||
|
srb.DataBuffer,
|
|||
|
length);
|
|||
|
|
|||
|
SetUlongInArray((iScsiResponse->Length),
|
|||
|
length);
|
|||
|
|
|||
|
iScsiResponse->ResponseLength[0] = (UCHAR) (length & 0x0000FF00);
|
|||
|
iScsiResponse->ResponseLength[1] = (UCHAR) (length & 0x000000FF);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = iSpSendData(iScsiConnection->ConnectionDeviceObject,
|
|||
|
iScsiConnection->ConnectionFileObject,
|
|||
|
iScsiResponse,
|
|||
|
sizeRequired,
|
|||
|
&bytesSent);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
DebugPrint((3,
|
|||
|
"Successfully sent SCSI Response. Bytes sent : %d\n",
|
|||
|
bytesSent));
|
|||
|
} else {
|
|||
|
DebugPrint((0, "Failed to send SCSI response. Status : 0x%x\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (irp->MdlAddress) {
|
|||
|
MmUnlockPages(irp->MdlAddress);
|
|||
|
|
|||
|
IoFreeMdl(irp->MdlAddress);
|
|||
|
}
|
|||
|
|
|||
|
IoFreeIrp( irp );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
iSpSendSrbSynchronousCompletion(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp,
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
*(Irp->UserIosb) = Irp->IoStatus;
|
|||
|
|
|||
|
//
|
|||
|
// Signal the caller's event.
|
|||
|
//
|
|||
|
|
|||
|
KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
|
|||
|
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UCHAR
|
|||
|
GetCdbLength(
|
|||
|
IN UCHAR OpCode
|
|||
|
)
|
|||
|
{
|
|||
|
UCHAR commandGroup;
|
|||
|
|
|||
|
commandGroup = (OpCode >> 5) & 0x07;
|
|||
|
DebugPrint((3, "Command Group - %d\n", commandGroup));
|
|||
|
|
|||
|
switch (commandGroup) {
|
|||
|
case COMMAND_GROUP_0: {
|
|||
|
return CDB6GENERIC_LENGTH;
|
|||
|
}
|
|||
|
|
|||
|
case COMMAND_GROUP_1:
|
|||
|
case COMMAND_GROUP_2: {
|
|||
|
return CDB10GENERIC_LENGTH;
|
|||
|
}
|
|||
|
|
|||
|
case COMMAND_GROUP_5: {
|
|||
|
return CDB12GENERIC_LENGTH;
|
|||
|
}
|
|||
|
|
|||
|
default: {
|
|||
|
ASSERTMSG("Unknown CDB Opcode type\n",
|
|||
|
FALSE);
|
|||
|
}
|
|||
|
} // switch (commandGroup)
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
iSpGetActiveClientRequestIndex(
|
|||
|
IN PISCSI_CONNECTION IScsiConnection,
|
|||
|
IN PISCSI_SCSI_COMMAND IScsiCommand
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG cmdRefNum;
|
|||
|
ULONG expCmdRefNum;
|
|||
|
ULONG inx;
|
|||
|
|
|||
|
GetUlongFromArray((IScsiCommand->CmdRN),
|
|||
|
cmdRefNum);
|
|||
|
|
|||
|
expCmdRefNum = IScsiConnection->ExpCommandRefNum;
|
|||
|
|
|||
|
if ((cmdRefNum < expCmdRefNum) ||
|
|||
|
(cmdRefNum >= (expCmdRefNum + MAX_PENDING_REQUESTS))) {
|
|||
|
|
|||
|
DebugPrint((0, "Unexpected Command Ref Num : %d",
|
|||
|
cmdRefNum));
|
|||
|
ASSERT(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
inx = cmdRefNum % MAX_PENDING_REQUESTS;
|
|||
|
if (inx == 0) {
|
|||
|
inx = MAX_PENDING_REQUESTS;
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((3, "Will copy request to slot %d\n", inx));
|
|||
|
|
|||
|
return inx;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|