Package org.jscsi.target.connection.stage.fullfeature

Source Code of org.jscsi.target.connection.stage.fullfeature.TargetFullFeatureStage

package org.jscsi.target.connection.stage.fullfeature;

import java.io.IOException;
import java.nio.ByteBuffer;

import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.ProtocolDataUnit;
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.connection.stage.TargetStage;
import org.jscsi.target.scsi.IResponseData;
import org.jscsi.target.scsi.ScsiResponseDataSegment;
import org.jscsi.target.scsi.sense.AdditionalSenseBytes;
import org.jscsi.target.scsi.sense.AdditionalSenseCodeAndQualifier;
import org.jscsi.target.scsi.sense.ErrorType;
import org.jscsi.target.scsi.sense.FixedFormatSenseData;
import org.jscsi.target.scsi.sense.SenseKey;
import org.jscsi.target.scsi.sense.information.FourByteInformation;
import org.jscsi.target.scsi.sense.senseDataDescriptor.senseKeySpecific.FieldPointerSenseKeySpecificData;

/**
* This class is an abstract super-class for stages of the {@link TargetFullFeaturePhase}.
*
* @see TargetStage
* @author Andreas Ergenzinger
*/
public abstract class TargetFullFeatureStage extends TargetStage {

    /**
     * The abstract constructor.
     *
     * @param targetFullFeaturePhase
     *            the phase this stage is a part of
     */
    public TargetFullFeatureStage(TargetFullFeaturePhase targetFullFeaturePhase) {
        super(targetFullFeaturePhase);
    }

    /**
     * Creates a PDU with {@link FixedFormatSenseData} that must be sent to the initiator after receiving a
     * Command
     * Descriptor Block with an illegal field.
     *
     * @param senseKeySpecificData
     *            contains a list of all illegal fields
     * @param additionalSenseCodeAndQualifier
     *            provides more specific information about the cause of the check condition
     * @param initiatorTaskTag
     *            used by the initiator to identify the task
     * @param expectedDataTransferLength
     *            the amount of payload data expected by the initiator (i.e. allocated buffer
     *            space)
     * @return the error PDU
     */
    protected static final ProtocolDataUnit createFixedFormatErrorPdu(
        final FieldPointerSenseKeySpecificData[] senseKeySpecificData,
        final AdditionalSenseCodeAndQualifier additionalSenseCodeAndQualifier, final int initiatorTaskTag,
        final int expectedDataTransferLength) {

        // 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,// additional sense code and
                                            // qualifier
            (byte)0,// field replaceable unit code
            senseKeySpecificData[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, expectedDataTransferLength);
        final int senseDataSize = senseData.size();

        // calculate residuals and flags
        final int residualCount = Math.abs(expectedDataTransferLength - senseDataSize);
        final boolean residualOverflow = expectedDataTransferLength < senseDataSize;
        final boolean residualUnderflow = expectedDataTransferLength > senseDataSize;

        // create and return PDU
        return TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
            false,// bidirectionalReadResidualUnderflow
            residualOverflow,// residualOverflow
            residualUnderflow,// residualUnderflow,
            SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response,
            SCSIStatus.CHECK_CONDITION,// status,
            initiatorTaskTag,// initiatorTaskTag,
            0,// snackTag
            0,// expectedDataSequenceNumber
            0,// bidirectionalReadResidualCount
            residualCount,// residualCount
            dataSegment);// data segment
    }

    /**
     * Creates a PDU with {@link FixedFormatSenseData} that must be sent to the initiator after receiving a
     * Command
     * Descriptor Block with an illegal field, which requires the the additional sense code
     * {@link AdditionalSenseCodeAndQualifier#INVALID_FIELD_IN_CDB}.
     *
     * @param senseKeySpecificData
     *            contains a list of all illegal fields
     * @param initiatorTaskTag
     *            used by the initiator to identify the task
     * @param expectedDataTransferLength
     *            the amount of payload data expected by the initiator (i.e. allocated buffer
     *            space)
     * @return the error PDU
     */
    protected static final ProtocolDataUnit createFixedFormatErrorPdu(
        final FieldPointerSenseKeySpecificData[] senseKeySpecificData, final int initiatorTaskTag,
        final int expectedDataTransferLength) {
        return createFixedFormatErrorPdu(senseKeySpecificData,
            AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB, initiatorTaskTag,
            expectedDataTransferLength);
    }

    /**
     * Creates a SCSI Response PDU with a length zero data segment. Objects created with this method can be
     * used as
     * replies in task terminating with {@link SCSIStatus#GOOD} which do not require additional data to be
     * transfered,
     * or for creating follow-up PDU with {@link SCSIStatus#CHECK_CONDITION} status sent after Data-In PDUs
     * with sense
     * data.
     *
     * @param status
     *            the SCSI status of the task
     * @param initiatorTaskTag
     *            used by the initiator to identify the task
     * @param expectedDataTransferLength
     *            total amount of payload data in bytes expected by the initiator
     * @param responseDataSize
     *            actual amount of payload data in bytes sent by the target
     * @return the SCSI Response PDU
     */
    protected static final ProtocolDataUnit createScsiResponsePdu(final SCSIStatus status,
        final int initiatorTaskTag, final int expectedDataTransferLength, final int responseDataSize) {

        // calculate residuals and flags
        final int residualCount = Math.abs(expectedDataTransferLength - responseDataSize);
        final boolean residualOverflow = expectedDataTransferLength < responseDataSize;
        final boolean residualUnderflow = expectedDataTransferLength > responseDataSize;

        return TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
            false,// bidirectionalReadResidualUnderflow
            residualOverflow,// residualOverflow,
            residualUnderflow,// residualUnderflow,
            SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
            status,// status
            initiatorTaskTag,// initiatorTaskTag
            0,// snackTag
            0,// expectedDataSequenceNumber
            0,// bidirectionalReadResidualCount
            residualCount,// residualCount
            ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// data segment
    }

    /**
     * Sends a two byte sequence of a Data-In and a SCSI Response PDU with the specified <i>responseData</i>
     * payload to
     * the initiator.
     *
     * @param initiatorTaskTag
     *            used by the initiator to identify the task
     * @param expectedDataTransferLength
     *            the total amount of payload data in bytes expected by the initiator
     *            <p>
     *            The method might throw exceptions during PDU serialization and sending.
     * @param responseData
     *            the data requested by the initiator
     * @throws InterruptedException
     * @throws IOException
     * @throws InternetSCSIException
     */
    protected final void sendResponse(final int initiatorTaskTag, final int expectedDataTransferLength,
        final IResponseData responseData) throws InterruptedException, IOException, InternetSCSIException {

        // serialize all response data
        final ByteBuffer fullBuffer = ByteBuffer.allocate(responseData.size());
        responseData.serialize(fullBuffer, 0);
       
        // copy fullBuffer to buffer with size trimmed to
        // expectedDataTransferLength
        ByteBuffer trimmedBuffer;
        if (fullBuffer.capacity() <= expectedDataTransferLength) {
            // no trimming
            trimmedBuffer = fullBuffer;
        } else {
            trimmedBuffer = ByteBuffer.allocate(expectedDataTransferLength);
            trimmedBuffer.put(fullBuffer.array(),// source array
                0,// offset in source
                expectedDataTransferLength);// length
        }

        // coompute residual count and associated flags
        final boolean residualOverflow = expectedDataTransferLength < fullBuffer.capacity();
        final boolean residualUnderflow = expectedDataTransferLength > fullBuffer.capacity();
        final int residualCount = Math.abs(expectedDataTransferLength - fullBuffer.capacity());

        // create and send PDU
        ProtocolDataUnit pdu = TargetPduFactory.createDataInPdu(true,// finalFlag
            false,// acknowledgeFlag always false
            residualOverflow,// residualOverflowFlag x
            residualUnderflow,// residualUnderflowFlag x
            true,// statusFlag
            SCSIStatus.GOOD,// status, reserved
            0,// logicalUnitNumber reserved
            initiatorTaskTag,// initiatorTaskTag
            -1,// targetTransferTag reserved
            0,// dataSequenceNumber
            0,// bufferOffset
            residualCount,// residualCount x
            trimmedBuffer);// dataSegment

        connection.sendPdu(pdu);
       
        //        VirtualBox was not working with the success message sent via ScsiResponse ..
        //        Deactivated this method and set the data-in pdu up to take over the success
        //        notification.
        //        pdu = TargetPduFactory.createSCSIResponsePdu(false,// bidirectionalReadResidualOverflow
        //            false,// bidirectionalReadResidualUnderflow
        //            residualOverflow,// residualOverflow
        //            residualUnderflow,// residualUnderflow
        //            ServiceResponse.COMMAND_COMPLETED_AT_TARGET,// response
        //            SCSIStatus.GOOD,// status
        //            initiatorTaskTag, 0,// snackTag, reserved
        //            0,// expectedDataSequenceNumber
        //            0,// bidirectionalReadResidualCount
        //            residualCount,// residualCount
        //            ScsiResponseDataSegment.EMPTY_DATA_SEGMENT);// scsiResponseDataSegment
        //
        //        connection.sendPdu(pdu);

    }
}
TOP

Related Classes of org.jscsi.target.connection.stage.fullfeature.TargetFullFeatureStage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.