All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jscsi.parser.data.DataInParser Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
 * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.jscsi.parser.data;


import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.Constants;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.TargetMessageParser;
import org.jscsi.parser.datasegment.DataSegmentFactory.DataSegmentFormat;
import org.jscsi.parser.scsi.SCSIStatus;
import org.jscsi.utils.Utils;


/**
 * This class parses a Data-In message defined in the iSCSI Standard (RFC3720).
 * 
 * @author Volker Wildi
 */
public class DataInParser extends TargetMessageParser {

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /** Acknowledge flag mask. */
    private static final int ACKNOWLEDGE_FLAG_MASK = 0x00400000;

    /** Status flag mask to extract. */
    private static final int STATUS_FLAG_MASK = 0x00010000;

    /** Bit mask, where the 11th, 12th and the 13th bit are set. */
    private static final int BIT_11_TO_13_FLAG_MASK = 0x00380000;

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /** The acknowledge Flag. */
    private boolean acknowledgeFlag;

    /** The Bidirectional Read Residual Overflow Flag (o bit). */
    private boolean bidirectionalReadResidualOverflow;

    /** The Bidirectional Read Residual Underflow Flag (u bit). */
    private boolean bidirectionalReadResidualUnderflow;

    /** The Residual Overflow Flag (O bit). */
    private boolean residualOverflow;

    /** The Residual Underflow Flag (U bit). */
    private boolean residualUnderflow;

    /** The Status Flag (S bit). */
    private boolean statusFlag;

    /** The status code. */
    private SCSIStatus status;

    /** The Data Sequence Number. */
    private int dataSequenceNumber;

    /** The Buffer Offset. */
    private int bufferOffset;

    /** The Residual Count. */
    private int residualCount;

    /** The Target Transfer Tag. */
    private int targetTransferTag;

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /**
     * Default constructor, creates a new, empty DataInParser object.
     * 
     * @param initProtocolDataUnit The reference ProtocolDataUnit instance, which contains this
     *            DataInParser subclass object.
     */
    public DataInParser (final ProtocolDataUnit initProtocolDataUnit) {

        super(initProtocolDataUnit);
    }

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /** {@inheritDoc} */
    @Override
    public String getShortInfo () {

        return super.getShortInfo() + ", dataSN: " + dataSequenceNumber + ", bufferOffset: " + bufferOffset;
    }

    /** {@inheritDoc} */
    @Override
    public String toString () {

        final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE);

        Utils.printField(sb, "StatusFlag", statusFlag, 1);
        Utils.printField(sb, "Status", status.value(), 1);
        Utils.printField(sb, "LUN", logicalUnitNumber, 1);
        Utils.printField(sb, "Target Task tag", targetTransferTag, 1);
        Utils.printField(sb, "StatSN", statusSequenceNumber, 1);
        Utils.printField(sb, "MaxCmdSN", maximumCommandSequenceNumber, 1);
        Utils.printField(sb, "DataSN", dataSequenceNumber, 1);
        Utils.printField(sb, "Buffer Offset", bufferOffset, 1);
        Utils.printField(sb, "Residual Count", residualCount, 1);
        sb.append(super.toString());

        return sb.toString();
    }

    /** {@inheritDoc} */
    @Override
    public DataSegmentFormat getDataSegmentFormat () {

        return DataSegmentFormat.BINARY;
    }

    /** {@inheritDoc} */
    @Override
    public void clear () {

        super.clear();

        acknowledgeFlag = false;
        bidirectionalReadResidualOverflow = false;
        bidirectionalReadResidualUnderflow = false;
        residualOverflow = false;
        residualUnderflow = false;
        statusFlag = false;

        status = null;

        dataSequenceNumber = 0;
        bufferOffset = 0;
        residualCount = 0;
        targetTransferTag = 0;
    }

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /** {@inheritDoc} */
    @Override
    public final boolean incrementSequenceNumber () {

        return isStatusFlag();
    }

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /**
     * The Buffer Offset field contains the offset of this PDU payload data within the complete data transfer. The sum
     * of the buffer offset and length should not exceed the expected transfer length for the command.
* The order of data PDUs within a sequence is determined by DataPDUInOrder. When set to Yes, it means that PDUs * have to be in increasing Buffer Offset order and overlays are forbidden.
* The ordering between sequences is determined by DataSequenceInOrder. When set to Yes, it means that sequences * have to be in increasing Buffer Offset order and overlays are forbidden. * * @return The buffer offset of this DataInParser object. */ public int getBufferOffset () { return bufferOffset; } /** * For input (read) or bidirectional Data-In PDUs, the DataSN is the input PDU number within the data transfer for * the command identified by the Initiator Task Tag.
* R2T and Data-In PDUs, in the context of bidirectional commands, share the numbering sequence (see Section 3.2.2.3 * Data Sequencing).
* For output (write) data PDUs, the DataSN is the Data-Out PDU number within the current output sequence. The * current output sequence is either identified by the Initiator Task Tag (for unsolicited data) or is a data * sequence generated for one R2T (for data solicited through R2T). * * @return The Data Sequence Number of this DataInParser object. */ public int getDataSequenceNumber () { return dataSequenceNumber; } /** * The Residual Count field MUST be valid in the case where either the U bit or the O bit is set. If neither bit is * set, the Residual Count field is reserved. Targets may set the residual count and initiators may use it when the * response code is "completed at target" (even if the status returned is not GOOD). If the O bit is set, the * Residual Count indicates the number of bytes that were not transferred because the initiator’s Expected Data * Transfer Length was not sufficient. If the U bit is set, the Residual Count indicates the number of bytes that * were not transferred out of the number of bytes expected to be transferred. * * @return The Residual Count of this object. */ public int getResidualCount () { return residualCount; } /** * On outgoing data, the Target Transfer Tag is provided to the target if the transfer is honoring an R2T. In this * case, the Target Transfer Tag field is a replica of the Target Transfer Tag provided with the R2T.
* On incoming data, the Target Transfer Tag and LUN MUST be provided by the target if the A bit is set to * 1; otherwise they are reserved. The Target Transfer Tag and LUN are copied by the initiator into the * SNACK of type DataACK that it issues as a result of receiving a SCSI Data-In PDU with the A bit set to * 1.
* The Target Transfer Tag values are not specified by this protocol except that the value 0xffffffff * is reserved and means that the Target Transfer Tag is not supplied. If the Target Transfer Tag is provided, then * the LUN field MUST hold a valid value and be consistent with whatever was specified with the command; otherwise, * the LUN field is reserved. * * @return Returns the Target Transfer Tag of this DataInParser object. */ public int getTargetTaskTag () { return targetTransferTag; } /** * For sessions with ErrorRecoveryLevel 1 or higher, the target sets this bit to 1 to * indicate that it requests a positive acknowledgement from the initiator for the data received. The target should * use the A bit moderately; it MAY only set the A bit to 1 once every MaxBurstLength bytes, or on the * last Data-In PDU that concludes the entire requested read data transfer for the task from the target’s * perspective, and it MUST NOT do so more frequently. The target MUST NOT set to 1 the A * bit for sessions with ErrorRecoveryLevel=0. The initiator MUST ignore the A bit
*

* On receiving a Data-In PDU with the A bit set to 1 on a session with ErrorRecoveryLevel greater than * 0, if there are no holes in the read data until that Data-In PDU, the initiator MUST issue a SNACK * of type DataACK except when it is able to acknowledge the status for the task immediately via ExpStatSN on other * outbound PDUs if the status for the task is also received. In the latter case (acknowledgement through * ExpStatSN), sending a SNACK of type DataACK in response to the A bit is OPTIONAL, but if it is done, it must not * be sent after the status acknowledgement through ExpStatSN. If the initiator has detected holes in the read data * prior to that Data-In PDU, it MUST postpone issuing the SNACK of type DataACK until the holes are filled. An * initiator also MUST NOT acknowledge the status for the task before those holes are filled. A status * acknowledgement for a task that generated the Data-In PDUs is considered by the target as an implicit * acknowledgement of the Data-In PDUs if such an acknowledgement was requested by the target. * * @return Returns true, if the AcknowledgeBit is set. Else false. */ public boolean isAcknowledgeFlag () { return acknowledgeFlag; } /** * In this case, the Bidirectional Read Residual Count indicates the number of bytes that were not transferred to * the initiator because the initiator’s Expected Bidirectional Read Data Transfer Length was not sufficient. * * @return True, if the ReadResidualOverflow-Flag of this object is set. Else false. */ public boolean isBidirectionalReadResidualOverflow () { return bidirectionalReadResidualOverflow; } /** * In this case, the Bidirectional Read Residual Count indicates the number of bytes that were not transferred to * the initiator out of the number of bytes expected to be transferred. * * @return True, if the ReadResidualUnderflow-Flag of this object is set. Else false. */ public boolean isBidirectionalReadResidualUnderflow () { return bidirectionalReadResidualUnderflow; } /** * In this case, the Residual Count indicates the number of bytes that were not transferred because the initiator’s * Expected Data Transfer Length was not sufficient. For a bidirectional operation, the Residual Count contains the * residual for the write operation. * * @return True, if the ResidualOverflow-Flag of this object is set. Else false. */ public boolean isResidualOverflow () { return residualOverflow; } /** * In this case, the Residual Count indicates the number of bytes that were not transferred out of the number of * bytes that were expected to be transferred. For a bidirectional operation, the Residual Count contains the * residual for the write operation. * * @return True, if the ResidualUnderflow-Flag of this object is set. Else false. */ public boolean isResidualUnderflow () { return residualUnderflow; } /** * The Status field is used to report the SCSI status of the command (as specified in [SAM2]) and is only valid if * the Response Code is Command Completed at target. *

* If a SCSI device error is detected while data from the initiator is still expected (the command PDU did not * contain all the data and the target has not received a Data PDU with the final bit Set), the target MUST wait * until it receives a Data PDU with the F bit set in the last expected sequence before sending the Response PDU. * * @return The status code of this object. * @see SCSIStatus */ public SCSIStatus getStatus () { return status; } /** * Set this to indicate that the Command Status field contains status. If this bit is set to 1, the * F bit MUST also be set to 1.
* The fields StatSN, Status, and Residual Count only have meaningful content if the S bit is set to 1 * and their values are defined in Section 10.4 SCSI Response. * * @return True, if the Status-Flag of this object is set. Else false. */ public boolean isStatusFlag () { return statusFlag; } public void setAcknowledgeFlag (boolean acknowledgeFlag) { this.acknowledgeFlag = acknowledgeFlag; } public void setResidualOverflowFlag (boolean residualOverflowFlag) { this.residualOverflow = residualOverflowFlag; } public void setResidualUnderflowFlag (boolean residualUnderflowFlag) { this.residualUnderflow = residualUnderflowFlag; } public void setStatusFlag (boolean statusFlag) { this.statusFlag = statusFlag; } public void setStatus (SCSIStatus status) { this.status = status; } public void setTargetTransferTag (int targetTransferTag) { this.targetTransferTag = targetTransferTag; } public void setDataSequenceNumber (int dataSequenceNumber) { this.dataSequenceNumber = dataSequenceNumber; } public void setBufferOffset (int bufferOffset) { this.bufferOffset = bufferOffset; } public void setResidualCount (int residualCount) { this.residualCount = residualCount; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override protected void deserializeBytes1to3 (final int line) throws InternetSCSIException { acknowledgeFlag = Utils.isBitSet(line & ACKNOWLEDGE_FLAG_MASK); residualOverflow = Utils.isBitSet(line & Constants.RESIDUAL_OVERFLOW_FLAG_MASK); residualUnderflow = Utils.isBitSet(line & Constants.RESIDUAL_UNDERFLOW_FLAG_MASK); statusFlag = Utils.isBitSet(line & STATUS_FLAG_MASK); Utils.isReserved(line & BIT_11_TO_13_FLAG_MASK); Utils.isReserved(line & Constants.THIRD_BYTE_MASK); status = SCSIStatus.valueOf((byte) (line & Constants.FOURTH_BYTE_MASK)); } /** {@inheritDoc} */ @Override protected void deserializeBytes20to23 (final int line) throws InternetSCSIException { targetTransferTag = line; } /** {@inheritDoc} */ @Override protected void deserializeBytes36to39 (final int line) throws InternetSCSIException { dataSequenceNumber = line; } /** {@inheritDoc} */ @Override protected void deserializeBytes40to43 (final int line) throws InternetSCSIException { bufferOffset = line; } /** {@inheritDoc} */ @Override protected void deserializeBytes44to47 (final int line) throws InternetSCSIException { residualCount = line; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override protected void checkIntegrity () throws InternetSCSIException { String exceptionMessage; do { if (statusFlag && !protocolDataUnit.getBasicHeaderSegment().isFinalFlag()) { exceptionMessage = "FinalFlag must also be set, if the StatusFlag is set."; break; } if (!statusFlag && (bidirectionalReadResidualOverflow || bidirectionalReadResidualUnderflow) && (residualOverflow || residualUnderflow)) { exceptionMessage = "The StatusFlag must be set, if any flags are set."; break; } if (acknowledgeFlag && (targetTransferTag == 0 && logicalUnitNumber == 0)) { exceptionMessage = "If the AcknowledgeFlag is set, the TargetTaskTag" + " and the LogicalUnitNumber must be unequal 0."; break; } if (!acknowledgeFlag && (targetTransferTag != 0 && logicalUnitNumber != 0)) { exceptionMessage = "The TargetTransferTag and LogicalUnitNumber must" + " be reserved, because the AcknowledgeFlag is not set."; break; } // message is checked correctly return; } while (false); throw new InternetSCSIException(exceptionMessage); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ @Override protected int serializeBytes1to3 () { int line = status.value(); if (acknowledgeFlag) { line |= ACKNOWLEDGE_FLAG_MASK; } if (residualOverflow) { line |= Constants.READ_RESIDUAL_OVERFLOW_FLAG_MASK; } if (residualUnderflow) { line |= Constants.READ_RESIDUAL_UNDERFLOW_FLAG_MASK; } if (statusFlag) { line |= STATUS_FLAG_MASK; } return line; } /** {@inheritDoc} */ @Override protected int serializeBytes20to23 () { return targetTransferTag; } /** {@inheritDoc} */ @Override protected int serializeBytes36to39 () { return dataSequenceNumber; } /** {@inheritDoc} */ @Override protected int serializeBytes40to43 () { return bufferOffset; } /** {@inheritDoc} */ @Override protected int serializeBytes44to47 () { return residualCount; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy