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.parser.scsi.SCSIResponseParser; import org.jscsi.parser.scsi.SCSIStatus; import org.jscsi.target.connection.TargetPduFactory; import org.jscsi.target.connection.phase.TargetFullFeaturePhase; import org.jscsi.target.scsi.ScsiResponseDataSegment; import org.jscsi.target.scsi.cdb.RequestSenseCdb; 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.SettingsException; /** * A stage for processing <code>REQUEST SENSE</code> SCSI commands. * <p> * The <code>REQUEST SENSE</code> command requests that the device server transfer {@link SenseData} to the * application client. * * @author Andreas Ergenzinger */ public class RequestSenseStage extends TargetFullFeatureStage { public RequestSenseStage(TargetFullFeaturePhase targetFullFeaturePhase) { super(targetFullFeaturePhase); } @Override public void execute(ProtocolDataUnit pdu) throws IOException, InterruptedException, InternetSCSIException, DigestException, SettingsException { final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); final SCSICommandParser parser = (SCSICommandParser)bhs.getParser(); ProtocolDataUnit responsePDU = null;// the response PDU // get command details in CDB final RequestSenseCdb cdb = new RequestSenseCdb(parser.getCDB()); final FieldPointerSenseKeySpecificData[] illegalFieldPointers = cdb.getIllegalFieldPointers(); if (illegalFieldPointers != null) { // an illegal request has been made SenseData senseData; if (cdb.getDescriptorFormat()) { // descriptor format sense data has been requested senseData = new DescriptorFormatSenseData(ErrorType.CURRENT,// errorType SenseKey.ILLEGAL_REQUEST,// sense key AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB,// additional // sense // code // and // qualifier new SenseDataDescriptor[0]);// sense data descriptors } else { // fixed format sense data has been requested 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 } responsePDU = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow false,// bidirectionalReadResidualUnderflow false,// residualOverflow false,// residualUnderflow, SCSIResponseParser.ServiceResponse.TARGET_FAILURE,// response, SCSIStatus.CHECK_CONDITION,// status, bhs.getInitiatorTaskTag(),// initiatorTaskTag, 0,// snackTag 0,// expectedDataSequenceNumber 0,// bidirectionalReadResidualCount 0,// residualCount new ScsiResponseDataSegment(senseData, parser.getExpectedDataTransferLength()));// data // segment } else { /* * PDU is okay * * carry out command * * Sense data shall be available and cleared under the conditions * defined in SAM-3. If the device server has no other sense data * available to return, it shall return the sense key set to NO * SENSE and the additional sense code set to NO ADDITIONAL SENSE * INFORMATION. This will always be the case with the jSCSI Target. */ SenseData senseData; final SenseKey senseKey = SenseKey.NO_SENSE; final AdditionalSenseCodeAndQualifier additionalSense = AdditionalSenseCodeAndQualifier.NO_ADDITIONAL_SENSE_INFORMATION; if (cdb.getDescriptorFormat()) { // descriptor format sense data has been requested senseData = new DescriptorFormatSenseData(ErrorType.CURRENT,// errorType senseKey,// sense key additionalSense,// additional sense code and qualifier new SenseDataDescriptor[0]);// sense data descriptors } else { // fixed format sense data has been requested 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()));// data // segment } // send response connection.sendPdu(responsePDU); } }