package org.jscsi.target.scsi.cdb;
import java.nio.ByteBuffer;
import org.jscsi.target.storage.IStorageModule;
/**
* This abstract class represents Command Descriptor Blocks for the <code>READ</code> and <code>WRITE</code>
* SCSI commands. This grouping makes
* sense, since, apart from the different values of the OPERATION CODE field,
* Read and Write CDBs are identical.
*
* @author Andreas Ergenzinger
*/
public abstract class ReadOrWriteCdb extends CommandDescriptorBlock {
/**
* The logical block address of the first logical block of data, where data
* shall be read from or written to.
*
* @see #transferLength
*/
private final long logicalBlockAddress;
/**
* The TRANSFER LENGTH field specifies the number of contiguous logical
* blocks of data that shall be read/written and transferred to/from the
* (initiator's) data-in buffer, starting with the logical block specified
* by the {@link #logicalBlockAddress} field.
*/
private final int transferLength;
public ReadOrWriteCdb(ByteBuffer buffer) {
super(buffer);
logicalBlockAddress = deserializeLogicalBlockAddress(buffer);
transferLength = deserializeTransferLength(buffer);
}
/**
* Deserializes the value of the {@link #logicalBlockAddress} field.
*
* @param buffer
* the {@link ByteBuffer} containing the CDB
* @return value of the {@link #logicalBlockAddress} field
*/
protected abstract long deserializeLogicalBlockAddress(final ByteBuffer buffer);
/**
* Deserializes the value of the {@link #transferLength} field.
*
* @param buffer
* the {@link ByteBuffer} containing the CDB
* @return value of the {@link #transferLength} field
*/
protected abstract int deserializeTransferLength(final ByteBuffer buffer);
/**
* Returns the value of {@link #logicalBlockAddress}.
*
* @return the value of {@link #logicalBlockAddress}
*/
public final long getLogicalBlockAddress() {
return logicalBlockAddress;
}
/**
* Returns the value of {@link #transferLength}.
*
* @return the value of {@link #transferLength}
*/
public final int getTransferLength() {
return transferLength;
}
/**
* Returns the index position of the first byte used for encoding the {@link #logicalBlockAddress} field.
*
* @return the index position of the first byte used for encoding the {@link #logicalBlockAddress} field
*/
protected abstract int getLogicalBlockAddressFieldIndex();
/**
* Returns the index position of the first byte used for encoding the {@link #transferLength} field.
*
* @return the index position of the first byte used for encoding the {@link #transferLength} field
*/
protected abstract int getTransferLengthFieldIndex();
/**
* This method is used for signaling an illegal value of the {@link #logicalBlockAddress} variable.
* <p>
* This method must be called if the {@link #logicalBlockAddress} lies outside the bounds of the used
* medium.
*
* @see #getIllegalFieldPointers()
* @see IStorageModule#checkBounds(long, int)
*/
public final void addIllegalFieldPointerForLogicalBlockAddress() {
addIllegalFieldPointer(getLogicalBlockAddressFieldIndex());
}
/**
* This method is used for signaling an illegal value of the {@link #transferLength} variable.
* <p>
* This method must be called if the {@link #transferLength} field value would result in accessing of
* out-of-bounds blocks of the storage medium.
*
* @see #getIllegalFieldPointers()
* @see IStorageModule#checkBounds(long, int)
*/
public final void addIllegalFieldPointerForTransferLength() {
addIllegalFieldPointer(getTransferLengthFieldIndex());
}
}