package org.jscsi.target.connection.stage.fullfeature;
import java.io.IOException;
import java.security.DigestException;
import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.BasicHeaderSegment;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.scsi.SCSICommandParser;
import org.jscsi.target.connection.phase.TargetFullFeaturePhase;
import org.jscsi.target.scsi.cdb.ReadCapacity10Cdb;
import org.jscsi.target.scsi.cdb.ReadCapacity16Cdb;
import org.jscsi.target.scsi.cdb.ReadCapacityCdb;
import org.jscsi.target.scsi.cdb.ScsiOperationCode;
import org.jscsi.target.scsi.readCapacity.ReadCapacity10ParameterData;
import org.jscsi.target.scsi.readCapacity.ReadCapacity16ParameterData;
import org.jscsi.target.scsi.readCapacity.ReadCapacityParameterData;
import org.jscsi.target.scsi.sense.AdditionalSenseCodeAndQualifier;
import org.jscsi.target.scsi.sense.senseDataDescriptor.senseKeySpecific.FieldPointerSenseKeySpecificData;
import org.jscsi.target.settings.SettingsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class ReadCapacityStage extends TargetFullFeatureStage {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadCapacityStage.class);
public ReadCapacityStage(final TargetFullFeaturePhase targetFullFeaturePhase) {
super(targetFullFeaturePhase);
}
@Override
public void execute(ProtocolDataUnit pdu) throws IOException, InterruptedException,
InternetSCSIException, DigestException, SettingsException {
// find out the type of READ CAPACITY command ((10) or (16))
final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
final SCSICommandParser parser = (SCSICommandParser)bhs.getParser();
final ScsiOperationCode opCode = ScsiOperationCode.valueOf(parser.getCDB().get(0));
ReadCapacityCdb cdb;
if (opCode == ScsiOperationCode.READ_CAPACITY_10)
cdb = new ReadCapacity10Cdb(parser.getCDB());
else if (opCode == ScsiOperationCode.READ_CAPACITY_16)
cdb = new ReadCapacity16Cdb(parser.getCDB());
else {
// programmer error, we should not be here, close the connection
throw new InternetSCSIException("wrong SCSI Operation Code " + opCode + " in ReadCapacityStage");
}
/*
* Everything is fine, carry on.
*
* The PMI bit of the command descriptor block is ignored, since there
* is no way to know if "substantial vendor specific delay in data
* transfer may be encountered" after the address in the LOGICAL BLOCK
* ADDRESS field. Therefore we always try to return the whole length of
* the storage medium.
*/
// make sure that the LOGICAL BLOCK ADDRESS field is valid and send
// appropriate response
if (session.getStorageModule().checkBounds(cdb.getLogicalBlockAddress(), 0) != 0) {
// invalid, log error, send error PDU, and return
LOGGER.error("encountered " + cdb.getClass() + " in ReadCapacityStage with "
+ "LOGICAL BLOCK ADDRESS = " + cdb.getLogicalBlockAddress());
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
};
final ProtocolDataUnit responsePdu = createFixedFormatErrorPdu(fpArray,// senseKeySpecificData
AdditionalSenseCodeAndQualifier.LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,// additionalSenseCodeAndQualifier
bhs.getInitiatorTaskTag(),// initiatorTaskTag
parser.getExpectedDataTransferLength());// expectedDataTransferLength
connection.sendPdu(responsePdu);
return;
} else {
// send PDU with requested READ CAPACITY parameter data
ReadCapacityParameterData parameterData;
if (cdb instanceof ReadCapacity10Cdb)
parameterData = new ReadCapacity10ParameterData(session.getStorageModule().getSizeInBlocks()-1,// returnedLogicalBlockAddress
session.getStorageModule().getBlockSize());// logicalBlockLengthInBytes
else
parameterData = new ReadCapacity16ParameterData(session.getStorageModule().getSizeInBlocks()-1,// returnedLogicalBlockAddress
session.getStorageModule().getBlockSize());// logicalBlockLengthInBytes
sendResponse(bhs.getInitiatorTaskTag(),// initiatorTaskTag,
parser.getExpectedDataTransferLength(),// expectedDataTransferLength,
parameterData);// responseData
}
}
}