package org.jscsi.target.connection;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.AssertJUnit.assertEquals;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.DigestException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.BasicHeaderSegment;
import org.jscsi.parser.InitiatorMessageParser;
import org.jscsi.parser.OperationCode;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.ProtocolDataUnitFactory;
import org.jscsi.parser.data.DataInParser;
import org.jscsi.parser.scsi.SCSICommandParser;
import org.jscsi.parser.scsi.SCSIResponseParser;
import org.jscsi.parser.scsi.SCSIResponseParser.ServiceResponse;
import org.jscsi.parser.scsi.SCSIStatus;
import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
import org.jscsi.target.connection.stage.TargetStage;
import org.jscsi.target.connection.stage.fullfeature.FormatUnitStage;
import org.jscsi.target.connection.stage.fullfeature.InquiryStage;
import org.jscsi.target.connection.stage.fullfeature.ReportLunsStage;
import org.jscsi.target.connection.stage.fullfeature.RequestSenseStage;
import org.jscsi.target.connection.stage.fullfeature.SendDiagnosticStage;
import org.jscsi.target.connection.stage.fullfeature.TestUnitReadyStage;
import org.jscsi.target.connection.stage.fullfeature.TextNegotiationStage;
import org.jscsi.target.connection.stage.fullfeature.UnsupportedOpCodeStage;
import org.jscsi.target.scsi.IResponseData;
import org.jscsi.target.scsi.ScsiResponseDataSegment;
import org.jscsi.target.scsi.cdb.InquiryCDB;
import org.jscsi.target.scsi.cdb.ReportLunsCDB;
import org.jscsi.target.scsi.cdb.RequestSenseCdb;
import org.jscsi.target.scsi.cdb.SendDiagnosticCdb;
import org.jscsi.target.scsi.inquiry.PageCode.VitalProductDataPageName;
import org.jscsi.target.scsi.inquiry.StandardInquiryData;
import org.jscsi.target.scsi.inquiry.SupportedVpdPages;
import org.jscsi.target.scsi.sense.AdditionalSenseBytes;
import org.jscsi.target.scsi.sense.AdditionalSenseCodeAndQualifier;
import org.jscsi.target.scsi.sense.DescriptorFormatSenseData;
import org.jscsi.target.scsi.sense.ErrorType;
import org.jscsi.target.scsi.sense.FixedFormatSenseData;
import org.jscsi.target.scsi.sense.SenseData;
import org.jscsi.target.scsi.sense.SenseKey;
import org.jscsi.target.scsi.sense.information.FourByteInformation;
import org.jscsi.target.scsi.sense.senseDataDescriptor.SenseDataDescriptor;
import org.jscsi.target.scsi.sense.senseDataDescriptor.senseKeySpecific.FieldPointerSenseKeySpecificData;
import org.jscsi.target.settings.ConnectionSettingsNegotiator;
import org.jscsi.target.settings.SessionSettingsNegotiator;
import org.jscsi.target.settings.SettingsException;
import org.jscsi.target.settings.TextKeyword;
import org.jscsi.target.settings.TextParameter;
import org.jscsi.target.util.ReadWrite;
import org.mockito.ArgumentCaptor;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ConnectionTest {
// /**
// * This test executes the mode sense stage covering the stage execution
// * using a the target connection and a stub'ish pdu.
// */
// @Test(enabled = false)
// public void testModeSenseStage() throws Exception {
// TargetConnection connection = targetServer.getConnection();
// modeSenseStage = new ModeSenseStage(new TargetFullFeaturePhase(connection));
//
// final ProtocolDataUnit pdu =
// new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None", "None");
//
// modeSenseStage.execute(pdu);
// }
//
// /**
// * This test executes the ping stage covering the stage execution
// * using a the target connection and a stub'ish pdu.
// */
// @Test(enabled = false)
// public void testPingStage() throws Exception {
// TargetConnection connection = targetServer.getConnection();
// pingStage = new PingStage(new TargetFullFeaturePhase(connection));
//
// final ProtocolDataUnit pdu =
// new ProtocolDataUnitFactory().create(false, true, OperationCode.NOP_OUT, "None", "None");
//
// pingStage.execute(pdu);
// }
ArgumentCaptor<ProtocolDataUnit> captor = ArgumentCaptor.forClass(ProtocolDataUnit.class);
final Connection connection = mock(Connection.class);
@Test(dataProvider = "instantiateStages", enabled = true)
public void testStages(Class<TargetStage> pTargetStageClass, TargetStage[] pStages,
Class<ProtocolDataUnit> pDataUnitClass, ProtocolDataUnit[] pDataUnits, Class<Checker> pCheckerClass,
Checker[] pChecker) throws DigestException, IOException, InterruptedException, InternetSCSIException,
SettingsException {
assertEquals(pStages.length, pDataUnits.length);
assertEquals(pStages.length, pChecker.length);
List<ProtocolDataUnit> units = new ArrayList<ProtocolDataUnit>();
for (int i = 0; i < 8; i++) {
pStages[i].execute(pDataUnits[i]);
units.add(pChecker[i].check(pStages[i].getConnection()));
// Some output that makes watching the pdus easiert
/*
* System.out.println("************** STAGE UNIT *************** ");
* System.out.println(pStages[i].getClass());
* System.out.println();
* System.out.println(units.get(i));*
*/
}
verify(connection, times(9)).sendPdu(captor.capture());
// Some output that makes watching the pdus easiert
/*
* for (int i = 0; i < 8; i++) {
* if (captor.getAllValues().get(i).getBasicHeaderSegment().getParser() instanceof DataInParser)
* continue;
*
* System.out.println("************** TEST UNIT *************** ");
* if (i > 0)
* System.out.println(pStages[i].getClass() + "(" + (pStages[i - 1].getClass()) + ")");
* else
* System.out.println(pStages[i].getClass());
* System.out.println();
* System.out.println(captor.getAllValues().get(i));
* }
*/
for (int i = 0; i < units.size(); i++) {
if (captor.getAllValues().get(0).getBasicHeaderSegment().getParser() instanceof DataInParser == false)
assertEquals(units.remove(0), captor.getAllValues().remove(0));
else
captor.getAllValues().remove(0);
}
}
@DataProvider(name = "instantiateStages")
public Object[][] provideStages() {
// special pdu for textnegotation
final ProtocolDataUnit textNegotationUnit =
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_TM_REQUEST, "None", "None");
textNegotationUnit.setDataSegment(ByteBuffer.wrap("hello world".getBytes()));
// setting up the connection properly
SessionSettingsNegotiator sessionSettingsNegotiator = new SessionSettingsNegotiator();
ConnectionSettingsNegotiator connectionSettingsNegotiator =
new ConnectionSettingsNegotiator(sessionSettingsNegotiator);
final TargetSession session = mock(TargetSession.class);
when(connection.getSettings()).thenReturn(connectionSettingsNegotiator.getSettings());
// setting up the phases
TargetFullFeaturePhase phase = new TargetFullFeaturePhase(connection);
Object[][] returnVal =
{
{
TargetStage.class,
new TargetStage[] {
new TestUnitReadyStage(phase), new SendDiagnosticStage(phase),
new ReportLunsStage(phase), new InquiryStage(phase), new RequestSenseStage(phase),
new TextNegotiationStage(phase), new UnsupportedOpCodeStage(phase),
new FormatUnitStage(phase)
},
ProtocolDataUnit.class,
new ProtocolDataUnit[] {
// TextUnitReadyStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None",
"None"),
// SendDiagnosticStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None",
"None"),
// ReportLunsStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None",
"None"),
// InquiryStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None",
"None"),
// RequestSenseStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None",
"None"),
// TextNegotiationStage
textNegotationUnit,
// UnsupportedOpCodeStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_TM_REQUEST,
"None", "None"),
// FormatUnitStage
new ProtocolDataUnitFactory().create(false, true, OperationCode.SCSI_COMMAND, "None",
"None")
}, Checker.class, new Checker[] {
// TestUnitReadyStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_COMMAND, "None", "None").getBasicHeaderSegment();
// Taken from the stage
responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
false,// residualOverflow
false,// residualUnderflow,
SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
SCSIStatus.GOOD,// status,
bhs.getInitiatorTaskTag(),// initiatorTaskTag,
0,// snackTag
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
0,// residualCount
ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// data
// segment
return responsePdu;
}
}, // SendDiagnosticStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_COMMAND, "None", "None").getBasicHeaderSegment();
final SCSICommandParser parser = (SCSICommandParser)bhs.getParser();
final SendDiagnosticCdb cdb = new SendDiagnosticCdb(parser.getCDB());
// create the whole sense data
FixedFormatSenseData senseData = new FixedFormatSenseData(false,// valid
ErrorType.CURRENT,// error type
false,// file mark
false,// end of medium
false,// incorrect length indicator
SenseKey.ILLEGAL_REQUEST,// sense key
new FourByteInformation(),// information
new FourByteInformation(),// command specific information
AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB,// additional sense
// code and
// qualifier
(byte)0,// field replaceable unit code
cdb.getIllegalFieldPointers()[0],// sense key specific data, only report
// first problem
new AdditionalSenseBytes());// additional sense bytes
// keep only the part of the sense data that will be sent
final ScsiResponseDataSegment dataSegment =
new ScsiResponseDataSegment(senseData, parser
.getExpectedDataTransferLength());
final int senseDataSize = senseData.size();
// calculate residuals and flags
final int residualCount =
Math.abs(parser.getExpectedDataTransferLength() - senseDataSize);
final boolean residualOverflow =
parser.getExpectedDataTransferLength() < senseDataSize;
final boolean residualUnderflow =
parser.getExpectedDataTransferLength() > senseDataSize;
// create and return PDU
responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
residualOverflow,// residualOverflow
residualUnderflow,// residualUnderflow,
SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
SCSIStatus.CHECK_CONDITION,// status,
bhs.getInitiatorTaskTag(),// initiatorTaskTag,
0,// snackTag
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
residualCount,// residualCount
dataSegment);// data segment
return responsePdu;
}
}, // ReportLunsStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_COMMAND, "None", "None").getBasicHeaderSegment();
final SCSICommandParser parser = (SCSICommandParser)bhs.getParser();
final ReportLunsCDB cdb = new ReportLunsCDB(parser.getCDB());
final FieldPointerSenseKeySpecificData[] illegalFieldPointers =
cdb.getIllegalFieldPointers();
FixedFormatSenseData senseData = new FixedFormatSenseData(false,// valid
ErrorType.CURRENT,// error type
false,// file mark
false,// end of medium
false,// incorrect length indicator
SenseKey.ILLEGAL_REQUEST,// sense key
new FourByteInformation(),// information
new FourByteInformation(),// command specific information
AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB,// additional sense
// code and
// qualifier
(byte)0,// field replaceable unit code
illegalFieldPointers[0],// sense key specific data, only report
// first problem
new AdditionalSenseBytes());// additional sense bytes
// keep only the part of the sense data that will be sent
final ScsiResponseDataSegment dataSegment =
new ScsiResponseDataSegment(senseData, parser
.getExpectedDataTransferLength());
final int senseDataSize = senseData.size();
// calculate residuals and flags
final int residualCount =
Math.abs(parser.getExpectedDataTransferLength() - senseDataSize);
final boolean residualOverflow =
parser.getExpectedDataTransferLength() < senseDataSize;
final boolean residualUnderflow =
parser.getExpectedDataTransferLength() > senseDataSize;
// create and return PDU
responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
residualOverflow,// residualOverflow
residualUnderflow,// residualUnderflow,
SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
SCSIStatus.CHECK_CONDITION,// status,
bhs.getInitiatorTaskTag(),// initiatorTaskTag,
0,// snackTag
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
residualCount,// residualCount
dataSegment);// data segment
// send response
return responsePdu;
}
}, // InquiryStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_COMMAND, "None", "None").getBasicHeaderSegment();
final SCSICommandParser parser = (SCSICommandParser)bhs.getParser();
final InquiryCDB cdb = new InquiryCDB(parser.getCDB());
IResponseData responseData = null;
if (!cdb.getEnableVitalProductData()) {
responseData = StandardInquiryData.getInstance();
} else {
final VitalProductDataPageName pageName =
cdb.getPageCode().getVitalProductDataPageName();
switch (pageName) {// is never null
case SUPPORTED_VPD_PAGES:
responseData = SupportedVpdPages.getInstance();
break;
case DEVICE_IDENTIFICATION:
responseData =
session.getDeviceIdentificationVpdPage(); // OODRIVE
break;
default:
throw new InternetSCSIException();
}
}
// The part from the targetfullfeaturephase
final ByteBuffer fullBuffer = ByteBuffer.allocate(responseData.size());
responseData.serialize(fullBuffer, 0);
ByteBuffer trimmedBuffer;
if (fullBuffer.capacity() <= parser.getExpectedDataTransferLength()) {
trimmedBuffer = fullBuffer;
} else {
trimmedBuffer =
ByteBuffer.allocate(parser.getExpectedDataTransferLength());
trimmedBuffer.put(fullBuffer.array(),// source array
0,// offset in source
parser.getExpectedDataTransferLength());// length
}
final boolean residualOverflow =
parser.getExpectedDataTransferLength() < fullBuffer.capacity();
final boolean residualUnderflow =
parser.getExpectedDataTransferLength() > fullBuffer.capacity();
final int residualCount =
Math.abs(parser.getExpectedDataTransferLength() - fullBuffer.capacity());
responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
residualOverflow,// residualOverflow
residualUnderflow,// residualUnderflow
ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
SCSIStatus.GOOD,// status
bhs.getInitiatorTaskTag(), 0,// snackTag, reserved
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
residualCount,// residualCount
ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// scsiResponseDataSegment
return responsePdu;
}
}, // RequestSenseStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_COMMAND, "None", "None").getBasicHeaderSegment();
final SCSICommandParser parser = (SCSICommandParser)bhs.getParser();
final RequestSenseCdb cdb = new RequestSenseCdb(parser.getCDB());
SenseData senseData;
final SenseKey senseKey = SenseKey.NO_SENSE;
final AdditionalSenseCodeAndQualifier additionalSense =
AdditionalSenseCodeAndQualifier.NO_ADDITIONAL_SENSE_INFORMATION;
if (cdb.getDescriptorFormat()) {
senseData = new DescriptorFormatSenseData(ErrorType.CURRENT,// errorType
senseKey,// sense key
additionalSense,// additional sense code and qualifier
new SenseDataDescriptor[0]);// sense data descriptors
} else {
senseData = new FixedFormatSenseData(false,// valid
ErrorType.CURRENT,// error type
false,// file mark
false,// end of medium
false,// incorrect length indicator
senseKey,// sense key
new FourByteInformation(),// information
new FourByteInformation(),// command specific
// information
additionalSense,// additional sense code and qualifier
(byte)0,// field replaceable unit code
null,// sense key specific data, only report first
// problem
null);// additional sense bytes
}
responsePdu =
TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
false,// residualOverflow
false,// residualUnderflow,
SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
SCSIStatus.GOOD,// status,
bhs.getInitiatorTaskTag(),// initiatorTaskTag,
0,// snackTag
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
0,// residualCount
new ScsiResponseDataSegment(senseData, parser
.getExpectedDataTransferLength()));
return responsePdu;
}
}, // TextNegotiationStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException,
SettingsException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs = textNegotationUnit.getBasicHeaderSegment();
final int initiatorTaskTag = bhs.getInitiatorTaskTag();
final String textRequest =
new String(textNegotationUnit.getDataSegment().array());
ByteBuffer replyDataSegment = null;// for later
// tokenize key-value pairs
final List<String> requestKeyValuePairs =
TextParameter.tokenizeKeyValuePairs(textRequest);
final List<String> responseKeyValuePairs = new Vector<String>();
// process SendTargets command
if (requestKeyValuePairs != null) {
String sendTargetsValue = null;
if (requestKeyValuePairs.size() == 1)
sendTargetsValue =
TextParameter.getSuffix(requestKeyValuePairs.get(0),// string
TextKeyword.SEND_TARGETS + TextKeyword.EQUALS);// prefix
if (sendTargetsValue != null) {
final boolean normal = session.isNormalSession();
final boolean sendTargetName = // see upper table
!normal && sendTargetsValue.equals(TextKeyword.ALL);
final boolean sendTargetAddress = // see upper table
(!normal && sendTargetsValue.equals(TextKeyword.ALL))
|| (session.getTargetServer()
.isValidTargetName(sendTargetsValue))
|| (normal && sendTargetsValue.length() == 0);
// add TargetName
if (sendTargetName) {
for (String curTargetName : session.getTargetServer()
.getTargetNames()) {
responseKeyValuePairs.add(TextParameter.toKeyValuePair(
TextKeyword.TARGET_NAME, curTargetName));
// add TargetAddress
if (sendTargetAddress)
responseKeyValuePairs.add(TextParameter.toKeyValuePair(
TextKeyword.TARGET_ADDRESS, session.getTargetServer()
.getConfig().getTargetAddress()
+ // domain
TextKeyword.COLON + // :
session.getTargetServer().getConfig().getPort() + // port
TextKeyword.COMMA + // ,
session.getTargetServer().getConfig()
.getTargetPortalGroupTag())); // groupTag)
}
} else {
// We're here if they sent us a target name and are asking for the
// address (I think)
if (sendTargetAddress)
responseKeyValuePairs.add(TextParameter.toKeyValuePair(
TextKeyword.TARGET_ADDRESS, session.getTargetServer()
.getConfig().getTargetAddress()
+ // domain
TextKeyword.COLON + // :
session.getTargetServer().getConfig().getPort() + // port
TextKeyword.COMMA + // ,
session.getTargetServer().getConfig()
.getTargetPortalGroupTag())); // groupTag)
}
}
// concatenate and serialize reply
final String replyString =
TextParameter.concatenateKeyValuePairs(responseKeyValuePairs);
replyDataSegment =
ReadWrite.stringToTextDataSegments(replyString, connection
.getSettings().getMaxRecvDataSegmentLength())[0];
}
responsePdu = TargetPduFactory.createTextResponsePdu(true,// finalFlag
false,// continueFlag
0,// logicalUnitNumber
initiatorTaskTag, 0xffffffff,// targetTransferTag
replyDataSegment);// dataSegment
return responsePdu;
}
}, // UnsupportedOpCodeStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_TM_REQUEST, "None", "None")
.getBasicHeaderSegment();
final InitiatorMessageParser parser = (InitiatorMessageParser)bhs.getParser();
final FieldPointerSenseKeySpecificData fp =
new FieldPointerSenseKeySpecificData(true,// senseKeySpecificDataValid
true,// commandData (i.e. invalid field in CDB)
false,// bitPointerValid
0,// bitPointer, reserved since invalid
0);// fieldPointer to the SCSI OpCode field
final FieldPointerSenseKeySpecificData[] fpArray =
new FieldPointerSenseKeySpecificData[] {
fp
};
// create the whole sense data
FixedFormatSenseData senseData = new FixedFormatSenseData(false,// valid
ErrorType.CURRENT,// error type
false,// file mark
false,// end of medium
false,// incorrect length indicator
SenseKey.ILLEGAL_REQUEST,// sense key
new FourByteInformation(),// information
new FourByteInformation(),// command specific information
AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB,// additional sense
// code and
// qualifier
(byte)0,// field replaceable unit code
fpArray[0],// sense key specific data, only report
// first problem
new AdditionalSenseBytes());// additional sense bytes
// keep only the part of the sense data that will be sent
final ScsiResponseDataSegment dataSegment =
new ScsiResponseDataSegment(senseData, parser
.getExpectedStatusSequenceNumber());
final int senseDataSize = senseData.size();
// calculate residuals and flags
final int residualCount =
Math.abs(parser.getExpectedStatusSequenceNumber() - senseDataSize);
final boolean residualOverflow =
parser.getExpectedStatusSequenceNumber() < senseDataSize;
final boolean residualUnderflow =
parser.getExpectedStatusSequenceNumber() > senseDataSize;
// create and return PDU
responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
residualOverflow,// residualOverflow
residualUnderflow,// residualUnderflow,
SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
SCSIStatus.CHECK_CONDITION,// status,
bhs.getInitiatorTaskTag(),// initiatorTaskTag,
0,// snackTag
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
residualCount,// residualCount
dataSegment);// data segment
return responsePdu;
}
}, // FormatUnitStage checker
new Checker() {
@Override
public ProtocolDataUnit check(final Connection pConnection)
throws InterruptedException, IOException, InternetSCSIException {
ProtocolDataUnit responsePdu;
final BasicHeaderSegment bhs =
new ProtocolDataUnitFactory().create(false, true,
OperationCode.SCSI_COMMAND, "None", "None").getBasicHeaderSegment();
final SCSICommandParser parser = (SCSICommandParser)bhs.getParser();
// Taken from the stage
final int residualCount =
Math.abs(parser.getExpectedDataTransferLength() - 0);
final boolean residualOverflow = parser.getExpectedDataTransferLength() < 0;
final boolean residualUnderflow = parser.getExpectedDataTransferLength() > 0;
responsePdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
false,// bidirectionalReadResidualUnderflow
residualOverflow,// residualOverflow,
residualUnderflow,// residualUnderflow,
SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
SCSIStatus.GOOD,// status
bhs.getInitiatorTaskTag(),// initiatorTaskTaginstantiateStages
0,// snackTag
0,// expectedDataSequenceNumber
0,// bidirectionalReadResidualCount
residualCount,// residualCount
ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// data segment
return responsePdu;
}
}
}
}
};
return returnVal;
}
static interface Checker {
ProtocolDataUnit check(final Connection pConnection) throws InterruptedException, IOException,
InternetSCSIException, SettingsException;
}
}