
org.jscsi.parser.snack.SNACKRequestParser Maven / Gradle / Ivy
/**
* 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.snack;
import java.util.HashMap;
import java.util.Map;
import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.Constants;
import org.jscsi.parser.InitiatorMessageParser;
import org.jscsi.parser.ProtocolDataUnit;
import org.jscsi.parser.datasegment.DataSegmentFactory.DataSegmentFormat;
import org.jscsi.utils.Utils;
/**
* SNACKRequestParser
*
* This class parses a SNACK Request message defined in the iSCSI Standard (RFC3720).
*
* If the implementation supports ErrorRecoveryLevel greater than zero, it MUST support all SNACK types.
*
* The SNACK is used by the initiator to request the retransmission of numbered-responses, data, or R2T PDUs from the
* target. The SNACK request indicates the numbered-responses or data "runs" whose retransmission is requested by the
* target, where the run starts with the first StatSN, DataSN, or R2TSN whose retransmission is requested and indicates
* the number of Status, Data, or R2T PDUs requested including the first. 0
has special meaning when used
* as a starting number and length:
*
*
* - When used in RunLength, it means all PDUs starting with the initial.
* - When used in both BegRun and RunLength, it means all unacknowledged PDUs.
*
* The numbered-response(s) or R2T(s), requested by a SNACK, MUST be delivered as exact replicas of the ones that the
* target transmitted originally except for the fields ExpCmdSN, MaxCmdSN, and ExpDataSN, which MUST carry the current
* values. R2T(s)requested by SNACK MUST also carry the current value of StatSN.
*
* The numbered Data-In PDUs, requested by a Data SNACK MUST be delivered as exact replicas of the ones that the target
* transmitted originally except for the fields ExpCmdSN and MaxCmdSN, which MUST carry the current values and except
* for resegmentation (see Section 10.16.3 Resegmentation).
*
* Any SNACK that requests a numbered-response, Data, or R2T that was not sent by the target or was already acknowledged
* by the initiator, MUST be rejected with a reason code of "Protocol error".
*
*
Data Acknowledgement
If an initiator operates at ErrorRecoveryLevel 1
or higher, it MUST issue
* a SNACK of type DataACK after receiving a Data-In PDU with the A bit set to 1
. However, if the initiator
* has detected holes in the input sequence, it MUST postpone issuing the SNACK of type DataACK until the holes are
* filled. An initiator MAY ignore the A bit if it deems that the bit is being set aggressively by the target (i.e.,
* before the MaxBurstLength limit is reached).
*
* The DataACK is used to free resources at the target and not to request or imply data retransmission.
*
* An initiator MUST NOT request retransmission for any data it had already acknowledged.
*
*
Resegmentation
If the initiator MaxRecvDataSegmentLength changed between the original transmission and the
* time the initiator requests retransmission, the initiator MUST issue a R-Data SNACK (see Section 10.16.1 Type). With
* R-Data SNACK, the initiator indicates that it discards all the unacknowledged data and expects the target to resend
* it. It also expects resegmentation. In this case, the retransmitted Data-In PDUs MAY be different from the ones
* originally sent in order to reflect changes in MaxRecvDataSegmentLength. Their DataSN starts with the BegRun of the
* last DataACK received by the target if any was received; otherwise it starts with 0 and is increased by 1 for each
* resent Data-In PDU.
*
* A target that has received a R-Data SNACK MUST return a SCSI Response that contains a copy of the SNACK Tag field
* from the R-Data SNACK in the SCSI Response SNACK Tag field as its last or only Response. For example, if it has
* already sent a response containing another value in the SNACK Tag field or had the status included in the last
* Data-In PDU, it must send a new SCSI Response PDU. If a target sends more than one SCSI Response PDU due to this
* rule, all SCSI responses must carry the same StatSN (see Section 10.4.4 SNACK Tag). If an initiator attempts to
* recover a lost SCSI Response (with a Status SNACK, see Section 10.16.1 Type) when more than one response has been
* sent, the target will send the SCSI Response with the latest content known to the target, including the last SNACK
* Tag for the command.
*
* For considerations in allegiance reassignment of a task to a connection with a different MaxRecvDataSegmentLength,
* refer to Section 6.2.2 Allegiance Reassignment.
*
*
Initiator Task Tag
For Status SNACK and DataACK, the Initiator Task Tag MUST be set to the reserved value
* 0xffffffff
. In all other cases, the Initiator Task Tag field MUST be set to the Initiator Task Tag of
* the referenced command.
*
*
* @author Volker Wildi
*/
public final class SNACKRequestParser extends InitiatorMessageParser {
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/**
* This enumeration defines all valid SNACK types.
*
*
*
* Type
* Description
*
*
* 0
* Data/R2T SNACK - requesting retransmission of one or more Data- In or R2T PDUs.
*
*
* 1
* Status SNACK - requesting retransmission of one or more numbered responses.
*
*
* 2
* DataACK - positively acknowledges Data-In PDUs.
*
*
* 3
* R-Data SNACK - requesting retransmission of Data-In PDUs with possible resegmentation and status tagging.
*
*
*
* All other values are reserved.
*
* Data/R2T SNACK, Status SNACK, or R-Data SNACK for a command MUST precede status acknowledgement for the given
* command.
*/
public static enum SNACKType {
/** The Data/R2T-Snack. */
DATA_R2T_SNACK((byte) 0),
/** The Status-SNACK. */
STATUS_SNACK((byte) 1),
/** The DataACK. */
DATA_ACK((byte) 2),
/** The R-Data SNACK. */
R_DATA_SNACK((byte) 3);
private final byte value;
private static Map mapping;
static {
SNACKType.mapping = new HashMap();
for (SNACKType s : values()) {
SNACKType.mapping.put(s.value, s);
}
}
private SNACKType (final byte newValue) {
value = newValue;
}
/**
* Returns the value of this enumeration.
*
* @return The value of this enumeration.
*/
public final byte value () {
return value;
}
/**
* Returns the constant defined for the given value
.
*
* @param value The value to search for.
* @return The constant defined for the given value
. Or null
, if this value is not
* defined by this enumeration.
*/
public static final SNACKType valueOf (final byte value) {
return SNACKType.mapping.get(value);
}
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** Bit mask to extract the SNACK type. */
private static final int TYPE_MASK = 0x000F0000;
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** The SNACK type. */
private SNACKType type;
/** The target transfer tag. */
private int targetTransferTag;
/** The first PDU number to start from with the retransmission. */
private int begRun;
/** The run length of requested PDUs to retransmit. */
private int runLength;
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Default constructor, creates a new, empty SNACKRequestParser
object.
*
* @param initProtocolDataUnit The reference ProtocolDataUnit
instance, which contains this
* SNACKRequestParser
subclass object.
*/
public SNACKRequestParser (final ProtocolDataUnit initProtocolDataUnit) {
super(initProtocolDataUnit);
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/**
* The DataSN
, R2TSN
, or StatSN
of the first PDU whose retransmission is
* requested (Data/R2T and Status SNACK), or the next expected DataSN (DataACK SNACK).
*
* BegRun
0
when used in conjunction with RunLength
0
means
* resend all unacknowledged Data-In, R2T or Response PDUs.
*
* BegRun
MUST be 0
for a R-Data SNACK.
*
* @return The BegRun of this SNACKRequestParser
obejct.
*/
public final int getBegRun () {
return begRun;
}
/**
* The number of PDUs whose retransmission is requested.
*
* RunLength
0
signals that all Data-In, R2T, or Response PDUs carrying the numbers equal
* to or greater than BegRun have to be resent.
*
* The RunLength
MUST also be 0
for a DataACK SNACK in addition to R-Data SNACK.
*
* @return The RunLength of this SNACKRequestParser
object.
*/
public final int getRunLength () {
return runLength;
}
/**
* For an R-Data SNACK, this field MUST contain a value that is different from 0
or
* 0xffffffff
and is unique for the task (identified by the Initiator Task Tag). This value MUST be
* copied by the iSCSI target in the last or only SCSI Response PDU it issues for the command.
*
* For DataACK
, the Target Transfer Tag MUST contain a copy of the Target Transfer Tag and LUN provided
* with the SCSI Data-In PDU with the A
bit set to 1
.
*
* In all other cases, the Target Transfer Tag field MUST be set to the reserved value of 0xffffffff
.
*
* @return The target transfer tag of this SNACKRequestParser
object.
*/
public final int getTargetTransferTag () {
return targetTransferTag;
}
/**
* Returns the SNACK Function Code of this SNACKRequestParser
object.
*
* @return The SNACK Function code of this SNACKRequestParser
object.
* @see org.jscsi.parser.snack.SNACKRequestParser.SNACKType
*/
public final SNACKType getType () {
return type;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/**
* Sets the begRun
variable to the given new value.
*
* @param newBegRun The new value.
*/
public final void setBegRun (final int newBegRun) {
begRun = newBegRun;
}
/**
* Sets the Run Length to the given value.
*
* @param newRunLength The new value.
*/
public final void setRunLength (final int newRunLength) {
runLength = newRunLength;
}
/**
* Sets the Target Transfer Tag to the given value.
*
* @param newTargetTransferTag The new value.
*/
public final void setTargetTransferTag (final int newTargetTransferTag) {
targetTransferTag = newTargetTransferTag;
}
/**
* Sets the type of this SNACKRequest to the given value.
*
* @param newType The new value.
*/
public final void setType (final SNACKType newType) {
type = newType;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
public final String toString () {
final StringBuilder sb = new StringBuilder(Constants.LOG_INITIAL_SIZE);
Utils.printField(sb, "Type", type.value(), 1);
Utils.printField(sb, "LUN", logicalUnitNumber, 1);
Utils.printField(sb, "Target Transfer Tag", targetTransferTag, 1);
sb.append(super.toString());
Utils.printField(sb, "BegRun", begRun, 1);
Utils.printField(sb, "Run Length", runLength, 1);
return sb.toString();
}
/** {@inheritDoc} */
@Override
public final DataSegmentFormat getDataSegmentFormat () {
return DataSegmentFormat.NONE;
}
/** {@inheritDoc} */
@Override
public final void clear () {
super.clear();
type = SNACKType.DATA_ACK;
targetTransferTag = 0x00000000;
begRun = 0x00000000;
runLength = 0x00000000;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
protected final void deserializeBytes1to3 (final int line) throws InternetSCSIException {
type = SNACKType.valueOf((byte) ((line & TYPE_MASK) >> Constants.TWO_BYTES_SHIFT));
Utils.isReserved(line & Constants.LAST_TWO_BYTES_MASK);
}
/** {@inheritDoc} */
@Override
protected final void deserializeBytes20to23 (final int line) throws InternetSCSIException {
targetTransferTag = line;
}
/** {@inheritDoc} */
@Override
protected final void deserializeBytes40to43 (final int line) throws InternetSCSIException {
begRun = line;
}
/** {@inheritDoc} */
@Override
protected final void deserializeBytes44to47 (final int line) throws InternetSCSIException {
runLength = line;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
protected final void checkIntegrity () throws InternetSCSIException {
// FIXME: Sure?
// do nothing...
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
protected final int serializeBytes1to3 () {
return type.value() << Constants.TWO_BYTES_SHIFT;
}
/** {@inheritDoc} */
@Override
protected final int serializeBytes20to23 () {
return targetTransferTag;
}
/** {@inheritDoc} */
@Override
protected final int serializeBytes24to27 () {
return 0;
}
/** {@inheritDoc} */
@Override
protected final int serializeBytes40to43 () {
return begRun;
}
/** {@inheritDoc} */
@Override
protected final int serializeBytes44to47 () {
return runLength;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
}